3

Context:

I created my own wrapper for CupertinoSlidingSegmentedControl with the help of a generic item builder.

The primary purpose of this is to group alot of similiar functionality with the addition of an easy to use "custom item builder" if I want additional icons, etc in the slider items.

I wish to make this generic using a custom typedef generic function as my item builder, I define like this:

Problem:

The problem I have is as follows:

typedef ItemValueWidgetBuilder<T> = Widget Function(BuildContext context, T key, bool active);

According to this post, my function (interface) is implemented correctly;

My implementation results in:

(BuildContext context, SexualPreference key, bool active) => Widget (*Text specifically*)

Shown the error below, I am unable to use this.

The following _TypeError was thrown building SegmentedSlider<SexualPreference>(dirty, dependencies: [_LocalizationsScope-[GlobalKey#f3e39], _InheritedTheme], state: _SegmentedSliderState<SexualPreference>#ab773):
type '(BuildContext, SexualPreference, bool) => Text' is not a subtype of type '(BuildContext, dynamic, bool) => Widget'

Question:

The only way I can get it (typedef + generics) to work is removing any trace of generics which is quite pointless.

What am I missing/doing wrong?


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

The relevant error-causing widget was: 
  SegmentedSlider<SexualPreference> file:///...mobile-flutter/lib/viewcontrollers/register/user/ui_register_details.dart:197:11
When the exception was thrown, this was the stack: 
#0      _SegmentedSliderState.build.<anonymous closure> (package:my-awesome-app/framework/ui/components/slider.dart:35:28)
#1      MappedListIterable.elementAt (dart:_internal/iterable.dart:412:31)
#2      ListIterator.moveNext (dart:_internal/iterable.dart:341:26)
#3      MapMixin.addEntries (dart:collection/maps.dart:177:23)
#4      new Map.fromEntries (dart:core/map.dart:182:17)

CupertinoSlider wrapper usage example:

SegmentedSlider<SexualPreference>(
    thumbColor: themeService.getAccentSwatchTheme(),
    onValueChanged: (value) {
      profile!.preferences.sexualOrientation = value!;
      profileRef.update(profile!.toJson());
      setState(() {});
    },
    itemBuilder: (context, key, active) => Text(
          SexualPreferenceExt.asString(key),
          style: Theme.of(context).textTheme.subtitle2!.copyWith(
                color: active
                    ? Colors.white
                    : themeService.getAccentSwatchTheme(),
              ),
        ),
    selectedValue: SexualPreference.None,
    values: SexualPreference.values
),

CupertinoSlider wrapper code:

// typedef ItemValueWidgetBuilder<T> = Widget Function(BuildContext context, T key, 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> itemBuilder;

  const SegmentedSlider({Key? key, this.thumbColor = Colors.grey, this.backgroundColor = Colors.white, required this.onValueChanged, required this.itemBuilder, 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) {
    var map = widget.values.map((e) {
      var _widget = widget.itemBuilder(context, e, e == activeValue);
      print(_widget);
      return MapEntry<T, Widget>(e, _widget);
    });
    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,
    );
  }
}
CybeX
  • 2,060
  • 3
  • 48
  • 115
  • The Same problem here, if you find a solution please share (: – Rafael Menicucci Jul 07 '21 at 22:54
  • @RafaelMenicucci may be of some use: https://stackoverflow.com/questions/68256552/dart-generic-typedef-function-is-not-subtype-of-error-with-cupertinoslidingsegme. Check you have `` everywhere - see my code example - I was missing one only as described in the comments – CybeX Jul 07 '21 at 23:07

0 Answers0