我遵循BLoC模式并订阅流,并对构建方法中的状态更改做出反应。加载数据后,我想关闭屏幕。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bloc'),
),
body: SafeArea(
child: StreamBuilder<UserState>(
stream: _userBloc.user,
initialData: UserInitState(),
builder: (context, snapshot) {
if (snapshot.data is UserInitState) {
return _buildInit();
}
if (snapshot.data is UserDataState) {
Navigator.pop(context, true);
return Container();
}
if (snapshot.data is UserLoadingState) {
return _buildLoading();
}
},
),
),
);
}
以Navigator.pop(context, true);
方法执行build()
时,我得到:
I/flutter ( 4360): ══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 4360): The following assertion was thrown while notifying status listeners for AnimationController:
I/flutter ( 4360): setState() or markNeedsBuild() called during build.
I/flutter ( 4360): This Overlay widget cannot be marked as needing to build because the framework is already in the
I/flutter ( 4360): process of building widgets. A widget can be marked as needing to be built during the build phase
I/flutter ( 4360): only if one of its ancestors is currently building. This exception is allowed because the framework
I/flutter ( 4360): builds parent widgets before children, which means a dirty descendant will always be built.
I/flutter ( 4360): Otherwise, the framework might not visit this widget during this build phase.
以BLoC模式处理此类案件的正确方法是什么?
我提出的解决方案之一是开始收听initState()
上的流。在这种情况下,我需要broadcast()
流,因为我有2个订阅者。
有没有更好的解决方案?
答案 0 :(得分:0)
我可以想象三种可能的解决方案:
1)在我看来,最好是重组小部件。据我所知,您需要一个“加载屏幕” ..我没有理由认为这必须是它自己的导航项,而不仅仅是另一个小部件。
即。您可以推let str = `From:
DEMO - Sliced Invoices Order Number
Suite 5A-1204 Order Number
123 Somewhere Street Order Number
Your City AZ 12345 Order Number
admin@slicedinvoices.com Order Number`
let op = str.match(/^.+?(?=\s{2,}|\n)/gm)
console.log(op)
吗?升级..因此您的构建器方法如下:
StreamBuilder
2)我想我个人将创建一个if (!snapshot.hasData) {
return LoadingScreen(snapshot);
}
// Whatever you do with your data.
,在StatefulWidget
中手动收听流,并手动调用initState()
。不需要setState()
3)作为一种疯狂的解决方法,您可能会在构建器中使用StreamBuilder
。 (有可能您必须使用Future(() { Navigator.of(context).pop(); });
方法的context
,而不是生成器。但我还是不建议使用该解决方案)
答案 1 :(得分:0)
我想我已经为您找到了解决方案。 (请检查)
使您的代码看起来像:
Widget build(BuildContext context) {
// other stuff
if (snapshot.data is UserDataState) {
myCallback(() {
Navigator.pop(context, true);
});
}
// other stuff
}
// after build method (but still in the same class,...) write below method
void myCallback(Function callback) {
WidgetsBinding.instance.addPostFrameCallback((_) {
callback();
});
}
希望有帮助。只需尝试一下,请在这里举报也可以帮助其他人!
答案 2 :(得分:0)
import SwiftUI
@main
struct SpinnerApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@State var isAnimating = false
@State var text = ""
var animation: Animation {
Animation.linear(duration: 3.0)
.repeatForever(autoreverses: false)
}
var body: some View {
HStack {
Spacer()
VStack {
Circle()
.foregroundColor(Color.orange)
.frame(height: 100)
.rotationEffect(Angle(degrees: self.isAnimating ? 360 : 0.0))
.animation(self.isAnimating ? animation : .default)
.onAppear { self.isAnimating = true }
.onDisappear { self.isAnimating = false }
if self.text != "" {
Text(self.text)
}
}
Spacer()
}
.background(Color.gray)
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now()+4, execute: {
self.text = "Test"
})
})
}
}