
在Flutter中,通过组合基础Widget实现自定义控件是常见做法。将多个基础Widget按布局规则组装成高级控件,能显著提升代码复用性。
定义数据结构存储控件所需信息:
class UpdateItemModel {
String appIcon;
String appName;
String appSize;
String appDate;
String appDescription;
String appVersion;
UpdateItemModel({
this.appIcon,
this.appName,
this.appSize,
this.appDate,
this.appDescription,
this.appVersion
});
}将UI分为上下两部分:
上半部分使用Row布局:
Widget buildTopRow() {
return Row(
children: [
Padding(
padding: EdgeInsets.all(10),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.asset(model.appIcon, width: 80, height: 80)
)
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(model.appName, maxLines: 1),
Text(model.appDate, maxLines: 1)
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 10, 0),
child: FlatButton(
child: Text("OPEN"),
onPressed: onPressed,
)
)
]
);
}下半部分使用Column布局:
Widget buildBottomRow() {
return Padding(
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(model.appDescription),
Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Text("${model.appVersion} • ${model.appSize} MB")
)
]
)
);
}将上下部分组合成完整控件:
class UpdatedItem extends StatelessWidget {
final UpdateItemModel model;
final VoidCallback onPressed;
UpdatedItem({Key key, this.model, this.onPressed}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
buildTopRow(),
buildBottomRow()
]
);
}
}当需要实现特殊绘制效果时,可通过CustomPainter进行自定义绘制:
class CustomCirclePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
canvas.drawCircle(
Offset(size.width/2, size.height/2),
size.width/2,
paint
);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
class CustomCircle extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CustomPaint(
size: Size(100, 100),
painter: CustomCirclePainter(),
);
}
}使用SizedBox控制控件尺寸:
SizedBox(
width: 100,
height: 100,
child: CustomCircle()
)使用AspectRatio保持宽高比:
AspectRatio(
aspectRatio: 1,
child: Container(color: Colors.red)
)避免在build方法中创建大量对象 使用const构造函数优化性能 考虑使用RepaintBoundary隔离重绘区域