passing generic type by Function(T) in flutter

自闭症网瘾萝莉.ら 提交于 2020-02-24 05:49:06

问题


I'm trying to create a generic consumer widget that facilitates the ViewModel to its child. therefor I have two functions. one that has a function(T) after init of the ViewModel and the other for passing the model to its child Widget.

in the generic class is a child of ChangeNotifier and that works fine until I want to send the T value in the two Functions.

then I get the following errors:

type '(OnBoardingViewModel) => Null' is not a subtype of type '(ChangeNotifier) => void'

and

type '(BuildContext, OnBoardingViewModel, Widget) => Scaffold' is not a subtype of type '(BuildContext, ChangeNotifier, Widget) => Widget'

But when i change the extends type from ChangeNotifier to OnBoardingViewModel, everything works fine.

can someone help me and or explain why this ain't working??

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

}

my widget

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

my ViewModel

import 'package:flutter/material.dart';

class OnBoardingViewModel extends ChangeNotifier{

  OnBoardingViewModel(){

  }
}

回答1:


The way you are using the generic type T is incomplete. The relationship between the StateFullConsumerWidget and the _StateFullConsumerWidgetState classes as written in your code are such that StateFullConsumerWidget creates its state using the same T type parameter as itself, so the widget knows the state uses the same generic type that it does. From the perspective of _StateFullConsumerWidgetState, though, the class is declared as such:

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

The problem is the state class is using the general form of StateFullConsumerWidget, so there is no explicit relationship between the T that _StateFullConsumerWidgetState is receiving as the type parameter and the T that StateFullConsumerWidget is using. Dart doesn't know how to reconcile this ambiguous relationship, so it defaults to the lowest common denominator the type constraints allow, which is ChangeNotifier.

Because of this, when you try to treat T as OnBoardingViewModel, Dart throws an error because, as far as the state class knows, the T of the parent widget is ChangeNotifier, not OnBoardingViewModel.

You can fix this by passing the type parameter along when you declare your state class:

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



回答2:


I am not exactly sure why this is the case, but the dart compiler doesn't recognize the type T from the StateFullConsumerWidget as the same type T of the _StateFullConsumerWidgetState. If you pass the functions to the State everything works as expected.

Resulting code:

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


来源:https://stackoverflow.com/questions/57886661/passing-generic-type-by-functiont-in-flutter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!