|
|
@@ -1,5 +1,7 @@
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
+import 'bubble/bubble_widget.dart';
|
|
|
+
|
|
|
/// 支持动画过渡和渐变色的进度条
|
|
|
// 使用示例
|
|
|
// AnimatedGradientProgressBar(
|
|
|
@@ -94,59 +96,80 @@ class AnimatedGradientProgressBarState
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
- return Stack(
|
|
|
- // 允许子组件溢出自己本身的大小,默认是裁切的
|
|
|
- clipBehavior: Clip.none,
|
|
|
- children: [
|
|
|
- // 百分比文本
|
|
|
- Positioned(
|
|
|
- right: 0,
|
|
|
- // 文字位于进度条上方
|
|
|
- bottom: widget.height + 4,
|
|
|
- child: AnimatedBuilder(
|
|
|
- animation: _animation,
|
|
|
- builder: (context, _) {
|
|
|
- return Text(
|
|
|
- '${(_animation.value * 100).toStringAsFixed(0)}%',
|
|
|
- style: const TextStyle(fontSize: 12, color: Colors.black54),
|
|
|
- );
|
|
|
- },
|
|
|
- ),
|
|
|
- ),
|
|
|
- // 进度条
|
|
|
- ClipRRect(
|
|
|
- borderRadius: BorderRadius.circular(widget.borderRadius),
|
|
|
- child: Container(
|
|
|
- width: double.infinity,
|
|
|
- height: widget.height,
|
|
|
- decoration: BoxDecoration(
|
|
|
- color: Colors.grey[200],
|
|
|
- borderRadius: BorderRadius.circular(widget.borderRadius),
|
|
|
+ return LayoutBuilder(
|
|
|
+ builder: (context, constraints) {
|
|
|
+ // 进度条的实际宽度
|
|
|
+ final progressBarWidth = constraints.maxWidth;
|
|
|
+ return Stack(
|
|
|
+ // 允许子组件溢出自己本身的大小,默认是裁切的
|
|
|
+ clipBehavior: Clip.none,
|
|
|
+ children: [
|
|
|
+ // 百分比文本
|
|
|
+ Positioned(
|
|
|
+ // 左侧偏移量,跟随当前进度的末尾,公式:当前比例值 * 进度条的宽度 - 气泡宽度
|
|
|
+ left: widget.targetValue * progressBarWidth - (widget.targetValue > 0.5 ? 32 : 24),
|
|
|
+ // 进度气泡,位于进度条上方
|
|
|
+ bottom: widget.height + 0.85,
|
|
|
+ child: AnimatedBuilder(
|
|
|
+ animation: _animation,
|
|
|
+ builder: (context, _) {
|
|
|
+ return BubbleWidget(
|
|
|
+ // 箭头方向
|
|
|
+ arrowDirection: AxisDirection.down,
|
|
|
+ arrowOffset: 22,
|
|
|
+ arrowLength: 8,
|
|
|
+ arrowRadius: 2,
|
|
|
+ arrowWidth: 5,
|
|
|
+ padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 7),
|
|
|
+ borderRadius: BorderRadius.circular(9),
|
|
|
+ // 气泡的背景颜色,取渐变色的第2个颜色
|
|
|
+ backgroundColor: widget.gradient.colors.last,
|
|
|
+ contentBuilder: (context) {
|
|
|
+ return Text(
|
|
|
+ '${(_animation.value * 100).toStringAsFixed(0)}%',
|
|
|
+ style: const TextStyle(fontSize: 10, color: Colors.white),
|
|
|
+ );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ },
|
|
|
+ ),
|
|
|
),
|
|
|
- child: Stack(
|
|
|
- children: [
|
|
|
- AnimatedBuilder(
|
|
|
- animation: _animation,
|
|
|
- builder: (context, _) {
|
|
|
- return FractionallySizedBox(
|
|
|
- widthFactor: _animation.value,
|
|
|
- alignment: Alignment.centerLeft,
|
|
|
- child: Container(
|
|
|
- decoration: BoxDecoration(
|
|
|
- gradient: widget.gradient,
|
|
|
- borderRadius: BorderRadius.circular(
|
|
|
- widget.borderRadius,
|
|
|
+ // 进度条
|
|
|
+ ClipRRect(
|
|
|
+ borderRadius: BorderRadius.circular(widget.borderRadius),
|
|
|
+ child: Container(
|
|
|
+ width: double.infinity,
|
|
|
+ height: widget.height,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: Colors.grey[200],
|
|
|
+ borderRadius: BorderRadius.circular(widget.borderRadius),
|
|
|
+ ),
|
|
|
+ child: Stack(
|
|
|
+ children: [
|
|
|
+ AnimatedBuilder(
|
|
|
+ animation: _animation,
|
|
|
+ builder: (context, _) {
|
|
|
+ return FractionallySizedBox(
|
|
|
+ widthFactor: _animation.value,
|
|
|
+ alignment: Alignment.centerLeft,
|
|
|
+ child: Container(
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ gradient: widget.gradient,
|
|
|
+ borderRadius: BorderRadius.circular(
|
|
|
+ widget.borderRadius,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
),
|
|
|
- ),
|
|
|
- ),
|
|
|
- );
|
|
|
- },
|
|
|
+ );
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ],
|
|
|
),
|
|
|
- ],
|
|
|
+ ),
|
|
|
),
|
|
|
- ),
|
|
|
- ),
|
|
|
- ],
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }
|
|
|
);
|
|
|
}
|
|
|
}
|