【问题标题】:dart generic typedef function is not subtype of error with CupertinoSlidingSegmentedControldart 通用 typedef 函数不是 CupertinoSlidingSegmentedControl 错误的子类型
【发布时间】:2021-09-16 06:13:43
【问题描述】:

上下文:

我正在尝试扩展和实现自定义 CupertinoSlidingSegmentedControl 并进行一些更改。

这是使用小部件的一个很好的例子:

class _ViewState extends State<View> {
  int segmentedControlGroupValue = 0;
  final Map<int, Widget> myTabs = const <int, Widget>{
    0: Text("Item 1"),
    1: Text("Item 2")
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CupertinoSlidingSegmentedControl(
          groupValue: segmentedControlGroupValue,
          children: myTabs,
          onValueChanged: (i) {
            setState(() {
              segmentedControlGroupValue = i;
            });
          }),
    );
  }
}

来自@AidanMarshall的答案here

我想做什么?

我正在将 myTabs 自定义为自定义 itemBuilder,类似于 ListView.builder 实现。我的实现应该使用如下:

SegmentedSlider<GenderPreference>(
  values: GenderPreference.values,
  thumbColor: Colors.blue, // or use a custom theme
  onValueChanged: (value) {
    // update profile information here
  },
  sliderItemBuilderFunction: (context, item, active) {
    return Text(
      GenderPreference.asString(item),
      style: Theme.of(context).textTheme.subtitle2!.copyWith(
        color: active
            ? Colors.white
            : Colors.green,
      ),
    );
  },
  selectedValue: GenderPreference.None,
)

有了这个,我使用自己的sliderItemBuilderFunction 函数定义如下:

typedef Widget ItemValueWidgetBuilder<T>(BuildContext context, T item, bool active);

这接受构建 context、通用项目 T 和(是)active 便利字段

问题:

问题是每次运行小部件时,values 中的每个项目都会出现以下错误:

======== Exception caught by widgets library =======================================================
The following _TypeError was thrown building SegmentedSlider<GenderPreference>(dirty, dependencies: [_LocalizationsScope-[GlobalKey#0a25e], _InheritedTheme], state: _SegmentedSliderState<GenderPreference>#40901):
type '(BuildContext, GenderPreference, bool) => Text' is not a subtype of type '(BuildContext, dynamic, bool) => Widget'

The relevant error-causing widget was: 
  SegmentedSlider<GenderPreference> file:///C:/Users/CybeX/MyAwesomeApp/awesome-app-mobile-flutter/lib/viewcontrollers/profile/ui_profile.dart:309:20
When the exception was thrown, this was the stack: 
#0      _SegmentedSliderState.build.<anonymous closure> (package:cozy_up/framework/ui/components/slider.dart:34:28)
#1      MappedListIterable.elementAt (dart:_internal/iterable.dart:412:31)
#2      ListIterator.moveNext (dart:_internal/iterable.dart:341:26)
#3      new _GrowableList._ofEfficientLengthIterable (dart:core-patch/growable_array.dart:188:27)
#4      new _GrowableList.of (dart:core-patch/growable_array.dart:150:28)
...
====================================================================================================
Reloaded 0 libraries in 1 536ms.

问题:

'(BuildContext, GenderPreference, bool) => Text' is not a subtype of type '(BuildContext, dynamic, bool) => Widget'

首先,'(BuildContext, GenderPreference, bool) =&gt; Text' 是我的自定义函数,它应该返回 typedef 中指定的 Widget

在 Slider 的构建函数中强制 Widget?

如果我将其作为Widget 强制使用

Widget _widget = widget.sliderItemBuilderFunction(context, e, e == activeValue);

在我的滑块 build 函数中,我得到了完全相同的错误。

在 itemBuilder 的函数中强制 Widget?

此外,如果我在 sliderItemBuilderFunction() 实现中返回一个小部件,我会得到同样的错误,但是

'(BuildContext, GenderPreference, bool) => Widget' is not a subtype of type '(BuildContext, dynamic, bool) => Widget'

我做错了什么?


使用的枚举

enum GenderPreference {
  Male,
  Female,
  Other,
  None,
}

extension GenderPreferenceExt on GenderPreference {
  static const enums = {
    GenderPreference.Male: 'Male',
    GenderPreference.Female: 'Female',
    GenderPreference.Other: 'Other',
    GenderPreference.None: 'None',
  };

  static String asString(GenderPreference genderPreference) {
    return enums[genderPreference] ?? "";
  }

  static GenderPreference parse(String _mode) {
    if (_mode == "" || _mode == null) {
      return GenderPreference.None;
    }
    return enums.entries
        .where((element) => element.value.toLowerCase() == _mode.toLowerCase())
        .first
        .key;
  }
}

完整的滑块实现:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

typedef Widget ItemValueWidgetBuilder<T>(
    BuildContext context, T item, bool active);

class SegmentedSlider<T> extends StatefulWidget {
  final Color backgroundColor;
  final Color thumbColor;
  final ValueChanged<T?> onValueChanged;
  final T selectedValue;
  final List<T> values;
  final ItemValueWidgetBuilder<T> sliderItemBuilderFunction;

  const SegmentedSlider(
      {Key? key,
      this.thumbColor = Colors.grey,
      this.backgroundColor = Colors.white,
      required this.onValueChanged,
      required this.sliderItemBuilderFunction,
      required this.selectedValue,
      required this.values})
      : super(key: key);

  @override
  _SegmentedSliderState<T> createState() => new _SegmentedSliderState<T>();
}

class _SegmentedSliderState<T> extends State<SegmentedSlider> {
  late T activeValue;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    activeValue = widget.selectedValue;
  }

  @override
  Widget build(BuildContext context) {
    List<MapEntry<T, Widget>> map = widget.values.map((e) {
      var _widget =
          widget.sliderItemBuilderFunction(context, e, e == activeValue);
      print(_widget);
      return MapEntry<T, Widget>(e, Container());
    }).toList();
    Map<T, Widget> children = Map.fromEntries(map);

    return CupertinoSlidingSegmentedControl<T>(
      backgroundColor: widget.backgroundColor,
      thumbColor: widget.thumbColor,
      onValueChanged: (value) {
        activeValue = value!;
        widget.onValueChanged(value);
      },
      children: children,
      groupValue: widget.selectedValue,
    );
  }
}

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    本质问题是_SegmentedSliderState不会自动知道如何参数化其父widget的类型,所以继承的widget属性的类型是SegmentedSlider&lt;dynamic&gt;而不是SegmentedSlider&lt;T&gt;

    要解决这个问题,只需像这样声明你的类:

    class _SegmentedSliderState<T> extends State<SegmentedSlider<T>> {
                                                                ^^^
    

    【讨论】:

    • *facepalm,我怎么会错过...谢谢!
    • 经过几天的互联网挖掘。这救了我的命!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-07
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    • 2021-08-30
    • 1970-01-01
    • 2021-11-09
    相关资源
    最近更新 更多