Flutter FutureProvider值未在Builder方法中更新

时间:2020-10-26 02:15:11

标签: flutter dart flutter-provider

问题

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

附带说明: 在Google上搜索之后,我尝试使用FutureProvider.value()来防止旧值更新,但没有运气。

在此先感谢您的帮助或指导!

快速演示

FutureProvider Bug Demo

使用的包裹

packages used

card_swipe.dart

Command Line Task

geolocator_service.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(),
              ),
      ),
    );
  }
}

place.dart

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

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);
  }
}

1 个答案:

答案 0 :(得分:1)

您必须向SwiperItem添加一个具有唯一值(例如地点名称)的键,因为当前的颤抖认为该小部件保持不变,因此Consumer的状态为最旧的最上面的小部件。 通过添加键,您可以告诉flutter您删除了最上面的窗口小部件,而新的最上面的窗口小部件实际上是第二个窗口小部件