[英]How to repeatedly apply animation to a Stateless Widget in Flutter when the widget's content is updated based on new input?
我正在尝试在我的应用程序中的一组网格项上应用一些 animation。 为此,我正在使用 package: https://pub.dev/packages/flutter_staggered_animations
当屏幕加载时,网格项以AnimationConfiguration.staggeredGrid()
中设置的淡入方式显示
但是,当我更新过滤器或排序标准时,通过单击相关的单选按钮、复选框或移动滑块,更新后的网格项目显示时没有任何 animation。 我希望更新后的网格项目与最初加载页面时的 animation 类型相同。
我了解网格项显示在无状态小部件中。 如何为更新的网格项目设置动画? 有没有办法将buildResult()
转换为有状态的小部件? 如果是这样,该怎么做?
完整代码:
import 'package:flutter/material.dart';
import 'package:switch_circle_color/model/girls.dart';
import 'package:switch_circle_color/screens/gender.dart';
import 'package:switch_circle_color/screens/girls_cart.dart';
import 'package:switch_circle_color/screens/selected_girl_details.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import '../global_variables/global_variables.dart';
class GirlsScreen extends StatefulWidget {
GirlsScreen({Key? key}) : super(key: key);
@override
State<GirlsScreen> createState() => _GirlsScreenState();
}
class _GirlsScreenState extends State<GirlsScreen> {
int distance = 15;
int age = 25;
String sortCriterion = "distance";
bool isSingle = false;
bool isSerious = false;
void changeDistance(double num) {
setState(() {
distance = num.round();
populateFilteredGirls(distance, age);
//buildResult(context);
});
}
void changeAgeLimit(double a) {
setState(() {
age = a.round();
populateFilteredGirls(distance, age);
//buildResult(context);
});
}
List<Girls> allGirls = [
Girls("Reshmita", 25, 33, "Married", "Serious"),
Girls("Ankita", 17, 26, "Single", "Serious"),
Girls("Rupali", 42, 28, "Single", "Casual"),
Girls("Monica", 50, 24, "Single", "Casual"),
Girls("Sakshi", 9, 27, "Married", "Casual"),
];
List<Girls> filteredGirlsbyDistance = [];
List<Girls> filteredGirlsbyAge = [];
List<Girls> filteredGirls = [];
List<Girls> filteredGirlsbySerious = [];
List<Girls> filteredGirlsbySingle = [];
//List<Girls> girlsCart = [];
void addGirlToCart(Girls girl) {
girlsCart.add(girl);
cartValue = cartValue + girl.age;
}
void removeGirlsfromCart(Girls girl) {
girlsCart.remove(girl);
cartValue = cartValue - girl.age;
}
String selectedGirlName = "";
int? selectedGirlDistance;
@override
void initState() {
super.initState();
//filteredGirls = allGirls;
distance = 20;
age = 28;
sortCriterion = "distance";
isSingle = false;
isSerious = false;
(sortCriterion == "distance")
? allGirls.sort((a, b) => a.distance.compareTo(b.distance))
: allGirls.sort((a, b) => a.age.compareTo(b.age));
populateFilteredGirls(distance, age);
}
void populateFilteredGirls(int dis, int ag) {
filteredGirlsbyDistance.clear();
filteredGirlsbyAge.clear();
filteredGirlsbySingle.clear();
filteredGirlsbySerious.clear();
filteredGirls.clear();
//int len = filteredGirls.length;
for (int i = 0; i < allGirls.length; i++) {
if (allGirls[i].distance <= dis) {
filteredGirlsbyDistance.add(allGirls[i]);
}
}
filteredGirls = filteredGirlsbyDistance;
for (int i = 0; i < filteredGirls.length; i++) {
if (filteredGirls[i].age <= ag) {
filteredGirlsbyAge.add(filteredGirls[i]);
}
}
filteredGirls = filteredGirlsbyAge;
//len = filteredGirls.length;
if (isSingle == true) {
for (int i = 0; i < filteredGirls.length; i++) {
if (filteredGirls[i].status.toLowerCase() == "single") {
filteredGirlsbySingle.add(filteredGirls[i]);
}
}
filteredGirls = filteredGirlsbySingle;
}
if (isSerious == true) {
for (int i = 0; i < filteredGirls.length; i++) {
if (filteredGirls[i].lookingFor.toLowerCase() == "serious") {
filteredGirlsbySerious.add(filteredGirls[i]);
}
}
filteredGirls = filteredGirlsbySerious;
}
//filteredGirls = filteredGirls.toSet().toList();
}
Widget buildResult(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(5.0),
child: AnimationLimiter(
child: GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 5,
mainAxisSpacing: 5,
childAspectRatio: 2,
children: List.generate(filteredGirls.length, (index) {
return AnimationConfiguration.staggeredGrid(
columnCount: 2,
position: index,
duration: const Duration(milliseconds: 375),
child: ScaleAnimation(
child: FadeInAnimation(
child: ListTile(
leading: InkWell(
child: const Icon(Icons.girl_outlined),
onTap: () {
removeGirlsfromCart(filteredGirls[index]);
},
),
trailing: InkWell(
child: Text("${filteredGirls[index].distance} km away"),
onTap: () {
addGirlToCart(filteredGirls[index]);
},
),
title: Text("${filteredGirls[index].name}"),
subtitle: Text(
"${filteredGirls[index].age} years old, ${filteredGirls[index].status}, ${filteredGirls[index].lookingFor}"),
onTap: () {
// setState(() {
// selectedGirlName = filteredGirls[index].name;
// selectedGirlDistance = filteredGirls[index].distance;
// });
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SelectedGirlDetails(
girl: filteredGirls[index],
)));
},
),
),
),
);
}),
//itemCount: ,
//itemBuilder: (BuildContext context, int index) {
),
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Padding(padding: EdgeInsets.all(20)),
// ElevatedButton(
// onPressed: () {
// Navigator.push(context,
// MaterialPageRoute(builder: (context) => GenderScreen()));
// },
// child: Text("Go to Gender Screen")),
// Padding(padding: EdgeInsets.all(30)),
Text("Set max distance"),
Padding(padding: EdgeInsets.all(10)),
Slider(
min: 1.0,
max: 100.0,
divisions: 100,
activeColor: Colors.green,
inactiveColor: Colors.orange,
label: 'Set distance value',
value: distance.toDouble(),
onChanged: (value) {
changeDistance(value);
},
),
Padding(padding: EdgeInsets.all(10)),
Text("Current distance is $distance kms"),
Padding(padding: EdgeInsets.all(10)),
Text("Set max age"),
Padding(padding: EdgeInsets.all(10)),
Slider(
min: 18.0,
max: 60.0,
divisions: 42,
activeColor: Colors.green,
inactiveColor: Colors.orange,
label: 'Set age limit',
value: age.toDouble(),
onChanged: (value) {
changeAgeLimit(value);
},
),
Padding(padding: EdgeInsets.all(10)),
Text("Age limit is $age years"),
Padding(padding: EdgeInsets.all(10)),
Text("Sort by:"),
Padding(padding: EdgeInsets.all(7.5)),
ListTile(
//minLeadingWidth: 30,
title: Text("Age"),
leading: Radio(
value: "age",
groupValue: sortCriterion,
onChanged: (value) {
setState(() {
sortCriterion = value.toString();
allGirls.sort((a, b) => a.age.compareTo(b.age));
populateFilteredGirls(distance, age);
//buildResult(context);
});
},
),
),
Padding(padding: EdgeInsets.all(7.5)),
ListTile(
//minLeadingWidth: 30,
title: Text("Distance"),
leading: Radio(
value: "distance",
groupValue: sortCriterion,
onChanged: (value) {
setState(() {
sortCriterion = value.toString();
allGirls.sort((a, b) => a.distance.compareTo(b.distance));
populateFilteredGirls(distance, age);
//buildResult(context);
});
},
),
),
Padding(padding: EdgeInsets.all(10)),
Text("Is Single?"),
Padding(padding: EdgeInsets.all(2.5)),
InkWell(
onTap: () {
setState(() {
isSingle = !isSingle;
populateFilteredGirls(distance, age);
//buildResult(context);
});
},
child: (isSingle == false)
? Icon(Icons.check_box_outline_blank)
: Icon(Icons.check_box),
),
Padding(padding: EdgeInsets.all(5)),
Text("Is Serious?"),
Padding(padding: EdgeInsets.all(2.5)),
InkWell(
onTap: () {
setState(() {
isSerious = !isSerious;
populateFilteredGirls(distance, age);
//buildResult(context);
});
},
child: (isSerious == false)
? Icon(Icons.check_box_outline_blank)
: Icon(Icons.check_box),
),
Padding(padding: EdgeInsets.all(10)),
buildResult(context),
Padding(padding: EdgeInsets.all(25)),
ElevatedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => GirlsCart()));
},
child: Text("Go to Girls Cart")),
Padding(padding: EdgeInsets.all(25)),
],
),
));
}
}
视频供参考:
为此看不到任何 controller。 您可以通过更改小部件键来重建完整的小部件。 但是尝试找到更好的方法。
创建一个将更改用作键值的变量。 当您喜欢动画时,更改键变量上的分配新值。 我正在使用int count = 0;
在 state class
int count = 0;
并使用 onkey
body: AnimationLimiter(
key: ValueKey("list $count"),
当喜欢动画时增加计数器。
onPressed: () {
count++;
setState(() {});
},
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.