如何在Flutter的StreamBuilder中制作动画?

3
为了测试BloC设计模式,我从基本的Flutter示例开始。在StreamBuilder中的缩放类型动画不起作用。
这是项目的源代码: https://github.com/fabienbellanger/flutter_bloc_example
动画仅在小部件加载时启动,而不是每次计数器更改时都启动。
[编辑] 我希望每次点击“+”时,计数器的字体大小都会增长。它只能在加载主页后工作一次。 输入图像描述 IncrementBloc
import 'dart:async';

import 'package:flutter_bloc_example/src/blocs/bloc_provider.dart';

class IncrementBloc implements BlocBase {
  final int _counterInitial = 0;

  int counter;

  ///
  /// Stream to handle the counter
  ///
  StreamController<int> _counterController = StreamController<int>.broadcast();
  StreamSink<int> get _inUpdate => _counterController.sink;
  Stream<int> get outCounter => _counterController.stream;

  ///
  /// Stream to handle the action on the counter
  ///
  StreamController<String> _actionController = StreamController<String>();
  StreamSink<String> get updateCounter => _actionController.sink;

  ///
  /// Constructor
  ///
  IncrementBloc() {
    counter = _counterInitial;
    _actionController.stream.listen(_handleLogic);
  }

  void dispose() {
    _actionController.close();
    _counterController.close();
  }

  void _handleLogic(String data) {
    if (data == 'add') {
      counter = counter + 1;
    } else {
      if (counter == 0) {
        counter = 0;
      } else {
        counter = counter - 1;
      }
    }

    _inUpdate.add(counter);
  }
}

计数器主页

import 'package:flutter/material.dart';
import 'package:flutter_bloc_example/src/blocs/bloc_provider.dart';
import 'package:flutter_bloc_example/src/blocs/increment_bloc.dart';
import 'package:flutter_bloc_example/src/blocs/navigation_bloc.dart';
import 'package:flutter_bloc_example/src/ui/pages/tabbar_page.dart';

///
/// CounterHome class
///
class CounterHome extends StatefulWidget {
  @override
  _CounterHomeState createState() => _CounterHomeState();
}

class _CounterHomeState extends State<CounterHome> {
  @override
  Widget build(BuildContext context) {
    final IncrementBloc _incrementBloc = BlocProvider.of<IncrementBloc>(context);

    return Center(
      child: StreamBuilder<int>(
          stream: _incrementBloc.outCounter,
          initialData: _incrementBloc.counter,
          builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                TextCounter(
                  counter: snapshot.data,
                ),
                RaisedButton(
                  color: Colors.orange,
                  textColor: Colors.white,
                  disabledColor: Colors.grey,
                  disabledTextColor: Colors.white70,
                  padding: const EdgeInsets.all(10.0),
                  child: const Text(
                    'Go to TabBar Page',
                    style: TextStyle(fontSize: 18.0),
                  ),
                  onPressed: () {
                    Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) {
                      return BlocProvider<NavigationBloc>(
                        bloc: NavigationBloc(),
                        child: TabBarPage(),
                      );
                    }));
                  },
                ),
              ],
            );
          }),
    );
  }
}

class TextCounter extends StatefulWidget {
  final int counter;

  const TextCounter({Key key, this.counter}) : super(key: key);

  @override
  _TextCounterState createState() => _TextCounterState();
}

class _TextCounterState extends State<TextCounter> with SingleTickerProviderStateMixin {
  AnimationController _animationController;
  Animation<double> _animationSize;
  int counter;

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

    counter = widget.counter;

    _animationController = new AnimationController(
      duration: const Duration(milliseconds: 400),
      vsync: this,
    );

    _animationController.addListener(() {
      setState(() {});
    });

    _animationSize = new Tween(begin: 5.0, end: 70.0).animate(_animationController);

    _animationController.forward();
  }

  @override
  void didUpdateWidget(TextCounter oldWidget) {
    if (counter != widget.counter) {
      setState(() {
        counter = widget.counter;

        print('didUpdateWidget');
      });
    }
    super.didUpdateWidget(oldWidget);
  }

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

  @override
  Widget build(BuildContext context) {
    double size = _animationSize?.value;

    return Text(
      counter.toString(),
      style: TextStyle(
        fontSize: size,
        color: Colors.blue,
      ),
    );
  }
}

4
请发布您的动画代码。 - pskink
对不起,我刚刚添加了它。 - Fabien Bellanger
谢谢你,但我不能应用你的解决方案。 - Fabien Bellanger
你运行了我发布的部件吗?将其应用到你的代码上有什么问题吗? - pskink
当我运行你的小部件时,它可以工作。但是我无法将其应用到我的示例中 :( 在点击增量按钮后,蓝色计数器没有动画效果,只有在我切换BottomAppBar项目时才会有动画效果。 - Fabien Bellanger
1个回答

0

要在StreamBuilder中进行转换动画非常容易,您可以简单地使用一个名为AnimatedSwitcher的小部件:

@override
Widget build(BuildContext context) {
 return StreamBuilder(
  stream: FirebaseAuth.instance.onAuthStateChanged,
  builder: (BuildContext context, snapshot) {
    return AnimatedSwitcher(
      duration: Duration(seconds: 1),
      child: _getMainWidget(snapshot, context),
    );
  },
);
}

在这里,我们使用AnimatedSwitcher来在子元素更改时动画过渡, 默认动画是淡入淡出的动画,但您可以通过将TransitionBuilder作为参数传递给小部件来轻松指定自己的动画。

非常感谢你的回答。即使使用了AnimatedSwitcher,它仍然无法正常工作:( 我已经更新了存储库(https://github.com/fabienbellanger/flutter_bloc_example),如果您想查看代码,请前往此链接。 - Fabien Bellanger
你好,Fabien。我看了一下你的代码,我建议你确保一件事情:在你的代码中,你将一个键传递给AnimatedSwitcher的子组件:key: ValueKey<int>(snapshot.data),请确保这个数据是一个整数,并且每次都会改变。如果键相同,就不会发生动画效果。那么,如何将计数器递增的值作为键传递呢?这可能会有所帮助!祝你好运! - ezzou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接