我一直在读《this post》这样的书,它解释了Ffltter在很大程度上更喜欢构图,而不是继承.虽然我部分理解其中的原因,但我质疑在这种做法变得冗长的情况下该怎么做.此外,在Ffltter的内部代码中,到处都是内置组件的继承.因此,从哲学上讲,在可以的情况下,肯定会有一些场景.
考虑这个例子(基于我做的一个真实的Widget
):
class MyFadingAnimation extends StatefulWidget {
final bool activated;
final Duration duration;
final Curve curve;
final Offset transformOffsetStart;
final Offset transformOffsetEnd;
final void Function()? onEnd;
final Widget? child;
const MyFadingAnimation({
super.key,
required this.activated,
this.duration = const Duration(milliseconds: 500),
this.curve = Curves.easeOut,
required this.transformOffsetStart,
this.transformOffsetEnd = const Offset(0, 0),
this.onEnd,
this.child,
});
@override
State<MyFadingAnimation> createState() => _MyFadingAnimationBuilder();
}
class _MyFadingAnimationBuilder extends State<MyFadingAnimation> {
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: widget.duration,
curve: widget.curve,
transform: Transform.translate(
offset: widget.activated ?
widget.transformOffsetStart : widget.transformOffsetEnd,
).transform,
onEnd: widget.onEnd,
child: AnimatedOpacity(
duration: widget.duration,
curve: widget.curve,
opacity: widget.activated ? 1 : 0,
child: widget.child
),
);
}
}
MyFadingAnimation
的目标是在Widget
上同时执行平移和不透明动画.太棒了!
现在,假设我想为这个小部件创建一些"快捷方式"或"别名",比如MyHorizontalAnimation
用于水平淡入,或者MyVerticalAnimation
用于垂直淡入.使用合成时,您必须创建如下内容:
class MyHorizontalAnimation extends StatelessWidget {
final bool activated;
final Duration duration;
final Curve curve;
final double offsetStart;
final void Function()? onEnd;
final Widget? child;
const MyHorizontalAnimation({
super.key,
required this.activated,
this.duration = const Duration(milliseconds: 500),
this.curve = Curves.easeOut,
required this.offsetStart,
this.onEnd,
this.child,
});
@override
Widget build(BuildContext context) {
return MyFadingAnimation(
activated: activated,
duration: duration,
curve: curve,
transformOffsetStart: Offset(offsetStart, 0),
onEnd: onEnd,
child: child,
);
}
}
那看起来...对我来说很冗长.所以我最初的 idea 是"嗯,也许我应该试着扩展一下这个课程……"
class MyHorizontalAnimation extends MyFadingAnimation {
final double offsetStart;
MyHorizontalAnimation({
super.key,
required super.activated,
super.duration,
super.curve,
this.offsetStart,
super.onEnd,
super.child,
}) : super(
transformOffsetStart: Offset(offsetStart, 0),
);
}
对我来说,这看起来更干净.此外,它还带来了额外的好处,即如果我将功能/props 添加到MyFadingAnimation
,它就会自动集成到MyHorizontalAnimation
中(除了必须添加super.newProp
之外).使用组合方法,我必须添加一个新属性,可能是复制/维护默认属性,然后将其添加到构造函数中,当我完成时,感觉就像是一件家务.
我使用继承的主要问题(这可能真的很小)是,除了我的基本小部件MyFadingAnimation
之外,我不能为任何东西使用const
构造函数.这一点,再加上strong对继承的阻碍,让我觉得有更好的方法.
所以,总而言之,我有两个问题:
- 我应该如何组织上面的代码,使其具有
const
个重定向到其他"基本"Widget
的Widget
? - 什么时候可以使用继承而不是组合?这方面有什么好的经验法则吗?