使用复杂签名子类化 Widget

Subclassing Widgets with complex signatures

据我所知,RadioListTile with Text als child has unlimited with.

作为帮手 class,我想用默认的 Text child 定义 来代替 class RadioListTile最大宽度.

不幸的是,RadioListTile 有一个非常复杂的构造函数。

是否存在最佳实践,如何创建 专用 RadioListTile 并以某种方式从复杂构造函数签名 中抽象?

RadioListTile 的构造函数:

  const RadioListTile({
    Key? key,
    required this.value,
    required this.groupValue,
    required this.onChanged,
    this.toggleable = false,
    this.activeColor,
    this.title,
    this.subtitle,
    this.isThreeLine = false,
    this.dense,
    this.secondary,
    this.selected = false,
    this.controlAffinity = ListTileControlAffinity.platform,
    this.autofocus = false,
    this.contentPadding,
    this.shape,
    this.tileColor,
    this.selectedTileColor,
    this.visualDensity,
    this.focusNode,
    this.enableFeedback,
  }) 

另一个例子

假设我经常使用这个片段:

Text( 'Tabelle', style: TextStyle(
            fontWeight: Theme.of(context).textTheme.bodyMedium?.fontWeight,
              fontSize: Theme.of(context).textTheme.bodyMedium?.fontSize,
            ) )

我想像这样使用专门的 Text() 小部件:

TextBodyMedium( 'Tabelle' )

如何在不枚举其所有 10 多个参数的情况下有序地专门化 Text() class?是否存在规范方式?

2022-05-12 更新: 使用 Dart 2.17,将参数传递给 superclass 构造函数的时间缩短了一倍,请参阅 https://dart.dev/guides/language/language-tour#super-parameters 以下所有内容仍然适用。

原回答:

在 Dart 中,无法自动将所有参数传递给 superclass。例如,这是 Column 小部件的实现方式(它是一个 Flex 垂直方向的小部件):

  Column({
    Key? key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection? textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline? textBaseline,
    List<Widget> children = const <Widget>[],
  }) : super(
    children: children,
    key: key,
    direction: Axis.vertical,
    mainAxisAlignment: mainAxisAlignment,
    mainAxisSize: mainAxisSize,
    crossAxisAlignment: crossAxisAlignment,
    textDirection: textDirection,
    verticalDirection: verticalDirection,
    textBaseline: textBaseline,
  );

这就是为什么您看不到那么多自定义标准小部件的软件包。

如果您在您的应用程序中使用自定义小部件并且不将其导出为库,您可能不需要这些参数的 80%。所以在实践中,我们创建的小部件只接受我们需要的参数。

说到给RadioListTile一个有限的宽度。为什么它是无限的并且不接受宽度是有目的的。在一个好的设计中,应该只有一种设置宽度的方法。可以考虑自动确定容器的宽度或显式传递它。出于多种原因,Flutter 选择了前者。一些好处包括调整大小时自动布局、避免 属性 钻取以及减少对自定义小部件的需求。所以我建议你让收音机的容器决定宽度。这样你就可以摆脱整个 class MyRadioListTile.

至于TextBodyMedium,我建议你先这样缩短:

Text('Tabelle', style: Theme.of(context).textTheme.bodyMedium);

下一步,如果您需要在一个页面上使用很多这样的元素,您可以使用 DefaultTextStyle 小部件将样式应用于树中它下面的所有小部件。

我认为 Alexey Inkin 的答案是正确的,但如果您想要一种方法为一个参数(在本例中为固定宽度的文本)提供一些标准值,同时仍然可以访问许多其他属性,您可以尝试类似下面代码的模式。它在使用上比简单的组合(或继承)稍微冗长,但您保留对所有 RadioListTile 参数的访问权。

class MyTextBuilder extends StatelessWidget {
  const MyTextBuilder({
    required this.text,
    required this.builder,
    Key? key,
  }) : super(key: key);

  final String text;
  final RadioListTile Function(BuildContext context, Widget child) builder;

  @override
  Widget build(BuildContext context) => builder(
        context,
        SizedBox(width: 100, child: Text(text)),
      );
}

// Usage:

final example = MyTextBuilder(
  text: "Hello",
  builder: (context, value) => RadioListTile(
    value: value,
    // any of the other plethora of parameters 
  ),
);