Flutter Widget中的didChangeDependencies挂钩包含不正确的类数据 [英] didChangeDependencies hook in Flutter Widget includes not accurate data of the class

查看:329
本文介绍了Flutter Widget中的didChangeDependencies挂钩包含不正确的类数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码中,我在Flutter中的LifeCyrles挣扎,只能在 didChangeDependencies 钩子或模板小部件(通过中)更新提供者的状态事件挂在按钮上)。

In my code below, I am struggling with LifeCyrles in Flutter where I can update my State in Provider, APPARENTLY, only in didChangeDependencies hook or in a template widget (via events hung up on buttons or so).

好的,我不介意只有当我前面提到的钩子中的逻辑依赖于某些类属性时,didChangeDependencies钩子才对我有用,但是我的准确性存在问题类数据。
我将数据落后了一步(因为我猜它是在 build 钩子之前调用的)。

Alright, I don't mind that only didChangeDependencies hook works for me BUT when my logic in earlier mentioned hook depends on some class properties I am having problems with the accuracy of the class data. I get data one step behind (since it's called before build hook I guess).

我无法在构建挂钩中运行此逻辑,因为它包含更改Provider中状态的请求。如果尝试更改状态,则会出现以下错误:

I cannot run this logic in the build hook because it includes a request to change the state in Provider. If I try to change the state there I've got either this error:

setState()或在构建过程中调用的markNeedsBuild()。

或这个

setter'lastPage ='被调用为null。
接收方:空
尝试调用:lastPage = true

我想做什么:我有一个包装器小部件,其中包含其他三个小部件:页脚,页眉和pageViewer。
当我到达最后一页时,我需要通知我的包装窗口小部件,以便它做出相应的反应并隐藏页眉和页脚。

What I want to do: I've got a wrapper widget which holds three other widgets: footer, header and pageViewer. When I reach the last page I need to notify my wrapper widget about that so it reacts accordingly and hides header and footer.

在此感谢您的帮助!

重点代码:

这是问题所在,必须解决

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,但也许我在那儿做错了。

I have already tried some other hooks like Scheduler but maybe I did something wrong there.

SchedulerBinding.instance
        .addPostFrameCallback((_) => this._detectLastPage());

在第一个集结阶段仅调用一次,仅此而已。
我在 AfterViewInit 中缺少Angular钩子。

It's called only once at the first build-up round and that's it. I lack an Angular hook here AfterViewInit. It would be handy here.

Mounted 在VueJS中

这是我剩下的代码,如果您想查看整个图片的话。
如果您对架构,结构或其他内容有任何建议,欢迎您。

That's the rest of my code if you'd like to see the whole picture. If you have any suggestions on the architecture, structure or something else you are welcome. It's highly appreciated since I'm new to 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,
      ),
    );
  }
}

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 (我通过提供者提供的状态)

welcomeBloc.dart (my state via Provider)

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方法)

footer.dart (that's where I've problems with data at the very bottom of the code - _detectLastPage method)

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;
    }
  }
}

提前谢谢!

推荐答案

我也是新手,但我了解到一些架构模式对您有所帮助我构建了一些应用程序。

I am new to flutter as well, But I have learned about a few architecture patterns that have helped me build some apps.

这是我的操作方式:

创建提供程序在运行时为您保存数据。 (根据您的情况,它可以是 Bloc )。坚持一种架构,不要试图将提供者和集团放在同一个项目中。两者都用于状态管理,并且仅使用一个是一种很好的做法。

Create a Provider which holds the data for you in runtime. (It can be a Bloc in your case). Stick to one architecture, don't try to put providers and blocs in the same project. Both are used for state management and only using one would be a great practice.

第二,注册提供者使用 ChangeNotificationProvider 或完成数据更改后重建子小部件的类似工作的任何其他小部件。

Second, Register the providers using ChangeNotificationProvider or any other widgets which does a similar job of rebuilding the child widget when a data gets changed.

第三,在小部件的build方法中获取提供程序,该提供程序应在变量provider的值更改时更改。这样,只重绘了相关的小部件。

Third, Get the provider in the build method of the widget that is supposed to change when the value of the variable provider changes. This way only the concerned widget is redrawn.

对于您的情况,
如果您想在到达最后一页后隐藏页眉和页脚,则可以声明一个变量,假设您的提供程序中默认将 isLastPage 设置为 false
接下来,用 ChangeNotificationListner包装小部件,即 header footer code>

For your case, If you want to hide the header and footer once you reach the last page, you can declare a variable, let's say isLastPage set to false by default in your provider. Next, wrap the widget, i.e. header and footer with ChangeNotificationListner

现在,让该小部件根据 isLastPage 的值来决定要执行的操作,要么隐藏自己要么显示自己。

Now, let that widget decide what it has to do based on the value of isLastPage, either hide itself or show.

我希望这会有所帮助!

这篇关于Flutter Widget中的didChangeDependencies挂钩包含不正确的类数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆