You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 00:45:52