如何正确地开始和结束或动画和更改其他类颤动的文本

问题描述

我正在学习颤振,我想从 AlertDialog 响应(基本上来自其他类)开始动画并设置应用栏标题“同步”,然后在异步操作后结束动画并再次设置标题

所以目前我正在使用 GlobalKey 和 Riverpod(StateNotifier) 实现这一点。 创建 MainScreen GlobalKey 并在我调用异步操作之前使用其他类中的 GlobalKey

mainScreenScaffoldKey.currentState.context
      .read(syncProgressprovider)
      .setSyncing();

并在异步操作后结束动画:

 mainScreenScaffoldKey.currentState.context
      .read(syncProgressprovider)
      .syncProgressDone();

代码

Map<String,dynamic> dialogResponse = await showDialog(
    context: context,builder: (context) => EditNoteScreen(
          _index,_task,_color,dateTime,priority: priority,));
if (dialogResponse != null) {
  mainScreenScaffoldKey.currentState.context
      .read(syncProgressprovider)
      .setSyncing();
  await SavetoLocal().save(context.read(listStateProvider.state));
  await CloudNotes().updateCloudNote(
    task: dialogResponse["task"],priority: dialogResponse["priority"],dateTime: dateTime.toString(),index: dialogResponse["index"],);
  mainScreenScaffoldKey.currentState.context
      .read(syncProgressprovider)
      .syncProgressDone();
}

和 MainScreen 中 AppBar 标题属性中的监听变量

我觉得这不是正确的方法吗?

这里有一些额外的片段 同步进度提供者:

 class SyncProgressModel extends StateNotifier<bool>{

 SyncProgressModel() : super(false);

 syncProgressDone(){
   state =false;
 }
 setSyncing(){
   state =true;
 }

主屏幕应用栏标题

Consumer(
      builder: (context,watch,child) {
        var syncProgress = watch(syncProgressprovider.state);
        if (!syncProgress) {
          return const Text('To-Do List');
        } else {
          return Row(
            children: [
              const Text('Syncing..'),Container(
                margin: const EdgeInsets.only(left: 10),width: 25,height: 25,child: CircularProgressIndicator(
                  strokeWidth: 2,valueColor: animColors,),)
            ],);
        }
      },

像这样

enter image description here

解决方法

我对你的动画一无所知(你实际上并没有分享任何逻辑或你指的是什么 initState)但是如果你唯一想要的是为 CircularProgressIndicator 的颜色设置动画,那么你可以创建一个为您执行此操作的 StatefulWidget 并仅在 syncProgress == true

时调用它来构建
class AnimatedWidget extends StatefulWidget {
  AnimatedWidget({Key key}) : super(key: key);

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

class _AnimatedWidgetState extends State<AnimatedWidget>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  final Animatable<Color> _colorTween = TweenSequence<Color>([
    TweenSequenceItem<Color>(
      tween: ColorTween(begin: Colors.red,end: Colors.amber),weight: 20,),TweenSequenceItem<Color>(
      tween: ColorTween(begin: Colors.amber,end: Colors.green),TweenSequenceItem<Color>(
      tween: ColorTween(begin: Colors.green,end: Colors.blue),TweenSequenceItem<Color>(
      tween: ColorTween(begin: Colors.blue,end: Colors.purple),TweenSequenceItem<Color>(
      tween: ColorTween(begin: Colors.purple,end: Colors.red),]).chain(CurveTween(curve: Curves.linear));

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 5),animationBehavior: AnimationBehavior.preserve,vsync: this,)..repeat();
  }

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

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const Text('Syncing..'),Container(
          margin: const EdgeInsets.only(left: 10),width: 25,height: 25,child: CircularProgressIndicator(
            strokeWidth: 2,valueColor: _colorTween.animate(_controller)
          ),)
      ],);
  }
}

在您的消费者中调用它,小部件将自行处理动画

Consumer(
      builder: (context,watch,child) {
        var syncProgress = watch(syncProgressProvider.state);
        if (!syncProgress) {
          return const Text('To-Do List');
        } else {
          return AnimatedWidget(); //right here
        }
      },

更新

要在其 dispose() 方法中安全地引用小部件的祖先,请保存一个 通过调用引用祖先 小部件中的dependOnInheritedWidgetOfExactType() didChangeDependencies() 方法。

这意味着在重建上下文本身之前,您应该根据上下文保留对象的引用(当您在对话框中调用 updateValueAt 或 updateValue 时,它​​会重建列表并且不再安全地调用上下文。阅读)

updateCloudNote(BuildContext context) async {
    /// keep the reference before calling the dialog to prevent 
    /// when the context change because of the dialogs action
    final syncProgress = context.read(syncProgressProvider); 
    final listState = context.read(listStateProvider.state);
    Map<String,dynamic> dialogResponse = await showDialog(
        context: context,builder: (context) => EditNoteScreen(
              _index,_task,_color,dateTime,priority: priority,));
    if (dialogResponse != null) {
      //when using GlobalKey didn't get that Widget Ancestor error
      // use the reference saved instead of context.read
      syncProgress.setSyncing();
      await SaveToLocal().save(listState);
      await CloudNotes().updateCloudNote(
        task: dialogResponse["task"],priority: dialogResponse["priority"],dateTime: dateTime.toString(),index: dialogResponse["index"],);
      syncProgress.syncProgressDone();
    }
  }

您组合提供者所做的基本上就是您可以在同一个 syncProgressProvider

final syncProgressProvider = StateNotifierProvider<SyncProgressModel>((ref)
    => SyncProgressModel(ref.read));

class SyncProgressModel extends StateNotifier<bool>{
 final saveToLocal saveLocal = SaveToLocal();
 final CloudNotes cloudNotes = CloudNotes();
 final Reader _read;

 SyncProgressModel(this._read) : super(false);

 syncProgressDone(){
   state = false;
 }

 setSyncing(){
   state = true;
 }

 updateCall({int priority,int index,String task,String dateTime}) async {
   state = true;
   await saveLocal.save(_read(listStateProvider.state));
   await cloudNotes.updateCloudNote(
      task: task,dateTime: dateTime,index: index,);
   state = false;
  }

}

最后结合两个想法:

updateCloudNote(BuildContext context) async {
    /// keep the reference before calling the dialog to prevent 
    /// when the context change because of the dialogs action
    final syncProgress = context.read(syncProgressProvider); 
    Map<String,));
    if (dialogResponse != null) {
      await syncProgress.updateCall(
        task: dialogResponse["task"],);
    }

 }