Flutter 实现炫酷进度条

1 阅读1分钟

效果图

分析

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,
      ),
    );
  }
}