3

使用 Flutter 构建应用程序并喜欢它,但一个烦人的问题困扰着我。

我有一个“主”状态小部件,其中包含属性中的商店列表、搜索栏、一个“子”小部件,它可以是地图或列表,我们可以通过单击按钮在视图之间切换。有一个 Inherited 小部件包裹在主小部件内,因此我们可以获得主小部件的状态,从而获得列表。

我在搜索栏上有一个监听器:

void updateNameFilter(){
  setState(() {
    FiltersService.nameSearch=_searchTextController.text;
  });}

它与我们过滤列表的列表小部件(它有一个 FutureBuilder)完美而流畅地工作。

child: TruckList(snapshot.data.where((Truck t)=>FiltersService.shouldDisplay(t)).toList(), _handleRefresh),

但是,对于地图小部件,我们使用 Google Maps 插件。在创建地图时,我们在其上为我们应该显示的列表中的每个项目添加一个标记:

void _onMapCreated(GoogleMapController controller) async {
mapController = controller;

 //Get the list of trucks from parent widget
List<Truck> list= await TrucksMainWidget.of(context).trucksList;
//Iterate on all trucks to add them on the map
list.where((Truck t) => FiltersService.shouldDisplay(t)).forEach((Truck t) => _addTruckMarker(t)); }

然后,每次搜索栏中的值发生变化时,它都会重新构建整个小部件,并且效率非常低,重建时会出现不美观的黑屏。此外,它偶尔会工作一次:大多数时候,小部件甚至都没有重建,从而导致搜索结果错误。

一件奇怪的事情是,当我在调试模式下启动应用程序并在地图小部件的“构建”方法上设置断点时,它按预期工作。

我想做的是,当主小部件中的列表发生变化时:-如果我们在列表小部件上,请重建 -如果我们在 Google 地图小部件上:触发一个函数,该函数将擦除所有标记并重新添加它们给定新列表,无需重建整个小部件。

我确信有办法做到这一点,但我已经尝试了几天,但我找不到办法。也许有人可以帮助我?非常感谢 !:)

编辑:这是我的代码:

继承的小部件

class _TrucksInherited extends InheritedWidget {
  _TrucksInherited({
    Key key,
    @required Widget child,
    @required this.data,
  }) : super(key: key, child: child);

  final _TrucksMainWidgetState data;

  @override
  bool updateShouldNotify(_TrucksInherited oldWidget) {
    return true;
  }
}

class TrucksMainWidget extends StatefulWidget {
  final Widget child;

  TrucksMainWidget({this.child});

  @override
  _TrucksMainWidgetState createState() => _TrucksMainWidgetState();

  static _TrucksMainWidgetState of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(_TrucksInherited)
            as _TrucksInherited)
        .data;
  }
}

class _TrucksMainWidgetState extends State<TrucksMainWidget> {
  final Icon _mapIcon = new Icon(
    FontAwesomeIcons.map,
    color: Color(0xFF666666),
  );
  final Icon _listIcon = new Icon(
      FontAwesomeIcons.thLarge, 
      color: Color(0xFF666666)
  );
  Widget _trucksListWidget;
  Widget _trucksMapWidget;

  TextEditingController _searchTextController;
  Icon _switchIcon;
  Widget _widgetView;

  Future<List<Truck>> _trucksList;

  @override
  void initState() {
    super.initState();
    _trucksList = TruckService.getAll();
    _trucksListWidget = new TrucksListWidget();
    _trucksMapWidget = new TrucksMapWidget();

    _searchTextController = new TextEditingController();
    _searchTextController.addListener(updateNameFilter);
    _switchIcon = _mapIcon;
    _widgetView = _trucksListWidget;
  }

  Future<List<Truck>> get trucksList => _trucksList;

  @override
  void dispose(){
    _searchTextController.removeListener(updateNameFilter);
    _searchTextController.dispose();
    super.dispose();
  }

  void updateNameFilter(){
    setState(() {
      FiltersService.nameSearch=_searchTextController.text;
    });
  }

  void refresh() {
    setState(() {
      _trucksList = TruckService.getAll();
    });
  }

  void _onSwitchView() {
    setState(() {
      if (_switchIcon.icon == FontAwesomeIcons.map) {
        _switchIcon = _listIcon;
        _widgetView = _trucksMapWidget;
      } else {
        _switchIcon = _mapIcon;
        _widgetView = _trucksListWidget;
      }
    });
  }

  _openFiltersDialog() async {
    bool shouldUpdate = await showDialog(
      barrierDismissible: false,
      context: context,
      builder: (BuildContext context) {
        return FiltersAlertBox();
      },
    );
    if (shouldUpdate != null && shouldUpdate) {
      setState(() {});
    }
  }

  Widget build(BuildContext context) {
    return Scaffold(
        resizeToAvoidBottomPadding: false,
        appBar: AppBar(
          backgroundColor: Colors.white,
          title: Padding(
            padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
            child: Directionality(
                textDirection: Directionality.of(context),
                child: TextField(
                  style: new TextStyle(color: Colors.black, fontSize: 16.0),
                  decoration: InputDecoration(
                      hintText: 'Recherche',
                      hintStyle: new TextStyle(color: Color(0xFF999999)),
                      fillColor: Color(0xFFF6F6F6),
                      filled: true,
                      border: InputBorder.none,
                      prefixIcon: Icon(Icons.search, color: Color(0xFF999999))),
                  autofocus: false,
                  controller: _searchTextController,
                )),
          ),
          actions: <Widget>[
            IconButton(
              icon: Icon(
                FontAwesomeIcons.slidersH,
                color: Color(0xFF666666),
              ),
              onPressed: _openFiltersDialog,
            ),
            IconButton(
              icon: _switchIcon,
              onPressed: _onSwitchView,
            )
          ],
        ),
        body: _TrucksInherited(
          data: this,
          child: _widgetView,
        ));
  }
}

列表小部件(确定)

class TrucksListWidget extends StatefulWidget {

  TrucksListWidget();

  _TrucksListWidgetState createState() => new _TrucksListWidgetState();

}

class _TrucksListWidgetState extends State<TrucksListWidget>{

  Future<List<Truck>> _handleRefresh() async{
    final state = TrucksMainWidget.of(context);
    state.refresh();
    return state.trucksList;
  }

  Widget build(BuildContext context){
    final state = TrucksMainWidget.of(context);
    return FutureBuilder<List<Truck>>(
          future: state.trucksList,
          builder: (BuildContext context, AsyncSnapshot snapshot){
            if(snapshot.hasData) {
              return RefreshIndicator(
                onRefresh: _handleRefresh,
                child: TruckList(snapshot.data.where((Truck t)=>FiltersService.shouldDisplay(t)).toList(), _handleRefresh),
              );
            }else if(snapshot.hasError){
              return Center(
                child: Text('${snapshot.error}'),
              );
            }
            return Center(
              child: CircularProgressIndicator(),
            );
          }
    );
  }
}

地图小部件 (KO)

class TrucksMapWidget extends StatefulWidget {
  _TrucksMapWidgetState createState() => new _TrucksMapWidgetState();
}

class _TrucksMapWidgetState extends State<TrucksMapWidget> {

  Future<Position> userPosition;
  GoogleMapController mapController;
  Map<Marker, Truck> allMarkers = {};
  StreamSubscription subscription;

  void initState(){
    super.initState();
    initPosition();
    subscription = LocationService.ctrl.stream.listen((Future<Position> p)=>userPosition=p); //Listening LocationService's stream for a change of the user position
  }

  void dispose(){
    super.dispose();
    subscription.cancel();
  }

  void initPosition() async{
   userPosition = LocationService.getUserPosition();
  }

  void _onMapCreated(GoogleMapController controller) async {
    mapController = controller;

     //Get the list of trucks from parent widget
    List<Truck> list= await TrucksMainWidget.of(context).trucksList;
    //Iterate on all trucks to add them on the map
    list.where((Truck t) => FiltersService.shouldDisplay(t)).forEach((Truck t) => _addTruckMarker(t));

  }



  void _addTruckMarker(Truck truck) async {
      Marker marker = await mapController.addMarker(MarkerOptions(
        icon: BitmapDescriptor.fromAsset(
          truck.situation.isOpen ? 'assets/images/open_marker.png' : 'assets/images/close_marker.png',
        ),
        infoWindowText: InfoWindowText(truck.name, truck.situation.address),
        position: LatLng(truck.situation.position.lat,
            truck.situation.position.long),
        consumeTapEvents: true,
      ));
      allMarkers[marker] = truck; //Linking the marker to its truck in the Map
  }

  Widget build(BuildContext context) {
    return FutureBuilder(
      future:userPosition,
      builder: (context, snapshot){
        if(snapshot.connectionState==ConnectionState.done){
          return _getMap(snapshot.data);
        }else{
          return Center(
            child : CircularProgressIndicator(),
          );
        }

      },
    );
  }

  Widget _getMap(Position pos){
    return GoogleMap(
      onMapCreated: _onMapCreated,
      options: GoogleMapOptions(
        myLocationEnabled: true,
        cameraPosition: CameraPosition(
          target: LatLng(pos.lat, pos.long), //Starting position at user
          zoom: 8.0,
        ),
      ),
    );
  }

}
4

0 回答 0