繁体   English   中英

当基于新输入更新小部件的内容时,如何将 animation 重复应用于 Flutter 中的无状态小部件?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM