【问题标题】:Flutter FutureProvider Value Not Updating In Builder MethodFlutter FutureProvider 值未在 Builder 方法中更新
【发布时间】:2020-10-26 02:15:11
【问题描述】:

问题

我正在 Flutter 中构建一个基本应用程序,它可以获取用户的位置并以类似于 Tinder 的刷卡格式显示附近的地点。我设法实现了地理定位,但是在使用 FutureProvider/Consumer 时,我遇到了一个奇怪的错误,即用户与该地点的相对距离被卡片组中的第一个距离值覆盖。虽然我是 Flutter 和 Provider 包的新手,但我相信有一个简单的解决方法。

旁注:在 Google 上搜索后,我尝试使用 FutureProvider.value() 来阻止旧值更新,但没有成功。

提前感谢您的任何帮助或指导!

快速演示

使用的包

card_swipe.dart

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:provider/provider.dart';
import 'package:swipe_stack/swipe_stack.dart';

import '../services/geolocator_service.dart';
import '../models/place.dart';

class CardSwipe extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final _currentPosition = Provider.of<Position>(context);
    final _placesProvider = Provider.of<Future<List<Place>>>(context);
    final _geoService = GeoLocatorService();

    return FutureProvider(
      create: (context) => _placesProvider,
      child: Scaffold(
        backgroundColor: Colors.grey[300],
        body: (_currentPosition != null)
            ? Consumer<List<Place>>(
                builder: (_, places, __) {
                  return (places != null)
                      ? Column(
                          children: [
                            SizedBox(height: 10.0),
                            Container(
                              margin: EdgeInsets.only(top: 120.0),
                              height: 600,
                              child: SwipeStack(
                                children: places.map((place) {
                                  return SwiperItem(builder:
                                      (SwiperPosition position,
                                          double progress) {
                                    return FutureProvider(
                                      create: (context) =>
                                          _geoService.getDistance(
                                              _currentPosition.latitude,
                                              _currentPosition.longitude,
                                              place.geometry.location.lat,
                                              place.geometry.location.lng),
                                      child: Consumer<double>(
                                          builder: (_, distance, __) {
                                        return (distance != null)
                                            ? Center(
                                                child: Card(
                                                  child: Container(
                                                    height: 200,
                                                    width: 200,
                                                    child: Center(
                                                      child: Column(
                                                        mainAxisAlignment:
                                                            MainAxisAlignment
                                                                .center,
                                                        children: [
                                                          Text(place.name),
                                                          Text(
                                                              '${(distance / 1609).toStringAsFixed(3)} mi'), // convert meter to mi
                                                        ],
                                                      ),
                                                    ),
                                                  ),
                                                ),
                                              )
                                            : Container();
                                      }),
                                    );
                                  });
                                }).toList(),
                                visibleCount: 3,
                                stackFrom: StackFrom.Top,
                                translationInterval: 6,
                                scaleInterval: 0.03,
                                onEnd: () => debugPrint("onEnd"),
                                onSwipe: (int index, SwiperPosition position) =>
                                    debugPrint("onSwipe $index $position"),
                                onRewind:
                                    (int index, SwiperPosition position) =>
                                        debugPrint("onRewind $index $position"),
                              ),
                            ),
                          ],
                        )
                      : Center(
                          child: CircularProgressIndicator(),
                        );
                },
              )
            : Center(
                child: CircularProgressIndicator(),
              ),
      ),
    );
  }
}

geolocator_service.dart

import 'package:geolocator/geolocator.dart';

class GeoLocatorService {
  final geolocator = Geolocator();

  Future<Position> getLocation() async {
    return await geolocator.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.high,
      locationPermissionLevel: GeolocationPermission.location,
    );
  }

  Future<double> getDistance(
      double startLat, double startLng, double endLat, double endLng) async {
    return await geolocator.distanceBetween(startLat, startLng, endLat, endLng);
  }
}

place.dart

快速说明: Place 类确实导入了一个名为 geometry.dart 的自定义类,但这纯粹是为了构建 Place 对象,我确信它不会影响错误。因此,它被省略了。

import './geometry.dart';

class Place {
  final String name;
  final Geometry geometry;

  Place(this.name, this.geometry);

  Place.fromJson(Map<dynamic, dynamic> parsedJson)
      : name = parsedJson['name'],
        geometry = Geometry.fromJson(
          parsedJson['geometry'],
        );
}

【问题讨论】:

    标签: flutter dart flutter-provider


    【解决方案1】:

    您必须向 SwiperItem 添加一个具有唯一值(如地点名称)的键,因为当前 Flutter 认为小部件保持不变,因此 Consumer 获取旧顶部小部件的状态. 通过添加键,您告诉颤振您删除了最顶层的小部件,而新的最顶层实际上是第二个小部件

    【讨论】:

    • 感谢@PietervanLoon 抽出宝贵时间。你是对的,这绝对是键的一个很好的用途,但似乎SwiperItem 小部件没有key 参数并给出错误。我试图将它添加到CenterCard 小部件中,但没有运气。有什么想法吗?
    • 啊,一定要为那个包提交一个问题来添加关键参数。但是现在您可以将SwiperItem 包装在KeyedSubtree 小部件中。将密钥放在要识别的树的顶部总是很重要的(在这种情况下是 SwiperItem)
    • 我肯定会提出问题。使用KeyedSubtree 后,被覆盖的文本现在消失了,但在移除卡后,我仍然体验到旧内容的“闪现”。这是查看结果的 giphcat 链接gfycat.com/jampackedvapiddinosaur
    • 我不熟悉这个包,所以无法帮助你,也许为这部分打开一个新问题(或 github 上的问题)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 2022-10-19
    • 2020-01-16
    • 2021-12-17
    • 1970-01-01
    • 2021-08-22
    • 1970-01-01
    相关资源
    最近更新 更多