Flutter中Nutrition Fact类UI组件名称及相关包问询
Flutter 营养成分表(Nutrition Fact)UI实现方案
原生组件实现
Flutter没有专门对应营养成分表的内置组件,可通过基础Widget组合构建:
- 用
Column+Row搭建列表/表格布局,承载营养项与对应数值 - 用
Divider实现分隔线,区分不同营养区块 - 用
Text搭配TextStyle实现标题、数值的样式区分 - 用
Container控制边框、内边距,还原标签的卡片式外观
搜索关键词
- Flutter nutrition facts table
- Flutter nutritional label UI
- Flutter food label component
第三方包推荐
flutter_nutrition_label:专为营养成分标签设计的包,支持自定义营养项与样式DataTable:Flutter内置表格组件,适合规整的营养数据排版flutter_table:用于构建复杂表格布局的工具包,可灵活定制营养表结构
待办事项
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
地图页面代码
import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import 'package:location/location.dart'; import '../widgets/map.dart'; class MapScreen extends StatefulWidget { static const routeName = "/mapScreen"; @override State<MapScreen> createState() => _MapScreenState(); } class _MapScreenState extends State<MapScreen> { LatLng _currLoc = new LatLng(19.2143, 72.8762); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("E-DAC Seva"), actions: [], ), body: Map(currentLocationData: _currLoc)); } }
地图组件代码
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import 'package:location/location.dart'; import 'package:http/http.dart' as http; import '../screens/qr_code_screen.dart'; class Map extends StatefulWidget { static const routeName = "/mapScreen"; final LatLng currentLocationData; Map({required this.currentLocationData}); @override State<Map> createState() => _MapState(); } class _MapState extends State<Map> with TickerProviderStateMixin { LatLng? _currentUserLocation; late final MapController mapController; late final List<Marker> _markers; bool _isSelecting = true; late LatLng _cameraPosition; LatLng? _chosenLocation; @override void initState() { super.initState(); mapController = MapController(); _currentUserLocation = widget.currentLocationData; _cameraPosition = _currentUserLocation!; _markers = [ Marker( width: 100, height: 90, point: _currentUserLocation as LatLng, builder: (ctx) => Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Icon( Icons.my_location, size: 40, color: Colors.red, ), // SizedBox( // height: 10, // ) ], ), ), ]; } bool _isFirstTapped = false; Marker _buildMarker({ required LatLng point, required String label, MaterialColor color = Colors.red, }) { return Marker( width: 300, height: 124, point: point, builder: (ctx) => Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15)), child: Column( children: [ Text( label, textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 15, ), ), ElevatedButton( onPressed: () { Navigator.of(context).pushNamed( QRCodeScreen.routeName, arguments: label, ); }, child: Text("View QR"), ), ], ), ), Icon( Icons.location_on, size: 40, color: color, ), ], ), ); } void _selectLocation(position, LatLng point) async { var resp = await http.post( Uri.parse("http://192.168.45.142:8000/api/dac"), body: { "Latitude": "${point.latitude}", "Longitude": "${point.longitude}", }, ); var data = jsonDecode(resp.body); print(data['DAC Code']); setState(() { _chosenLocation = point; if (_isFirstTapped) { _markers.removeLast(); } _isFirstTapped = true; print(point.latitude); print(point.longitude); _markers.add( _buildMarker(label: "Block No: ${data['DAC Code']}", point: point)); }); } void _animatedMapMove( LatLng destLocation, double destZoom, bool shouldRotate) { // Create some tweens. These serve to split up the transition from one location to another. // In our case, we want to split the transition be<tween> our current map center and the destination. final latTween = Tween<double>( begin: mapController.center.latitude, end: destLocation.latitude); final lngTween = Tween<double>( begin: mapController.center.longitude, end: destLocation.longitude); final zoomTween = Tween<double>(begin: mapController.zoom, end: destZoom); final rotationTween = Tween<double>(begin: mapController.rotation, end: 0.0); // Create a animation controller that has a duration and a TickerProvider. var controller = AnimationController( duration: const Duration(milliseconds: 500), vsync: this); // The animation determines what path the animation will take. You can try different Curves values, although I found // fastOutSlowIn to be my favorite. Animation<double> animation = CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn); controller.addListener(() { if (shouldRotate) { mapController.moveAndRotate( LatLng(latTween.evaluate(animation), lngTween.evaluate(animation)), zoomTween.evaluate(animation), rotationTween.evaluate(animation), ); } else { mapController.move( LatLng(latTween.evaluate(animation), lngTween.evaluate(animation)), zoomTween.evaluate(animation), ); } }); animation.addStatusListener((status) { if (status == AnimationStatus.completed) { controller.dispose(); } else if (status == AnimationStatus.dismissed) { controller.dispose(); } }); controller.forward(); } @override Widget build(BuildContext context) { return Stack( children: [ FlutterMap( mapController: mapController, options: MapOptions( center: _currentUserLocation, zoom: 15.0, onTap: _isSelecting ? _selectLocation : null, onPositionChanged: (position, _) { _cameraPosition = position.center as LatLng; }), layers: [ TileLayerOptions( urlTemplate: , additionalOptions: { 'accessToken': , 'id': 'mapbox.mapbox-streets-v11', }, ), MarkerLayerOptions( markers: _markers, ), ], ), Positioned( right: 20, bottom: 20, child: FloatingActionButton( tooltip: "Current location", onPressed: () { _animatedMapMove(_currentUserLocation as LatLng, 17.0, true); }, child: Icon(Icons.my_location), ), ), Positioned( right: 25, bottom: 90, child: Container( decoration: BoxDecoration( color: Theme.of(context).accentColor, borderRadius: BorderRadius.circular(10), ), child: Column( children: [ IconButton( tooltip: "Zoom in", onPressed: () { _animatedMapMove( _cameraPosition, mapController.zoom + 1, false); }, icon: Icon(Icons.add), ), IconButton( tooltip: "Zoom out", onPressed: () { _animatedMapMove( _cameraPosition, mapController.zoom - 1, false); }, icon: Icon(Icons.remove), ), ], ), ), ), ], ); } }
筛选出的家政人员
- Kanta bai:居住在${location}附近,${date-time}的${timeSlot}时段可上岗,可承担家务:${chores}
- Gangu tai:居住在${location}附近,${date-time}的${timeSlot}时段可上岗,可承担家务:${chores}
- Ramu kaka:居住在${location}附近,${date-time}的${timeSlot}时段可上岗,可承担家务:仅房屋清洁
- Chotu:居住在距离${location}较远的区域,${date-time}的${timeSlot}时段可上岗,可承担家务:${chores}
内容的提问来源于stack exchange,提问作者Jai Joshi
相关产品推荐
相关产品推荐

