flutter - Flutter Widget 中的 didChangeDependencies 钩子包含不准确的类数据
问题描述
在下面的代码中,我在 Flutter 中与 LifeCyrles 苦苦挣扎,我可以在 Provider 中更新我的状态,显然,只能在didChangeDependencies
钩子或模板小部件中(通过挂在按钮上的事件等)。
好吧,我不介意只有 didChangeDependencies 钩子对我有用,但是当我在前面提到的钩子中的逻辑取决于某些类属性时,我在类数据的准确性方面遇到了问题。我得到数据落后一步(因为build
我猜它是在钩子之前调用的)。
我无法在构建挂钩中运行此逻辑,因为它包含更改 Provider 中状态的请求。如果我尝试更改那里的状态,我会遇到以下错误:
setState() or markNeedsBuild() called during build.
或者这个
The setter 'lastPage=' was called on null.
Receiver: null
Tried calling: lastPage=true
我想要做什么:我有一个包装小部件,它包含三个其他小部件:页脚、页眉和 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);
}
}
我已经尝试过其他一些钩子,比如调度程序,但也许我在那里做错了什么。
SchedulerBinding.instance
.addPostFrameCallback((_) => this._detectLastPage());
它在第一轮集结时只被调用一次,仅此而已。我在这里缺少一个 Angular 钩子AfterViewInit
。在这里会很方便。
或Mounted
在 VueJS 中
如果您想查看整个图片,这就是我的代码的其余部分。如果您对架构,结构或其他方面有任何建议,欢迎您。由于我是 Flutter 的新手,因此非常感谢。
主要.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,
),
);
}
}
Welcome.dart(我的包装器)
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);
}
}
footer.dart(这就是我在代码最底部遇到数据问题的地方 - _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的build方法中获取当变量provider的值改变时应该改变的provider。这样只有相关的小部件被重绘。
对于您的情况,如果您想在到达最后一页后隐藏页眉和页脚,您可以声明一个变量,假设在您的提供程序中默认isLastPage
设置为false
。接下来,包装小部件,即header
和footer
ChangeNotificationListner
现在,让该小部件根据 的值决定它必须做什么isLastPage
,要么隐藏自己,要么显示。
我希望这有帮助!
推荐阅读
- javascript - 两个日期之间的确切月份差 - MomentJS
- search - 如何计算河内塔的最大分支因子
- javascript - 将 UTC ISO 字符串转换为 UTC 日期对象
- python - Numpy 通过索引列表调用数组值
- laravel - 从 url 流明中删除公共
- java - E/BitmapFactory:无法解码流:java.io.FileNotFoundException(没有这样的文件或目录)
- r - 使用 shinyjs 时,renderPlot 出错但 renderPrint 不出错
- php - 如何在 Symfony 的 PHPUnit Bridge 中使用 PHPUnit 扩展?
- java - AWS lambda:格式错误的 Lambda 代理响应
- javascript - 将数据写入firebase会删除节点并且没有数据写入