MENU

【Flutter】CircularProgressIndicatorでは角を丸くできないので、CustomPaintを使って円形のプログレスインディケーターを作成する

記事内に商品プロモーションが含まれる場合があります

CircularProgressIndicatorを使う場合、下の画像のように青い部分の角が丸くならない。

今のところ、角を丸くする方法はなさそうなので、CustomPaintを使ってカスタムウィジェットを作成します。

目次

CustomPaintを使った角丸のプログレスインジケータ

import 'package:flutter/material.dart';
import 'dart:math' as math;

// カスタムプログレスバー
class RoundedProgressBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300.0,
      height: 300.0,
      child: CustomPaint(
        painter: RoundedProgressPainter(
          valueColor: Colors.blue,
          backgroundColor: Colors.grey[300]!,
          strokeWidth: 30.0,
          value: 0.7,
        ),
      ),
    );
  }
}

// カスタムペインター
class RoundedProgressPainter extends CustomPainter {
  final Color valueColor;        // 進捗の色
  final Color backgroundColor;  // 背景色
  final double strokeWidth;      // ストローク幅
  final double value;            // 進捗値 (0.0 - 1.0)

  // コンストラクタ
  RoundedProgressPainter({
    required this.valueColor,
    required this.backgroundColor,
    required this.strokeWidth,
    required this.value,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = backgroundColor
      ..strokeWidth = strokeWidth
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke;

    final center = Offset(size.width / 2, size.height / 2);
    final radius = math.min(size.width, size.height) / 2 - strokeWidth / 2;

    // 背景の円を描画
    canvas.drawCircle(center, radius, paint);

    // 進捗のアークを描画
    paint.color = valueColor;
    final progressStartAngle = -math.pi / 2;
    final progressEndAngle = progressStartAngle + (math.pi * 2 * value);

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      progressStartAngle,
      progressEndAngle - progressStartAngle,
      false,
      paint,
    );
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

結果

Center(
    child: RoundedProgressBar(),
)

いい感じに角丸になりました。

プログレスインジケータの中心にテキストを入れる

import 'package:flutter/material.dart';
import 'dart:math' as math;

class RoundedProgressBarWithText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300.0,
      height: 300.0,
      child: CustomPaint(
        painter: RoundedProgressPainterWithText(
          valueColor: Colors.blue,
          backgroundColor: Colors.grey[300]!,
          strokeWidth: 30.0,
          value: 0.7,
          text: '70', // 表示するテキスト
          textStyle: TextStyle(
            color: Colors.grey.shade800,
            fontSize: 76.0,
            fontWeight: FontWeight.bold
          ),
        ),
      ),
    );
  }
}

// テキストが付いたカスタムペインター
class RoundedProgressPainterWithText extends CustomPainter {
  final Color valueColor;       // 進捗の色
  final Color backgroundColor; // 背景色
  final double strokeWidth;     // ストローク幅
  final double value;           // 進捗値 (0.0 - 1.0)
  final String text;            // 表示するテキスト
  final TextStyle textStyle;    // テキストのスタイル

  // コンストラクタ
  RoundedProgressPainterWithText({
    required this.valueColor,
    required this.backgroundColor,
    required this.strokeWidth,
    required this.value,
    required this.text,
    required this.textStyle,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = backgroundColor
      ..strokeWidth = strokeWidth
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke;

    final center = Offset(size.width / 2, size.height / 2);
    final radius = math.min(size.width, size.height) / 2 - strokeWidth / 2;

    // 背景の円を描画
    canvas.drawCircle(center, radius, paint);

    // 進捗のアークを描画
    paint.color = valueColor;
    final progressStartAngle = -math.pi / 2;
    final progressEndAngle = progressStartAngle + (math.pi * 2 * value);

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      progressStartAngle,
      progressEndAngle - progressStartAngle,
      false,
      paint,
    );

    // テキストを描画
    final textPainter = TextPainter(
      text: TextSpan(
        text: text,
        style: textStyle,
      ),
      textDirection: TextDirection.ltr,
    );

    textPainter.layout();
    final textX = center.dx - textPainter.width / 2;
    final textY = center.dy - textPainter.height / 2;

    textPainter.paint(canvas, Offset(textX, textY));
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

結果

Center(
    child: RoundedProgressBarWithText(),
)

プログレスインディケーターの中心にテキストを表示できました。

Flutterが学べる書籍

Share

Comment

コメントする

目次