每次我进入文本字段时,Flutter AnimatedSwitcher 都会重建

Flutter AnimatedSwitcher rebuilds everytime I enter into a textfield

在下面的代码中,我希望 AnimatedSwitcher 下的文本仅在按下 FlatButton 时进行动画处理,但它会针对我在 TextField 中输入的每个字符进行动画处理。由于 TextField 在其 onChanged 方法中有一个 setState,每次输入一个字符时都会触发动画。

如何防止 AnimatedSwitcher 在每次调用 setState 方法时都重建,并且仅在其子项的值已更新时才重建?

class _TestScreenState extends State<TestScreen> {
  int _counter = 0;
  int _value = 0;
  TextEditingController controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          AnimatedSwitcher(
            duration: Duration(milliseconds: 300),
            child: Text(_counter.toString(),
                key: UniqueKey(), style: TextStyle(fontSize: 50)),
            transitionBuilder: (Widget child, Animation<double> animation) {
              return FadeTransition(
                opacity: animation,
                child: ScaleTransition(
                  scale: animation.status == AnimationStatus.dismissed
                      ? Tween<double>(begin: .5, end: 1).animate(animation)
                      : AlwaysStoppedAnimation(1.0),
                  child: child,
                ),
              );
            },
          ),
          Padding(
            padding: EdgeInsets.all(10),
            child: Text(
              _value.toString(),
              style: TextStyle(fontSize: 20),
            ),
          ),
          Padding(
            padding: EdgeInsets.all(10),
            child: TextField(
              controller: controller,
              keyboardType: TextInputType.number,
              textAlign: TextAlign.center,
              onChanged: (val) {
                setState(() {
                  _value = int.parse(val) * 5;
                });
              },
              decoration: InputDecoration(labelText: "Enter amount"),
            ),
          ),
          Padding(
            padding: EdgeInsets.all(10),
            child: FlatButton(
              onPressed: () => setState(() {
                _counter = int.parse(controller.text) * 5;
              }),
              child: Text('Tap to change value'),
            ),
          )
        ],
      ),
    );
  }
}

试试这个

class _TestScreenState extends State<TestScreen> {
  int _counter = 0;
  int _value = 0;
  TextEditingController controller = TextEditingController();

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          AnimatedSwitcher(
            duration: Duration(milliseconds: 300),
            child: Text(_counter.toString(), key: ValueKey<int>(_counter), style: TextStyle(fontSize: 50)),
            transitionBuilder: (Widget child, Animation<double> animation) {
              return FadeTransition(
                opacity: animation,
                child: ScaleTransition(
                  scale: animation.status == AnimationStatus.dismissed
                      ? Tween<double>(begin: .5, end: 1).animate(animation)
                      : AlwaysStoppedAnimation(1.0),
                  child: child,
                ),
              );
            },
          ),
          Padding(
            padding: EdgeInsets.all(10),
            child: Text(
              _value.toString(),
              style: TextStyle(fontSize: 20),
            ),
          ),
          Padding(
            padding: EdgeInsets.all(10),
            child: TextField(
              controller: controller,
              keyboardType: TextInputType.number,
              textAlign: TextAlign.center,
              onChanged: (val) {
                setState(() {
                  _value = int.parse(val) * 5;
                });
              },
              decoration: InputDecoration(labelText: "Enter amount"),
            ),
          ),
          Padding(
            padding: EdgeInsets.all(10),
            child: FlatButton(
              onPressed: () => setState(() {
                _counter = int.parse(controller.text) * 5;
              }),
              child: Text('Tap to change value'),
            ),
          )
        ],
      ),
    );
  }
}