11

我正在尝试创建一个通用的消费者小部件,以促进 ViewModel 对其孩子的影响。因此我有两个功能。一个在 ViewModel 初始化后具有函数(T),另一个用于将模型传递给其子 Widget。

在泛型类中是 ChangeNotifier 的子级,在我想在两个函数中发送 T 值之前它工作正常。

然后我收到以下错误:

类型 '(OnBoardingViewModel) => Null' 不是类型 '(ChangeNotifier) => void' 的子类型

type '(BuildContext, OnBoardingViewModel, Widget) => Scaffold' 不是类型 '(BuildContext, ChangeNotifier, Widget) => Widget' 的子类型

但是当我将扩展类型从 ChangeNotifier 更改为 OnBoardingViewModel 时,一切正常。

有人可以帮助我或解释为什么这不起作用吗?

import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:provider/provider.dart';

class StateFullConsumerWidget<T extends ChangeNotifier> extends StatefulWidget{

  StateFullConsumerWidget({@required this.builder,Key key,this.onPostViewModelInit,this.child}) : super(key : key);

  final Widget Function(BuildContext context, ChangeNotifier value, Widget child) builder;
  final Widget child;

  final void Function(T) onPostViewModelInit;

  @override
  _StateFullConsumerWidgetState<T> createState() => _StateFullConsumerWidgetState<T>();
}

class _StateFullConsumerWidgetState<T extends ChangeNotifier> extends State<StateFullConsumerWidget>{
  T _viewModel;
  @override
  void initState() {
    // assign the model once when state is initialised
    _viewModel = GetIt.instance.get<T>();
    widget.onPostViewModelInit(_viewModel);


    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<T>(
      builder: (context) => _viewModel,
      child: Consumer<T>(
        builder: widget.builder,
        child: widget.child,
      ),
    );
  }

}

我的小部件

StateFullConsumerWidget<OnBoardingViewModel>(
      onPostViewModelInit: (viewModel){
        buildIntroList(viewModel);
        viewModel.maxPages = _introWidgetsList.length;
      },
      builder: (context,viewModel,child) {
        return Scaffold(
          key: widget.scaffoldKey,
          body: SafeArea(
            child: Container(),
            ),
          ),
        );
      },
    );

我的视图模型

import 'package:flutter/material.dart';

class OnBoardingViewModel extends ChangeNotifier{

  OnBoardingViewModel(){

  }
}
4

2 回答 2

25

您使用泛型类型的方式T是不完整的。代码中编写的StateFullConsumerWidget和类之间的关系是这样的,即使用与其自身相同的类型参数创建其状态,因此小部件知道该状态使用与它相同的泛型类型。但是,从 的角度来看,该类是这样声明的:_StateFullConsumerWidgetStateStateFullConsumerWidgetT_StateFullConsumerWidgetState

class _StateFullConsumerWidgetState<T extends ChangeNotifier> 
    extends State<StateFullConsumerWidget>

问题是状态类使用 的一般形式,因此作为类型参数接收的 与正在使用的之间StateFullConsumerWidget没有明确的关系。Dart 不知道如何调和这种模棱两可的关系,所以它默认使用类型约束允许的最小公分母,即.T_StateFullConsumerWidgetStateTStateFullConsumerWidgetChangeNotifier

因此,当您尝试将Tas 视为时OnBoardingViewModel,Dart 会抛出错误,因为据状态类所知,T父窗口小部件的 是ChangeNotifier,而不是OnBoardingViewModel

您可以通过在声明状态类时传递类型参数来解决此问题:

class _StateFullConsumerWidgetState<T extends ChangeNotifier> 
    extends State<StateFullConsumerWidget<T>>
于 2019-09-11T18:19:55.957 回答
2

我不确定为什么会这样,但 dart 编译器无法将 StateFullConsumerWidget 的类型 T 识别为 _StateFullConsumerWidgetState 的相同类型 T。如果你将函数传递给 State 一切都会按预期工作。

结果代码:

class StateFullConsumerWidget<T extends ChangeNotifier> extends StatefulWidget{

  StateFullConsumerWidget({@required this.builder,Key key,this.onPostViewModelInit,this.child}) : super(key : key);

  final Widget Function(BuildContext context, T value, Widget child) builder;
  final Widget child;

  final Function(T viewModel) onPostViewModelInit;

  @override
  _StateFullConsumerWidgetState<T> createState() => _StateFullConsumerWidgetState<T>(onPostViewModelInit, builder);
}

class _StateFullConsumerWidgetState<T extends ChangeNotifier> extends State<StateFullConsumerWidget>{
  final Function(T viewModel) _onPostViewModelInit;
  final Widget Function(BuildContext context, T value, Widget child) _builder;
  T _viewModel;

  _StateFullConsumerWidgetState(this._onPostViewModelInit, this._builder);

  @override
  void initState() {
    // assign the model once when state is initialised
    _viewModel = GetIt.instance.get<T>();
    _onPostViewModelInit(_viewModel);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<T>(
      builder: (context) => _viewModel,
      child: Consumer<T>(
        builder: _builder,
        child: widget.child,
      ),
    );
  }
}
于 2019-09-11T15:59:05.480 回答