效果图
分析
1、这是一个自定义的进度条,我们可以看到它分为3部分:背景、进度、角标。
2、由于这3个部分是 重叠 的关系,所以我们要选择 Stack 组件来实现。
3、背景实现:背景实现比较简单,我们利用 Positioned 来定位,里面包裹 Container 来实现背景。
4、进度实现:进度实现稍微复杂点,也是需要借鉴 Positioned 的 width 属性来设置进度的宽度
(1)容器的宽度获取需要借助 LayoutBuilder 来获取。
(2)进度这个图片截取借助 ClipRRect 来实现。
(3)进度的图片就用 Image 实现。
5、角标实现:利用 Positioned 来实现
如何实现
import 'package:flutter/material.dart';
class CustomImageProgress extends StatelessWidget {
final double progress; //进度
const CustomImageProgress({super.key, required this.progress});
@override
Widget build(BuildContext context) {
// 进度条总宽度(减去左右边距)
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
// 获取进度的宽度
double containerWidth = constraints.maxWidth;
final progressWidth = containerWidth * progress;
// 构建进度条
return SizedBox(
height: 20,
width: double.infinity,
child: Stack(
children: [
// 底部背景
_bottomBgWidget(),
// 进度组件
_progressWidget(progressWidth),
// 三角形组件
_sanJiaoWidget(progressWidth),
],
),
);
},
);
}
// 构建背景
Positioned _bottomBgWidget() {
return Positioned(
left: 0,
right: 0,
bottom: 0,
height: 16,
child: Container(
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(20),
),
),
);
}
// 构建进度组件
Positioned _progressWidget(double progressWidth) {
return Positioned(
bottom: 0,
left: 0,
width: progressWidth,
// 加上裁剪,圆角
child: ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
topLeft: Radius.circular(20),
bottomRight: Radius.circular(0),
),
child: Image.asset(
"assets/images/lsjdt.png",
fit: BoxFit.cover,
height: 16,
),
),
);
}
Positioned _sanJiaoWidget(double progressWidth) {
return Positioned(
bottom: 3,
left: progressWidth - 8.5,
child: Image.asset(
'assets/images/icon.png',
color: Colors.white,
width: 18,
height: 18,
),
);
}
}