3

我想实现类似下面的东西(动画风格无关紧要,我正在寻找做到这一点的方法)

例子

但是,所有资源和问题仅说明如何创建项目添加或移除动画。

我当前的代码(我使用 BLoC 模式)

class _MembersPageState extends State<MembersPage> {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<MembersPageBloc>(
      create: (context) =>
          MembersPageBloc(userRepository: UserRepository.instance)..add(MembersPageShowed()),
      child: BlocBuilder<MembersPageBloc, MembersPageState>(
        builder: (context, state) {
          if (state is MembersPageSuccess) {
            return ListView.builder(
              itemCount: state.users.length,
              itemBuilder: (context, index) {
                User user = state.users[index];

                return ListTile(
                  isThreeLine: true,
                  leading: Icon(Icons.person, size: 36),
                  title: Text(user.name),
                  subtitle: Text(user.username),
                  onTap: () => null,
                );
              },
            );
          } else
            return Text("I don't care");
        },
      ),
    );
  }
}

4

2 回答 2

3

动画小部件喜欢AnimatedOpacity并且AnimatedPositioned可以做到。通过这种方式,您可以使用不同的动画小部件、曲线、开始和结束值来获得不同的动画。

但是,Listview 中子部件的生命周期有点复杂。它们会根据滚动位置被销毁和重新创建。如果子窗口小部件有一个在初始化时开始的动画,那么只要孩子对 UI 可见,它就会重新动画。

这是我的hacky解决方案。我使用了一个静态布尔值来指示它是第一次还是娱乐状态,并且简单地忽略了娱乐。你可以在 Dartpad 中快速尝试一下。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: Colors.black54),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
          body: ListView(
        children: List.generate(
            25, (i) => AnimatedListItem(i, key: ValueKey<int>(i))),
      )),
    );
  }
}

class AnimatedListItem extends StatefulWidget {
  final int index;

  AnimatedListItem(this.index, {Key key}) : super(key: key);

  @override
  _AnimatedListItemState createState() => _AnimatedListItemState();
}

class _AnimatedListItemState extends State<AnimatedListItem> {
  bool _animate = false;

  static bool _isStart = true;

  @override
  void initState() {
    super.initState();
    _isStart
        ? Future.delayed(Duration(milliseconds: widget.index * 100), () {
            setState(() {
              _animate = true;
              _isStart = false;
            });
          })
        : _animate = true;
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedOpacity(
      duration: Duration(milliseconds: 1000),
      opacity: _animate ? 1 : 0,
      curve: Curves.easeInOutQuart,
      child: AnimatedPadding(
        duration: Duration(milliseconds: 1000),
        padding: _animate
            ? const EdgeInsets.all(4.0)
            : const EdgeInsets.only(top: 10),
        child: Container(
          constraints: BoxConstraints.expand(height: 100),
          child: Card(
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                widget.index.toString(),
                style: TextStyle(fontSize: 24),
              ),
            ),
          ),
        ),
      ),
    );
  }
}
于 2019-12-28T16:47:48.377 回答
0

我在 dartpad 上创建了一个要点,展示了如何为ListView

关键是AnimationController为每个列表项创建一个,缓存它,并在动画完成时清理。

于 2021-10-26T09:03:07.907 回答