【问题标题】:AnimatedBuilder not working when trying to avoid setState call inside add listener尝试避免在添加侦听器中调用 setState 时,AnimatedBuilder 不起作用
【发布时间】:2020-10-22 08:27:15
【问题描述】:

我复制粘贴了一个动画按钮的代码,该按钮调用 setState,因为它向动画控制器添加了一个侦听器。

这篇文章和答案:

(Article) Flutter Laggy Animations: How Not To setState

(SO answer) Flutter animation not working

表示在这种情况下不建议调用 setState,因为每次按下按钮时它都会重建整个 UI。有道理!

现在,当我使用 AnimatedBuilder 时,它会停止工作。我做错了什么?

代码:

class _AnimatedButtonState extends State<AnimatedButton>
    with SingleTickerProviderStateMixin {
  final style = GoogleFonts.volkhov(
    color: Colors.black,
    fontSize: 15,
  );
  double _scale;
  AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
        vsync: this,
        duration: Duration(milliseconds: 100),
        lowerBound: 0.0,
        upperBound: 0.1);
    // _controller.addListener(() {
    //   setState(() {});
    // });
  }

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

  @override
  Widget build(BuildContext context) {
    _scale = 1 - _controller.value;

    return GestureDetector(
      onTap: _onTap,
      onTapDown: _onTapDown,
      onTapUp: _onTapUp,
      onTapCancel: _onTapCancel,
      child: AnimatedBuilder(           // HERE HERE
          animation: _controller,
          child: _animatedButtonUI,
          builder: (context, child) {
            return Transform.scale(
              scale: _scale,
              child: child,
            );
          },
      )
    );
  }

  _onTapUp(TapUpDetails details) => _controller.reverse();
  _onTapDown(TapDownDetails details) => _controller.forward();
  _onTapCancel() => _controller.reverse();

  Widget get _animatedButtonUI => Container(
    height: 100,
    width: 250,
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(100),
      gradient: LinearGradient(
        begin: Alignment.bottomLeft,
        end: Alignment.bottomRight,
        colors: [Colors.green, Colors.green[400], Colors.green[500]],
      ),
    ),
    child: Center(
      child: Text(
        'Save',
        style: TextStyle(
          fontSize: 25,
          fontWeight: FontWeight.bold,
          color: Colors.black,
        ),
      ),
    ),
  );

旁注:我之所以找到这个提示,是因为我试图让我的按钮对点击/触摸反应更灵敏。手机上的快速点击和触摸,在我使用 setState 时没有触发动画。相反,它比用户随意的触摸花费的时间更长。 如果您也能帮我解决这个问题,我将不胜感激。

【问题讨论】:

  • 在这种情况下,setState 似乎不会很昂贵,因为整个小部件只是按钮,它是唯一需要动画的东西。使用 AnimatedBuilder 几乎没有好处。
  • 我也这么认为。这只是我第一次遇到 AnimatedBuilder,所以我想使用它。
  • 它在有状态小部件包含更多内容的其他情况下效果很好,如您发布的文章中所示。请参阅我的答案以解决您的问题。

标签: flutter animation setstate


【解决方案1】:

问题是您用作动画值的_scale 由于缺少setState 而没有更新。 _scale 唯一被更新的地方是有状态小部件的构建方法。唯一一次在第一次之后再次调用 build 是在调用 setState 时,导致 _scale 没有像你想要的那样更新。

AnimatedBuilder 与调用setState 基本相同,但它将重建隔离到自身的builder,而不是封闭的有状态小部件作为一个整体,这就是为什么它被认为更适合性能。

要解决这个问题,只需将_scale = 1 - _controller.value; 移动到AnimatedBuilderbuilder 中。

@override
Widget build(BuildContext context) {
  //_scale = 1 - _controller.value; NOT HERE
  return GestureDetector(
    onTap: _onTap,
    onTapDown: _onTapDown,
    onTapUp: _onTapUp,
    onTapCancel: _onTapCancel,
    child: AnimatedBuilder(
        animation: _controller,
        child: _animatedButtonUI,
        builder: (context, child) {
          _scale = 1 - _controller.value; //HERE
          return Transform.scale(
            scale: _scale,
            child: child,
          );
        },
    )
  );
}

【讨论】:

    猜你喜欢
    • 2021-01-01
    • 2021-06-25
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多