提问人:Bartek Pacia 提问时间:12/28/2019 最后编辑:Albert221Bartek Pacia 更新时间:7/15/2023 访问量:13482
初始化时对 ListView 中的元素进行动画处理
Animate elements in ListView on initialization
问:
我想实现如下目标(动画风格无关紧要,我正在寻找做到这一点的方法)
但是,所有资源和问题都只解释了如何创建 项目添加或删除动画。
我当前的代码(我使用 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");
},
),
);
}
}
答:
7赞
easeccy
12/29/2019
#1
像 和 这样的小部件可用于实现这一点。但是,子小部件的生命周期有点复杂。它们会根据滚动位置被破坏和重新创建。如果子 widget 具有在初始化时启动的动画,则每当子 widget 对 UI 可见时,它就会重新激活。AnimatedOpacity
AnimatedPositioned
ListView
这是我的黑客解决方案。我使用静态布尔值来指示它是“第一次”还是“娱乐”状态,而简单地忽略“娱乐”。您可以在 Dartpad 中复制并试用。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.brown,
body: ListView(
children: List.generate(
25,
(i) => AnimatedListItem(i, key: ValueKey<int>(i)),
),
),
),
);
}
}
class AnimatedListItem extends StatefulWidget {
final int index;
const AnimatedListItem(this.index, {Key? key}) : super(key: key);
@override
State<AnimatedListItem> createState() => _AnimatedListItemState();
}
class _AnimatedListItemState extends State<AnimatedListItem> {
bool _animate = false;
static bool _isStart = true;
@override
void initState() {
super.initState();
if (_isStart) {
Future.delayed(Duration(milliseconds: widget.index * 100), () {
setState(() {
_animate = true;
_isStart = false;
});
});
} else {
_animate = true;
}
}
@override
Widget build(BuildContext context) {
return AnimatedOpacity(
duration: const Duration(milliseconds: 1000),
opacity: _animate ? 1 : 0,
curve: Curves.easeInOutQuart,
child: AnimatedPadding(
duration: const Duration(milliseconds: 1000),
padding: _animate
? const EdgeInsets.all(4.0)
: const EdgeInsets.only(top: 10),
child: Container(
constraints: const BoxConstraints.expand(height: 100),
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
widget.index.toString(),
style: const TextStyle(fontSize: 24),
),
),
),
),
),
);
}
}
评论
0赞
Bartek Pacia
12/29/2019
是的,我知道这一点,但我不会添加或删除项目。我已经从后端收到了一些物品。我想做的就是为这些创建“布局”动画。
0赞
Bartek Pacia
12/31/2019
好吧,我不得不说,当有更多项目时,它会在滚动时产生严重的问题。我会继续接受这一点,但它效果不佳。
1赞
easeccy
1/15/2020
我将更新我的答案,使其仅在开始时才显示动画。您也可以自己添加该逻辑。很抱歉回复晚了。
1赞
Stepan
3/3/2021
如何使用这种方法从上面的 gif 中实现“从底部滑动”效果。谢谢。
0赞
giorgio79
5/13/2023
api.flutter.dev/flutter/widgets/AnimatedList-class.html 怎么样
0赞
Brave Dolphin
10/26/2021
#2
我在 dartpad 上创建了一个要点,展示了如何为ListView
关键点是为每个列表项创建一个,缓存它,并在动画完成时进行清理。AnimationController
0赞
maryam hashemi
7/15/2023
#3
import 'package:flutter/material.dart';
class DifferentPage extends StatefulWidget {
const DifferentPage({super.key});
@override
State<DifferentPage> createState() => DifferentStatePage();
}
class DifferentStatePage extends State<DifferentPage> {
final _item = [];
final GlobalKey<AnimatedListState> _key = GlobalKey();
void _addItem() {
_item.insert(0, 'Item ${_item.length + 1}');
_key.currentState!.insertItem( 0,
duration: const Duration(seconds: 1),
);
}
void _removeItem(int index) {
_key.currentState!.removeItem( index, (_, animation) {
return SizeTransition(
sizeFactor: animation,
child: const Card(
margin: EdgeInsets.all(10),
color: Colors.red,
child: ListTile(
title: Text(
'Deleted',
style: TextStyle(fontSize: 22),
),
),
),
);
},
duration: const Duration(milliseconds: 300),
);
_item.removeAt(index);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
const SizedBox( height: 10 ),
IconButton(
onPressed: _addItem,
icon: const Icon(Icons.add_box_rounded),
),
Expanded(
child: AnimatedList(
key: _key,
initialItemCount: 0,
padding: const EdgeInsets.all(10),
itemBuilder: (context, index, animation) {
return SizeTransition(
key: UniqueKey(),
sizeFactor: animation,
child: Card(
margin: const EdgeInsets.all(10),
color: Colors.amberAccent,
child: ListTile(
title: Text(
_item[index],
style: const TextStyle(fontSize: 22),
),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
_removeItem(index);
},
),
),
),
);
},
),
)
],
);
}}
评论