在我下面的代码中,我在Flutter的LifeCyrles中挣扎,在那里我可以在Provider中更新我的State,APPARENTLY,只有在 didChangeDependencies
钩子或在一个模板部件中(通过挂在按钮上的事件等)。
好吧,我不介意只有didChangeDependencies钩子对我有效,但是当我在前面提到的钩子中的逻辑依赖于一些类的属性时,我对类数据的准确性有问题。我得到的数据晚了一步(因为它的调用是在 build
钩子吧)。)
我不能在构建钩子中运行这个逻辑,因为它包含了一个在Provider中改变状态的请求。如果我试着在那里改变状态,我得到的不是这个错误。
setState() or markNeedsBuild() called during build.
或者是这个
The setter 'lastPage=' was called on null.
Receiver: null
Tried calling: lastPage=true
我想做什么: 我有一个wrapper widget,里面有另外三个widget:footer、header和pageViewer。当我到达最后一页时,我需要通知我的包装部件,这样它就会做出相应的反应并隐藏页眉和页脚。
如果有任何帮助,我将不胜感激
重点代码。
以下是问题和必须解决的问题
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:ui_flutter/screens/welcome/welcome_bloc.dart';
import 'package:flutter/scheduler.dart';
class _FooterState extends State<Footer> {
@override
void initState() {
super.initState();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
final WelcomeBloc _welcome = Provider.of<WelcomeBloc>(context);
_welcomeBloc = _welcome;
// this._detectLastPage();
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.bottomCenter,
padding: EdgeInsets.symmetric(vertical: 30.0, horizontal: 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
this.stepper,
this.nextArrow,
],
),
);
}
_detectLastPage() {
// Here I've got inaccurate data
print(this.widget.currentStep);
}
}
我已经尝试了一些其他的钩子,比如Scheduler,但也许我在那里做错了什么。
SchedulerBinding.instance
.addPostFrameCallback((_) => this._detectLastPage());
它只在第一轮建立时调用一次,就是这样。我这里缺少一个Angular钩子 AfterViewInit
. 这将是方便在这里。
或者 Mounted
在VueJS中
这就是我代码的其余部分,如果你想看全貌的话.如果你对架构、结构或其他方面有什么建议,欢迎提出。这是高度赞赏,因为我是新来的Flutter。
main.dart
import 'package:flutter/material.dart';
import 'package:ui_flutter/routing.dart';
import 'package:provider/provider.dart';
import 'screens/welcome/welcome_bloc.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => WelcomeBloc()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/welcome',
onGenerateRoute: RouteGenerator.generateRoute,
),
);
}
}
迎宾镖局 (我的包装纸)
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:provider/provider.dart';
import 'package:ui_flutter/screens/welcome/welcome_bloc.dart';
import './footer.dart';
import './viewWrapper.dart';
import './header.dart';
// import 'package:ui_flutter/routing.dart';
class Welcome extends StatefulWidget {
@override
_WelcomeState createState() => _WelcomeState();
}
class _WelcomeState extends State<Welcome> {
WelcomeBloc _welcomeBloc;
@override
Widget build(BuildContext context) {
final WelcomeBloc _welcome = Provider.of<WelcomeBloc>(context);
this._welcomeBloc = _welcome;
print('Welcome: _welcome.currentPage - ${this._welcomeBloc.lastPage}');
return Scaffold(
body: SafeArea(
child: Stack(
children: <Widget>[
ViewerWrapper(),
Footer(
currentStep: _welcomeBloc.currentPage,
totalSteps: 3,
activeColor: Colors.grey[800],
inactiveColor: Colors.grey[100],
),
WelcomeHeader,
],
),
),
);
}
}
WelcomeBloc.dart (我的国家通过提供者)
import 'package:flutter/material.dart';
class WelcomeBloc extends ChangeNotifier {
PageController _controller = PageController();
int _currentPage;
bool _lastPage = false;
bool get lastPage => _lastPage;
set lastPage(bool value) {
_lastPage = value;
notifyListeners();
}
int get currentPage => _currentPage;
set currentPage(int value) {
_currentPage = value;
notifyListeners();
}
get controller => _controller;
nextPage(Duration duration, Curves curve) {
controller.nextPage(duration: duration, curve: curve);
}
}
脚下的飞镖 (这就是我在代码最底部的数据问题--_detectLastPage方法)
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:ui_flutter/screens/welcome/welcome_bloc.dart';
import 'package:flutter/scheduler.dart';
class Footer extends StatefulWidget {
final int currentStep;
final int totalSteps;
final Color activeColor;
final Color inactiveColor;
final Duration duration;
final Function onFinal;
final Function onStart;
Footer({
this.activeColor,
this.inactiveColor,
this.currentStep,
this.totalSteps,
this.duration,
this.onFinal,
this.onStart,
}) {}
@override
_FooterState createState() => _FooterState();
}
class _FooterState extends State<Footer> {
final double radius = 10.0;
final double distance = 4.0;
Container stepper;
Container nextArrow;
bool lastPage;
WelcomeBloc _welcomeBloc;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final WelcomeBloc _welcome = Provider.of<WelcomeBloc>(context);
_welcomeBloc = _welcome;
this._detectLastPage();
}
@override
Widget build(BuildContext context) {
this._makeStepper();
this._makeNextArrow();
return Container(
alignment: Alignment.bottomCenter,
padding: EdgeInsets.symmetric(vertical: 30.0, horizontal: 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
this.stepper,
this.nextArrow,
],
),
);
}
_makeCirle(activeColor, inactiveColor, position, currentStep) {
currentStep = currentStep == null ? 0 : currentStep - 1;
Color color = (position == currentStep) ? activeColor : inactiveColor;
return Container(
height: this.radius,
width: this.radius,
margin: EdgeInsets.only(left: this.distance, right: this.distance),
decoration: BoxDecoration(
color: color,
border: Border.all(color: activeColor, width: 2.0),
borderRadius: BorderRadius.circular(50.0)),
);
}
_makeStepper() {
List<Container> circles = List();
for (var i = 0; i < widget.totalSteps; i++) {
circles.add(
_makeCirle(this.widget.activeColor, this.widget.inactiveColor, i,
this.widget.currentStep),
);
}
this.stepper = Container(
child: Row(
children: circles,
),
);
}
_makeNextArrow() {
this.nextArrow = Container(
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: GestureDetector(
onTap: () {
_welcomeBloc.controller.nextPage(
duration: this.widget.duration ?? Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
},
child: Icon(
Icons.arrow_forward,
)),
),
);
}
_onLastPage() {
if (this.widget.onFinal != null) {
this.widget.onFinal();
}
}
_onFirstPage() {
if (this.widget.onStart != null) {
this.widget.onStart();
}
}
_detectLastPage() {
// Here I've got inaccurate data
int currentPage =
this.widget.currentStep == null ? 1 : this.widget.currentStep;
if (currentPage == 1 && this.widget.currentStep == null) {
this._onFirstPage();
} else if (currentPage == this.widget.totalSteps) {
print('lastPage detected');
setState(() {
this.lastPage = true;
});
_welcomeBloc.lastPage = true;
this._onLastPage();
} else {
setState(() {
this.lastPage = false;
});
_welcomeBloc.lastPage = false;
}
}
}
先谢谢你
我是新的flutter,以及,但我已经了解了一些架构模式,帮助我建立一些应用程序。
下面是我如何做的。
创建一个 Provider
它在运行时为你保存数据。它可以是一个 Bloc
的情况下)。) 坚持使用一种架构,不要试图把提供者和集团放在同一个项目中。两者都是用来进行状态管理的,只用其中一个是很好的做法。
第二种。Register
的提供者 ChangeNotificationProvider
或任何其他widget,当数据被改变时,它做了类似的工作来重建子widget。
第三,在构建方法中获取当变量提供者的值改变时应该改变的部件的提供者。这样,只有相关的widget会被重新绘制。
对于你的情况,如果你想在到达最后一页时隐藏页眉和页脚,你可以声明一个变量,比方说...。isLastPage
设为 false
下一步,将widget包装起来,即在你的provider中默认为 header
和 footer
与 ChangeNotificationListner
现在,让这个小组件根据 isLastPage
,要么隐藏自己,要么显示。
希望对大家有所帮助!
从长远来看,我似乎已经发现了 Mounted
生命周期钩子在Flutter中的帮助下实现。Future.microtask
. 不像 .addPostFrameCallback
:
SchedulerBinding.instance
.addPostFrameCallback((_) => this._detectLastPage());
只触发一次,像 InitState
(但只在构建执行结束时)。Future.microtask
可以放在 build
块,并在每次变更和状态更新后被调用。
这并不能解决状态不准确的问题。didChangeDependencies
钩子,但提供了另一种方式来执行构建后的执行。
归功于 @Abion47 的当前解决方案。
例子
Future.microtask(() => this._detectLastPage());