Flutter 颤振提供程序-重建列表项而不是列表视图

Flutter 颤振提供程序-重建列表项而不是列表视图,flutter,Flutter,我正在使用提供商软件包来管理我的应用程序业务逻辑,但我遇到了一个问题,我的整个ListView正在重建,而不是单个ListTile。以下是让您更好理解的UI: 当前,如果我滚动到列表的底部,点击最后一项的复选框,我看不到复选框切换的动画,滚动跳到屏幕的顶部,因为整个小部件已重建如何使用提供程序,以便仅重建单个ListTile,而不是重建列表中的所有项目? 以下是一些相关代码: class MyApp extends StatelessWidget { @override Widget

我正在使用提供商软件包来管理我的应用程序业务逻辑,但我遇到了一个问题,我的整个ListView正在重建,而不是单个ListTile。以下是让您更好理解的UI:

当前,如果我滚动到列表的底部,点击最后一项的复选框,我看不到复选框切换的动画,滚动跳到屏幕的顶部,因为整个小部件已重建如何使用提供程序,以便仅重建单个ListTile,而不是重建列表中的所有项目? 以下是一些相关代码:


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Checklist',
        theme: ThemeData(
          brightness: Brightness.light,
          primaryColor: Colors.indigo[500],
          accentColor: Colors.amber[500],
        ),
        home: ChecklistHomeScreen(),
      ),
      providers: [
        ChangeNotifierProvider(
          create: (ctx) => ChecklistsProvider(),
        ),
      ],
    );
  }
}
class ChecklistHomeScreen扩展StatefulWidget{
@凌驾
_ChecklistHomeScreenState createState()=>\u ChecklistHomeScreenState();
}
类_ChecklistHomeScreenState扩展状态{
void createList(BuildContext上下文,字符串listName){
if(listName.isNotEmpty){
Provider.of(context).addChecklist(listName);
}
}
@凌驾
小部件构建(构建上下文){
final _checklists=提供者.of(上下文).checklists;
最终_scaffoldKey=GlobalKey();
ScrollController\u ScrollController=
PrimaryScrollController.of(上下文)??ScrollController();
返回脚手架(
钥匙:_scaffoldKey,
正文:自定义滚动视图(
控制器:\ u滚动控制器,
条子:[
滑杆(
浮动:是的,
错,,
标题:文本(“您的列表”),
标题:对,
行动:[
弹出菜单按钮(
itemBuilder:(ctx)=>null,
),
],
),
可重排序列表(
委托:ReorderableSliverChildBuilderDelegate(
(ctx,i)=>\u buildListItem(\u检查表[i],i),
childCount:_checklists.length,
),
onReorder:(int-oldIndex,int-newIndex){
设置状态(){
最终检查表=_检查表。删除(旧索引);
_检查表。插入(新索引、检查表);
});
},
),
],
),
抽屉(
child:null,
),
浮动操作按钮:浮动操作按钮(
子:图标(Icons.add),
onPressed:null,
),
);
}
小部件_buildListItem(检查表列表,int listIndex){
可驳回的回报(
key:ObjectKey(list.id),
方向:DismissDirection.endToStart,
背景:卡片(
海拔:0,
子:容器(
对齐:对齐方向.centerEnd,
颜色:主题。背景。强调颜色,
孩子:填充(
填充:来自LTRB(0.0,0.0,10.0,0.0)的边缘设置,
子:图标(
图标。删除,
颜色:颜色,白色,
),
),
),
),
孩子:卡片(
孩子:ListTile(
onTap:null,
标题:文本(列表名称),
前导:复选框(
值:list.completed,
一旦更改:(值){
提供者(上下文)
.toggleCompletedStatus(list.id,list.completed);
},
),
尾随:图标按钮(
图标:图标(更多图标),
onPressed:null,
),
),
),
onDismissed:(方向){
_onDeleteList(列表、列表索引);
},
);
}
作废删除列表(检查表列表、int列表索引){
Scaffold.of(context.removeCurrentSnackBar();
Scaffold.of(上下文).showSnackBar(
小吃条(
行动:SnackBarAction(
标签:“撤消”,
已按下:(){
提供者(上下文)
.检查表(列表、列表索引);
},
),
内容:文本(
“已删除列表”,
样式:TextStyle(颜色:Theme.of(context).accentColor),
),
),
);
}
}
带有ChangeNotifier的类检查列表Provider{
最终ChecklistRepository _repository=ChecklistRepository();//单例
UnmodifiableListView获取检查列表=>UnmodifiableListView(_repository.getChecklists());
void addChecklist(字符串名称){
_储存库。添加清单(名称);
notifyListeners();
}
无效删除检查表(内部id){
_储存库。删除清单(id);
notifyListeners();
}
void toggleCompletedStatus(int-id,bool-completed){
最终列表=检查列表.firstWhere((c)=>c.id==id);
如果(列表!=null){
list.completed=已完成;
_repository.updateChecklist(列表);
notifyListeners();
}
}
}
我应该说我理解为什么这是当前的行为,我只是不确定正确的方法来确保只重建我想要更新的列表项,而不是整个屏幕。
我也读过关于
消费者的内容,但我不确定如何将其应用到我的实现中。

消费者基本上允许您使用对更改通知程序所做的任何更改。最好的做法是将使用者尽可能深入地嵌入到构建方法中。这样,只有包装好的小部件才能重新构建。这份文件很好地解释了这一点:

尝试将复选框小部件包装到消费者小部件中。只应重新生成复选框

Consumer<ChecklistsProvider>(
  builder: (context, provider, _) {
    return Checkbox(
      value: list.completed,
      onChanged: (value) {
        provider.toggleCompletedStatus(list.id, list.completed);
      },
    );
  },
),
消费者(
生成器:(上下文,提供程序,u41;{
返回复选框(
值:list.completed,
一旦更改:(值){
provider.toggleCompletedStatus(list.id,list.completed);
},
);
},
),

如果您希望重新构建ListTile和复选框,只需将ListTile包装到使用者中即可

我解决此问题的方法是创建另一个
提供程序
类,该类将仅由每个
ListTile
复选框
小部件使用

leading: Consumer<ChecklistTileProvider>(
                  builder: (ctx, provider, _) => Checkbox(
                    value: list.completed,
                    onChanged: (value) {
                      provider.toggleCompletedStatus(list.id, value);
                    },
                  ),
                ),
领先:消费者(
生成器:(ctx,提供程序,)=>复选框(
值:list.completed,
Consumer<ChecklistsProvider>(
  builder: (context, provider, _) {
    return Checkbox(
      value: list.completed,
      onChanged: (value) {
        provider.toggleCompletedStatus(list.id, list.completed);
      },
    );
  },
),
leading: Consumer<ChecklistTileProvider>(
                  builder: (ctx, provider, _) => Checkbox(
                    value: list.completed,
                    onChanged: (value) {
                      provider.toggleCompletedStatus(list.id, value);
                    },
                  ),
                ),