segmented_ring_painter 1.1.0
segmented_ring_painter: ^1.1.0 copied to clipboard
High-performance segmented circular progress and concentric activity ring widget for Flutter with gradient arcs, rounded caps, gap math, and tap hit-testing.
segmented_ring_painter #
A high-performance, GPU-accelerated Flutter package for rendering segmented progress rings and Apple Fitness-style concentric activity rings with gradient arcs, angular gaps, rounded caps, smooth physics animations, and tap hit-testing.
β¨ Features #
- π Concentric Activity Rings (
NestedActivityRings): Apple Fitness-style nested rings with authentic overlap drop-shadows on overachievement (>100% goal). - π° Proportional & Segmented Rings (
SegmentedRingChart): Dynamic multi-segment progress circles with precise angular gap spacing (perfect for Macro/Nutrition breakdowns, Budget allocation, or Multi-phase workflows). - π¨ Rich Styling: Solid colors, sweep gradients, outer glow filters, and customizable end caps (
RingCapStyle.round,butt,square). - π Built-in Touch Hit-Testing: Tap any individual segment or concentric ring to trigger tooltips, detail sheets, and selection states.
- β‘ Buttery Smooth: Hardware-accelerated
CustomPainterwith strictshouldRepaintdirty checks to ensure steady 60/120 FPS. - π All 6 Platforms Supported: 100% pure Dart & Flutter with zero native C/C++ dependencies. Works out-of-the-box on Android, iOS, Web, macOS, Windows, and Linux.
π¦ Installation #
Add segmented_ring_painter to your pubspec.yaml:
dependencies:
segmented_ring_painter: ^1.0.0
Or run:
flutter pub add segmented_ring_painter
π Quick Start #
1. Concentric Activity Rings (Apple Fitness Style) #
import 'package:flutter/material.dart';
import 'package:segmented_ring_painter/segmented_ring_painter.dart';
Widget buildActivityRings() {
return NestedActivityRings(
width: 220,
height: 220,
rings: [
NestedRing(
value: 520,
maxValue: 500, // 104% -> Overachieved!
color: const Color(0xFFFA114F),
label: 'Move',
),
NestedRing(
value: 38,
maxValue: 30,
color: const Color(0xFFAAF724),
label: 'Exercise',
),
NestedRing(
value: 9,
maxValue: 12,
color: const Color(0xFF00F5D4),
label: 'Stand',
),
],
style: const NestedRingsStyle(
strokeWidth: 20.0,
ringSpacing: 4.0,
enableOverachievementShadow: true,
),
center: const Icon(Icons.local_fire_department, color: Color(0xFFFA114F), size: 32),
onRingTap: (index, ring) {
print('Tapped ${ring.label}: ${ring.value}/${ring.maxValue}');
},
);
}
2. Segmented Proportional Ring (Nutrition / Budget) #
import 'package:flutter/material.dart';
import 'package:segmented_ring_painter/segmented_ring_painter.dart';
Widget buildMacroBreakdown() {
return SegmentedRingChart(
width: 220,
height: 220,
segments: [
RingSegment(
value: 180 * 4, // Carbs kcal
color: const Color(0xFF38BDF8),
label: 'Carbs',
shadowColor: const Color(0xFF38BDF8),
shadowBlur: 6.0,
),
RingSegment(
value: 140 * 4, // Protein kcal
color: const Color(0xFF34D399),
label: 'Protein',
shadowColor: const Color(0xFF34D399),
shadowBlur: 6.0,
),
RingSegment(
value: 65 * 9, // Fat kcal
color: const Color(0xFFFBBF24),
label: 'Fats',
shadowColor: const Color(0xFFFBBF24),
shadowBlur: 6.0,
),
],
style: const SegmentedRingStyle(
strokeWidth: 22.0,
gapAngle: 5.0, // 5Β° angular gap between segments
capStyle: RingCapStyle.round,
),
center: const Text(
'1,865\nkcal',
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
onSegmentTap: (index, segment) {
print('Selected segment: ${segment.label} (${segment.value} kcal)');
},
);
}
π οΈ API Reference #
NestedActivityRings Properties #
| Property | Type | Default | Description |
|---|---|---|---|
rings |
List<NestedRing> |
Required | Concentric ring configurations from outer to inner. |
style |
NestedRingsStyle |
NestedRingsStyle() |
Stroke thickness, spacing, shadows, and cap styling. |
center |
Widget? |
null |
Optional widget anchored at the center of the innermost ring. |
animationDuration |
Duration |
Duration(milliseconds: 1000) |
Duration for entrance & value change animations. |
animationCurve |
Curve |
Curves.easeOutCubic |
Interpolation curve for smooth physics. |
onRingTap |
Function(int, NestedRing)? |
null |
Callback returning the tapped ring index and data. |
SegmentedRingChart Properties #
| Property | Type | Default | Description |
|---|---|---|---|
segments |
List<RingSegment> |
Required | The data segments to partition across the ring. |
style |
SegmentedRingStyle |
SegmentedRingStyle() |
Stroke width, angular gap, background track, glow. |
mode |
SegmentedRingMode |
SegmentedRingMode.proportional |
proportional (auto-sums to 100%) or absolute. |
totalValue |
double? |
null |
Target total capacity for SegmentedRingMode.absolute. |
center |
Widget? |
null |
Optional center widget. |
onSegmentTap |
Function(int, RingSegment)? |
null |
Callback returning the tapped segment index and data. |
π¨π» Author & Maintainer #
Developed and maintained by Govind Tank.
Contributions, bug reports, and feature suggestions are always welcome on GitHub!
π License #
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.