举个栗子,封装一个 Text Widget 。
方式一
优点:
不用担心为了自定义某个预设样式,而导致所有预设样式丢失。
缺点:
这里只是暴露了 Text 控件的几个属性,实际开发中一个 Widget 可能需要暴露很多属性,后面扩展下来,属性列表可能会拉的很长。在这里极限情况就要暴露 Text 控件的所有属性给外界。
class TextWidget extends StatelessWidget {
final String text;
final Color? color;
final double? fontSize;
final FontWeight? fontWeight;
const TextWidget({
Key? key,
required this.text,
this.color = Colors.black,
this.fontSize = 16,
this.fontWeight = FontWeight.normal,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(
text,
style: TextStyle(
color: color,
fontSize: fontSize,
fontWeight: fontWeight,
),
);
}
}
方式二
优点:
不用暴露太多属性,直接暴露一个 textStyle 属性,需要用到 text 的什么属性,使用者自己传入 textStyle 即可。
缺点:
一旦 Widget 使用者,需要传入 textStyle 自定义部分样式,会丢失预设的 textStyle 所有默认样式,所有样式都需要重新传,对于只改其中单个或少数几个样式来说,很不方便。
这里预设了颜色、字号、字重这三个样式属性,使用者如果仅仅需要修改颜色,那在将自定义 color 传入 textStyle 的同时,还要传入字号、字重这俩属性默认的值。
这里预设样式比较少还好。如果预设样式列表特别长,有十几个甚至更多属性,为了自定义其中一个属性的样式,需要重新传所有样式,就很难受很不友好。
class TextWidget extends StatelessWidget {
final String text;
final TextStyle textStyle;
const TextWidget({
Key? key,
required this.text,
this.textStyle = const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.normal,
),
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(text, style: textStyle);
}
}
1
Trello OP Flutter 中有没有哪种方式,能兼容上述两种方式的优点?诸如像 RN 中封装组件那样,就很优雅简洁。
方便扩展,不用传入多个样式属性,一个 style 即可。 同时也不用担心预设样式丢失,直接使用扩展运算符增量覆盖即可。 以下是 RN 写法。 interface Props { text: String, textStyle?: TextStyle, } class TextComponent extends React.Component<Props> { render() { const { text, textStyle } = this.props; return ( <Text style={{ color: '#000', fontSize: 16, fontWeight: 'normal', ...textStyle }} > {text} </Text> ) } } |
2
shetz163 2022-06-11 20:08:26 +08:00
TextStyle 里面有一个方法 merge, 可以合并另外一个 TextStyle
其实可以写一个默认的 TextStyle, 然后传入想要部分修改的 TextStyle, 合并使用就好 |
3
Trello OP 友友们请不吝赐教哈
|
4
Trello OP @shetz163 谢谢,原来还要这么个方法,那文本样式方面的不用愁了。请问 EdgeInsets 之类的有类似的合并方法吗?比如我预设了边距,后面再传一个 EdgeInsets ,以后来的为准。
|
5
shetz163 2022-06-11 20:37:30 +08:00
edgeinsets 好像没有这样的合并方式, 可以用 ?? 来做默认的, 但如果要合并的话, 可能得自己去做一下处理, 比如判断一下 上下左右是否大于 0 来确认是否继承
|
6
Trello OP @shetz163 好的吧,谢谢。我在寻求 Flutter 内一种通用的 Widget 传参属性扩展方式。
在 React 内给组件传 Props 属性,如果要扩展的话,也是直接扩展运算符就可以扩充了。 诸如有这么个 A 组件,有两个确定要传的 a 、b 属性,同时使用{...props}保留了扩展性。 <Component a={xxx} b={xxx} {...props}> 不知道 Flutter 中各式各样的 widget 传属性时,如果要动态扩充,有没有什么通用的办法。 |
8
Trello OP @shetz163 我看 Stack Overflow 上的回复,好像没有这种方式,就很无奈。需要哪个属性就得写哪个属性,一点都不灵活。
https://stackoverflow.com/questions/56934960/flutter-inherit-all-props-from-parent-widget |
9
shetz163 2022-06-11 20:52:33 +08:00
现有的看起来就只有自己去做继承, 也可以用 dart extension 来自己做一个继承的方法, 最新的 flutter 3 上对于 extension 支持更好了, 好像是可以不用提前导入 extension 的文件就可以直接联想出来方法, 并且自动导入
|
10
Trello OP @shetz163 哇,那岂不是得用一个 widget 就得写一个继承类来实现合并,这也太累了呀。而且写的这个继承类还不能通用,因为不同场景下预设值不一样,比如 EdgeInsets 我写了个继承类,里面属性赋上某个场景下预设的默认边距,别的场景这个 EdgeInsets 的边距默认值又变了,那还得重写一个关于 EdgeInsets 的继承类,或者在原来写的继承类里加判断或其他命名构造函数做场景区分(这些常用的 widget 场景太多,一个继承类根本维护不下去的)。吐了呀,要崩溃。。。太反人类吧。
|
11
shetz163 2022-06-12 01:15:00 +08:00
我的意思是说做个继承的方法 比如扩展一个 edgeinsets.merge(edgeinsets other)这样的方法然后 other 里有非 0 的值就填进去 没有就用默认的
|