dart泛型typedef函数不是CupertinoSlidingSegmentedControl错误的子类型



上下文:

我正在尝试通过一些修改来扩展和实现自定义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在这里找到的答案

我想做什么

我正在将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和(is(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) => Text'是我的自定义函数,它应该返回typedef中指定的Widget

在Slider的构建函数中强制小工具

如果我强制将其作为带有的Widget

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

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

在itemBuilder的函数中强制使用Widget

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

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

关键问题是_SegmentedSliderState不会自动知道如何参数化其父小部件的类型,因此继承的widget属性的类型为SegmentedSlider<dynamic>,而不是SegmentedSlider<T>

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

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

相关内容

最新更新