Flutter自定义矩形进度条实现详解

在Flutter应用开发中,进度条是一个常见的UI组件,用于展示任务的完成进度。本文将详细介绍如何实现一个支持动画效果的自定义矩形进度条。

功能特点

  • 支持圆角矩形外观
  • 平滑的动画过渡效果
  • 可自定义渐变色
  • 可配置边框宽度和颜色
  • 支持进度更新动画

实现原理

该进度条的实现主要基于Flutter的CustomPaint和CustomPainter,通过绘制路径来实现圆角矩形的进度效果。

1. 基础组件结构

首先,我们创建一个StatefulWidget来管理进度条的状态:

dart:lib/rectangle_progress_bar.dart 复制代码
class RectangleProgressBar extends StatefulWidget {
  final double progress;
  final Size size;
  final double borderRadius;
  final Duration duration;

  const RectangleProgressBar({
    super.key,
    required this.progress,
    this.size = const Size(200, 200),
    this.borderRadius = 20,
    this.duration = const Duration(milliseconds: 1000),
  });
  
  // ...
}

2. 动画控制

在State类中,我们使用AnimationController来控制进度条的动画效果:

dart:lib/rectangle_progress_bar.dart 复制代码
class _RectangleProgressBarState extends State<RectangleProgressBar>
    with SingleTickerProviderStateMixin {
  // ... 初始化代码 ...

  @override
  void didUpdateWidget(RectangleProgressBar oldWidget) {
    if (oldWidget.progress != widget.progress) {
      _previousProgress = _animation.value;
      _animation = Tween<double>(
        begin: _previousProgress,
        end: widget.progress,
      ).animate(CurvedAnimation(
        parent: _controller,
        curve: Curves.easeInOutCubic,
      ));
      _controller.reset();
      _controller.forward();
    }
  }
}

3. 自定义绘制器

核心的绘制逻辑在RectangleProgressPainter类中实现:

dart:lib/rectangle_progress_bar.dart 复制代码
class RectangleProgressPainter extends CustomPainter {
  // ... 属性定义 ...

  @override
  void paint(Canvas canvas, Size size) {
    final rect = Rect.fromLTWH(0, 0, size.width, size.height);
    final path = _createRoundedRectanglePath(size);
    _drawBackground(canvas, path);
    _drawProgress(canvas, path, rect);
  }
}

4. 路径创建

进度条的路径创建是一个重要部分,需要精确控制每个圆角的绘制:

dart:lib/rectangle_progress_bar.dart 复制代码
Path _createRoundedRectanglePath(Size size) {
  final path = Path();
  // 从顶部中点开始绘制
  path.moveTo(size.width / 2, 0);
  // 绘制右上角
  path.lineTo(size.width - borderRadius, 0);
  path.arcToPoint(
    Offset(size.width, borderRadius),
    radius: Radius.circular(borderRadius),
  );
  // ... 继续绘制其他边和圆角 ...
  return path;
}

5. 进度绘制

进度条的绘制使用了路径度量和渐变色:

dart:lib/rectangle_progress_bar.dart 复制代码
void _drawProgress(Canvas canvas, Path path, Rect rect) {
  final pathMetric = path.computeMetrics().first;
  final progressLength = pathMetric.length * value;
  final progressPath = Path()
    ..addPath(
      pathMetric.extractPath(0, progressLength),
      Offset.zero,
    );
    
  final progressPaint = Paint()
    ..style = PaintingStyle.stroke
    ..strokeWidth = strokeWidth
    ..strokeCap = StrokeCap.round
    ..strokeJoin = StrokeJoin.miter
    ..isAntiAlias = true
    ..shader = LinearGradient(
      begin: Alignment.centerRight,
      end: Alignment.centerLeft,
      colors: valueColors,
    ).createShader(rect);

  canvas.drawPath(progressPath, progressPaint);
}

使用方法

使用这个自定义进度条非常简单:

dart 复制代码
RectangleProgressBar(
  progress: 0.7, // 70%的进度
  size: Size(300, 300),
  borderRadius: 25,
  duration: Duration(milliseconds: 1500),
)

性能优化

为了确保性能,我们实现了shouldRepaint方法来控制重绘逻辑:

dart:lib/rectangle_progress_bar.dart 复制代码
@override
bool shouldRepaint(RectangleProgressPainter oldDelegate) {
  return oldDelegate.value != value ||
      !listEquals(valueColors, oldDelegate.valueColors) ||
      bgStrokeColor != oldDelegate.bgStrokeColor ||
      strokeWidth != oldDelegate.strokeWidth ||
      progressStrokeWidth != oldDelegate.progressStrokeWidth ||
      borderRadius != oldDelegate.borderRadius;
}

总结

这个自定义矩形进度条实现了以下特点:

  1. 使用CustomPainter实现自定义绘制
  2. 支持平滑的动画效果
  3. 可自定义外观(颜色、大小、圆角等)
  4. 使用路径度量实现精确的进度显示
  5. 支持渐变色效果

通过这个实现,我们不仅创建了一个美观的UI组件,还学习了Flutter中自定义绘制和动画的相关知识。这个组件可以在各种场景下使用,比如文件上传、下载进度显示等。

相关推荐
爱笑鱼2 小时前
Android 系统启动机制(九):system_server 已经运行,为什么还不能说 Android 启动完成?
android
mmsx2 小时前
Android 上的 AI 对话链路:流式响应、SSE 解析与三级降级
android·kotlin
阿俊-全栈开发2 小时前
LikeShop单商户高级版定时任务实现:订单超时关闭与自动确认收货
android·likeshop·likeshop开源商城
倔强的石头1063 小时前
【Transformer】Tokenization详解_BPE_WordPiece_SentencePiece
android·深度学习·transformer
haerapi3 小时前
仓库拣货路线不只靠最短边:S 形启发式的反例记录
android·开发语言·javascript
事圆则缓4 小时前
Flutter 状态管理框架对比(六):同一个购物车,四种方案怎么落地?
前端·javascript·flutter
其实防守也摸鱼13 小时前
Fastjson 反序列化漏洞(JNDI注入)
android·数据库·安全·oracle·自动化·fastjson·反序列化
狗凯之家源码网14 小时前
微博图床 PHP 系统搭建与实战应用指南
android·开发语言·php
消失的旧时光-194315 小时前
(第一篇)JNI 多线程到底难在哪:从 Linux Thread 到 JNIEnv
android·jni·ndk
逗脑IDE18 小时前
零基础学ESP32:蓝牙控制舵机——手机一点,舵机就转!
android·智能手机