问题描述
我正在学习颤振,我想从 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,),)
],);
}
},
像这样
解决方法
我对你的动画一无所知(你实际上并没有分享任何逻辑或你指的是什么 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"],);
}
}