water_drop_progress 1.0.0
water_drop_progress: ^1.0.0 copied to clipboard
A customizable animated water-drop progress indicator with smooth liquid waves and animated fill levels.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:water_drop_progress/water_drop_progress.dart';
void main() {
runApp(const WaterDropExampleApp());
}
class WaterDropExampleApp extends StatelessWidget {
const WaterDropExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Water Drop Progress',
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF2F7BFF),
),
scaffoldBackgroundColor: const Color(0xFFF6F8FC),
),
home: const WaterDropDemoScreen(),
);
}
}
class WaterDropDemoScreen extends StatefulWidget {
const WaterDropDemoScreen({super.key});
@override
State<WaterDropDemoScreen> createState() {
return _WaterDropDemoScreenState();
}
}
class _WaterDropDemoScreenState
extends State<WaterDropDemoScreen> {
static const int _dailyGoal = 2500;
double _progress = 0.65;
bool _animateWave = true;
bool _showPercentage = true;
int get _consumedWater {
return (_progress * _dailyGoal).round();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Water Drop Progress'),
centerTitle: true,
),
body: SafeArea(
child: ListView(
padding: const EdgeInsets.all(24),
children: <Widget>[
const Text(
'Daily Hydration',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w800,
),
),
const SizedBox(height: 8),
Text(
'Move the slider to update the water level.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Colors.black.withOpacity(0.60),
),
),
const SizedBox(height: 30),
Center(
child: WaterDropProgress(
value: _progress,
width: 190,
height: 220,
animateWave: _animateWave,
showPercentage: _showPercentage,
semanticLabel: 'Daily hydration progress',
),
),
const SizedBox(height: 24),
Text(
'$_consumedWater mL',
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.w800,
),
),
const SizedBox(height: 4),
Text(
'Daily goal: $_dailyGoal mL',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Colors.black.withOpacity(0.60),
),
),
const SizedBox(height: 24),
Slider(
value: _progress,
min: 0,
max: 1,
divisions: 100,
label: '${(_progress * 100).round()}%',
onChanged: (double value) {
setState(() {
_progress = value;
});
},
),
const SizedBox(height: 8),
_SettingTile(
title: 'Animate waves',
value: _animateWave,
onChanged: (bool value) {
setState(() {
_animateWave = value;
});
},
),
_SettingTile(
title: 'Show percentage',
value: _showPercentage,
onChanged: (bool value) {
setState(() {
_showPercentage = value;
});
},
),
const SizedBox(height: 24),
const Text(
'Quick values',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 12),
Wrap(
alignment: WrapAlignment.center,
spacing: 12,
runSpacing: 12,
children: <Widget>[
OutlinedButton(
onPressed: () {
setState(() {
_progress = 0;
});
},
child: const Text('Empty'),
),
OutlinedButton(
onPressed: () {
setState(() {
_progress = 0.25;
});
},
child: const Text('25%'),
),
OutlinedButton(
onPressed: () {
setState(() {
_progress = 0.50;
});
},
child: const Text('50%'),
),
OutlinedButton(
onPressed: () {
setState(() {
_progress = 0.75;
});
},
child: const Text('75%'),
),
FilledButton(
onPressed: () {
setState(() {
_progress = 1;
});
},
child: const Text('Full'),
),
],
),
const SizedBox(height: 36),
const Text(
'Custom Content',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w800,
),
),
const SizedBox(height: 16),
Center(
child: WaterDropProgress(
value: _progress,
width: 160,
height: 185,
showPercentage: false,
animateWave: _animateWave,
waterGradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: <Color>[
Color(0xFF74EBD5),
Color(0xFF35B7C9),
Color(0xFF147D92),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Icon(
Icons.water_drop_outlined,
color: Colors.white,
size: 28,
),
const SizedBox(height: 6),
Text(
'$_consumedWater mL',
style: const TextStyle(
color: Colors.white,
fontSize: 17,
fontWeight: FontWeight.w800,
),
),
],
),
),
),
const SizedBox(height: 40),
],
),
),
);
}
}
class _SettingTile extends StatelessWidget {
const _SettingTile({
required this.title,
required this.value,
required this.onChanged,
});
final String title;
final bool value;
final ValueChanged<bool> onChanged;
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: Text(
title,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
),
),
),
Switch(
value: value,
onChanged: onChanged,
),
],
);
}
}