首页 > 解决方案 > Flutter AnimatedList 与提供者模式

问题描述

我有实现 ChangeNotifier 的模型

class DataModel with ChangeNotifier{
   List<Data> data = List<Data>();

   void addData(Data data){
      data.add(data);
      notifyListeners();
   }
}

和一个监听这些变化的 ListView:

class DataListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<DataModel>(
      builder: (context, model, child) {
        return ListView.builder(
          itemCount: model.data.length,
          itemBuilder: (context, index) {
            return Text(model.data[index].value);
          },
        );
      },
    );
  }
}

到目前为止一切顺利,当将项目添加到模型中的列表时,更改通知会触发 Listview 的重建,我会看到新数据。但是我无法将其与 AnimatedList 而不是 ListView 一起使用。最好 id 喜欢保持我的模型原样,因为动画是 ui 的关注点,而不是我的逻辑关注点。

changenotifier 总是为我提供最新版本的数据,但我真正需要的是“添加项目”或“删除项目”通知。

有没有这样做的最佳实践方法?

标签: flutterproviderflutter-animatedlist

解决方案


这是我试验的结果。这是一个 Riverpod 版本,但我认为供应商也是如此。

有两点。

  1. 在使用 AnimatedList 的小部件的父小部件中初始化状态。
  2. 使用 async 异步添加/删除 AnimatedList 和添加/删除状态。

主要.dart

import 'package:animatedlist_riverpod_sample/provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:hooks_riverpod/all.dart';

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Home(),
    );
  }
}

class Home extends HookWidget {
  const Home({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final todoList = useProvider(todoListProvider.state);
    return Scaffold(appBar: AppBar(title: Text('Todo[${todoList.length}]')), body: TodoListView());
  }
}

class TodoListView extends HookWidget {
  TodoListView({Key key}) : super(key: key);
  final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
  final todoList = useProvider(todoListProvider.state);

  @override
  Widget build(BuildContext context) {
    return AnimatedList(
      key: _listKey,
      initialItemCount: todoList.length,
      itemBuilder: (context, index, animation) =>
          _buildItem(todoList[index], animation, index, context),
    );
  }

  Slidable _buildItem(Todo todo, Animation<double> animation, int index, BuildContext context) {
    return Slidable(
      actionPane: SlidableDrawerActionPane(),
      child: SizeTransition(
          sizeFactor: animation,
          axis: Axis.vertical,
          child: ListTile(title: Text(todo.description), subtitle: Text(todo.id), onTap: () => {})),
      secondaryActions: <Widget>[
        IconSlideAction(
          caption: 'Delete',
          color: Colors.red,
          icon: Icons.delete,
          onTap: () {
            _listKey.currentState.removeItem(
                index, (context, animation) => _buildItem(todo, animation, index, context),
                duration: Duration(milliseconds: 200));
            _removeItem(context, todo);
          },
        ),
      ],
    );
  }

  void _removeItem(BuildContext context, Todo todo) async {
    await Future.delayed(
        Duration(milliseconds: 200), () => context.read(todoListProvider).remove(todo));
  }
}

提供者.dart

import 'package:hooks_riverpod/all.dart';

final todoListProvider = StateNotifierProvider<TodoList>((ref) {
  return TodoList([
    Todo(id: '0', description: 'Todo1'),
    Todo(id: '1', description: 'Todo2'),
    Todo(id: '2', description: 'Todo3'),
  ]);
});

class Todo {
  Todo({
    this.id,
    this.description,
  });

  final String id;
  final String description;
}

class TodoList extends StateNotifier<List<Todo>> {
  TodoList([List<Todo> initialTodos]) : super(initialTodos ?? []);

  void add(String description) {
    state = [
      ...state,
      Todo(description: description),
    ];
  }

  void remove(Todo target) {
    state = state.where((todo) => todo.id != target.id).toList();
  }
}

示例存储库在这里


推荐阅读