Introduction:
Implementing a sleek circular slider in Flutter allows you to create visually appealing sliders for selecting values within a range. The sleek_circular_slider
package provides a customizable circular slider widget that you can integrate into your Flutter app. This tutorial will guide you through implementing a sleek circular slider in Flutter using the sleek_circular_slider
package.
Content:
Step 1: Add the dependency:
Add the sleek_circular_slider
package to your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
sleek_circular_slider: ^2.0.4
Save the file and run flutter pub get
to install the package.
Step 2: Import the package:
Import the sleek_circular_slider
package in your Dart file:
import 'package:flutter/material.dart';
import 'package:sleek_circular_slider/sleek_circular_slider.dart';
Step 3: Create the sleek circular slider:
Create a SleekCircularSlider
widget to display the sleek circular slider. Customize the slider’s appearance, range, initial value, and other properties.
SleekCircularSlider(
min: 0,
max: 100,
initialValue: 50,
appearance: CircularSliderAppearance(
size: 200,
startAngle: 150,
angleRange: 240,
customColors: CustomSliderColors(
trackColor: Colors.grey,
progressBarColors: [Colors.blue, Colors.green, Colors.orange],
shadowColor: Colors.black,
),
customWidths: CustomSliderWidths(
progressBarWidth: 10,
shadowWidth: 20,
),
infoProperties: InfoProperties(
mainLabelStyle: TextStyle(fontSize: 24, color: Colors.blue),
),
),
onChange: (double value) {
// Handle slider value change
},
),
Step 4: Run the app:
Run your Flutter app to see the sleek circular slider in action. You should be able to drag the slider handle to select a value within the specified range.
Sample Code:
import 'dart:async';
import 'package:flutter/material.dart';
// import 'package:example/utils.dart';
import 'dart:math';
import 'dart:math' as math;
import 'package:sleek_circular_slider/sleek_circular_slider.dart';
/// Example 01
final CircularSliderAppearance appearance01 = CircularSliderAppearance();
final viewModel01 = ExampleViewModel(appearance: appearance01, min: 0, max: 100, value: 60, pageColors: [Colors.white, HexColor('#E1C3FF')]);
final example01 = ExamplePage(
viewModel: viewModel01,
);
/// Example 02
final customWidth02 = CustomSliderWidths(trackWidth: 1, progressBarWidth: 2);
final customColors02 = CustomSliderColors(trackColor: Colors.white, progressBarColor: Colors.orange, hideShadow: true);
final info02 = InfoProperties(
topLabelStyle: TextStyle(color: Colors.orangeAccent, fontSize: 30, fontWeight: FontWeight.w600),
topLabelText: 'Budget',
mainLabelStyle: TextStyle(color: Colors.white, fontSize: 50.0, fontWeight: FontWeight.w100),
modifier: (double value) {
final budget = (value * 1000).toInt();
return '\$ $budget';
});
final CircularSliderAppearance appearance02 = CircularSliderAppearance(
customWidths: customWidth02,
customColors: customColors02,
infoProperties: info02,
startAngle: 180,
angleRange: 270,
size: 200.0,
animationEnabled: false);
final viewModel02 = ExampleViewModel(appearance: appearance02, min: 0, max: 10, value: 8, pageColors: [Colors.black, Colors.black87]);
final example02 = ExamplePage(
viewModel: viewModel02,
);
/// Example 03
final customWidth03 = CustomSliderWidths(trackWidth: 22, progressBarWidth: 20, shadowWidth: 50);
final customColors03 = CustomSliderColors(
trackColors: [HexColor('#FFF8CB'), HexColor('#B9FFFF')],
progressBarColors: [HexColor('#FFC84B'), HexColor('#00BFD5')],
shadowColor: HexColor('#5FC7B0'),
dynamicGradient: true,
shadowMaxOpacity: 0.05);
final info03 = InfoProperties(
bottomLabelStyle: TextStyle(color: HexColor('#002D43'), fontSize: 20, fontWeight: FontWeight.w700),
bottomLabelText: 'Goal',
mainLabelStyle: TextStyle(color: Color.fromRGBO(97, 169, 210, 1), fontSize: 30.0, fontWeight: FontWeight.w200),
modifier: (double value) {
final kcal = value.toInt();
return '$kcal kCal';
});
final CircularSliderAppearance appearance03 = CircularSliderAppearance(
customWidths: customWidth03, customColors: customColors03, infoProperties: info03, size: 250.0, startAngle: 180, angleRange: 340);
final viewModel03 =
ExampleViewModel(appearance: appearance03, min: 500, max: 2300, value: 1623, pageColors: [HexColor('#D9FFF7'), HexColor('#FFFFFF')]);
final example03 = ExamplePage(
viewModel: viewModel03,
);
/// Example 04
final customWidth04 = CustomSliderWidths(trackWidth: 4, progressBarWidth: 20, shadowWidth: 40);
final customColors04 = CustomSliderColors(
trackColor: HexColor('#CCFF63'),
progressBarColor: HexColor('#00FF89'),
shadowColor: HexColor('#B0FFDA'),
shadowMaxOpacity: 0.5, //);
shadowStep: 20);
final info04 = InfoProperties(
bottomLabelStyle: TextStyle(color: HexColor('#6DA100'), fontSize: 20, fontWeight: FontWeight.w600),
bottomLabelText: 'Temp.',
mainLabelStyle: TextStyle(color: HexColor('#54826D'), fontSize: 30.0, fontWeight: FontWeight.w600),
modifier: (double value) {
final temp = value.toInt();
return '$temp ˚C';
});
final CircularSliderAppearance appearance04 = CircularSliderAppearance(
customWidths: customWidth04,
customColors: customColors04,
infoProperties: info04,
startAngle: 90,
angleRange: 90,
size: 200.0,
animationEnabled: true);
final viewModel04 = ExampleViewModel(appearance: appearance04, min: 0, max: 40, value: 27, pageColors: [Colors.white, HexColor('#F1F1F1')]);
final example04 = ExamplePage(
viewModel: viewModel04,
);
/// Example 05
final customWidth05 = CustomSliderWidths(trackWidth: 4, progressBarWidth: 45, shadowWidth: 70);
final customColors05 = CustomSliderColors(
dotColor: HexColor('#FFB1B2'),
trackColor: HexColor('#E9585A'),
progressBarColors: [HexColor('#FB9967'), HexColor('#E9585A')],
shadowColor: HexColor('#FFB1B2'),
shadowMaxOpacity: 0.05);
final info05 = InfoProperties(
topLabelStyle: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w400),
topLabelText: 'Elapsed',
bottomLabelStyle: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w400),
bottomLabelText: 'time',
mainLabelStyle: TextStyle(color: Colors.white, fontSize: 50.0, fontWeight: FontWeight.w600),
modifier: (double value) {
final time = printDuration(Duration(seconds: value.toInt()));
return '$time';
});
final CircularSliderAppearance appearance05 = CircularSliderAppearance(
customWidths: customWidth05, customColors: customColors05, infoProperties: info05, startAngle: 270, angleRange: 360, size: 350.0);
final viewModel05 = ExampleViewModel(appearance: appearance05, min: 0, max: 86400, value: 67459, pageColors: [Colors.black, Colors.black87]);
final example05 = ExamplePage(
viewModel: viewModel05,
);
/// Example 06
final customWidth06 = CustomSliderWidths(trackWidth: 4, progressBarWidth: 40, shadowWidth: 70);
final customColors06 = CustomSliderColors(
dotColor: Colors.white.withOpacity(0.1),
trackColor: HexColor('#F9EBE0').withOpacity(0.2),
progressBarColors: [HexColor('#A586EE').withOpacity(0.3), HexColor('#F9D3D2').withOpacity(0.3), HexColor('#BF79C2').withOpacity(0.3)],
shadowColor: HexColor('#7F5ED9'),
shadowMaxOpacity: 0.05);
final CircularSliderAppearance appearance06 =
CircularSliderAppearance(customWidths: customWidth06, customColors: customColors06, startAngle: 180, angleRange: 360, size: 300.0);
final viewModel06 = ExampleViewModel(
innerWidget: (double value) {
return Transform.rotate(
angle: degreeToRadians(value),
child: Align(
alignment: Alignment.center,
child: Container(
width: value / 2.5,
height: value / 2.5,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [HexColor('#F9D3D2').withOpacity(value / 360), HexColor('#BF79C2').withOpacity(value / 360)],
begin: Alignment.bottomLeft,
end: Alignment.topRight,
tileMode: TileMode.clamp),
// borderRadius: BorderRadius.all(
// Radius.circular(value / 6),
// ),
)),
));
},
appearance: appearance06,
min: 0,
max: 360,
value: 45,
pageColors: [HexColor('#4825FF'), HexColor('#FFCAD2')]);
final example06 = ExamplePage(
viewModel: viewModel06,
);
/// Example 07
final customWidth07 = CustomSliderWidths(trackWidth: 2, progressBarWidth: 10, shadowWidth: 20);
final customColors07 = CustomSliderColors(
dotColor: Colors.white.withOpacity(0.1),
trackColor: HexColor('#7EFFFF').withOpacity(0.2),
progressBarColors: [HexColor('#17C5E5'), HexColor('#DFFF97'), HexColor('#04FFB5')],
shadowColor: HexColor('#0CA1BD'),
shadowMaxOpacity: 0.05);
final CircularSliderAppearance appearance07 = CircularSliderAppearance(
customWidths: customWidth07, customColors: customColors07, startAngle: 180, angleRange: 360, size: 130.0, spinnerMode: true);
final viewModel07 = ExampleViewModel(appearance: appearance07, value: 50, pageColors: [HexColor('#FFFFFF'), HexColor('#93EBEB')]);
final example07 = ExamplePage(
viewModel: viewModel07,
);
/// Example 08
final customWidth08 = CustomSliderWidths(trackWidth: 1, progressBarWidth: 15, shadowWidth: 50);
final customColors08 = CustomSliderColors(
dotColor: Colors.white.withOpacity(0.5),
trackColor: HexColor('#7EFFFF').withOpacity(0.1),
progressBarColors: [HexColor('#3586FC').withOpacity(0.1), HexColor('#FF8876').withOpacity(0.25), HexColor('#FAFF76').withOpacity(0.5)],
shadowColor: HexColor('#133657'),
shadowMaxOpacity: 0.02);
final CircularSliderAppearance appearance08 =
CircularSliderAppearance(customWidths: customWidth08, customColors: customColors08, size: 230.0, spinnerMode: true, spinnerDuration: 1000);
final viewModel08 = ExampleViewModel(
appearance: appearance08, value: 50, pageColors: [HexColor('#EA875A'), HexColor('#9EAABB'), HexColor('#3272AE'), HexColor('#041529')]);
final example08 = ExamplePage(
viewModel: viewModel08,
);
/// Example 09
final customWidth09 = CustomSliderWidths(trackWidth: 1, progressBarWidth: 15, shadowWidth: 50);
final customColors09 = CustomSliderColors(
dotColor: Colors.white.withOpacity(0.5),
trackColor: HexColor('#000000').withOpacity(0.1),
progressBarColors: [HexColor('#3586FC').withOpacity(0.1), HexColor('#FF8876').withOpacity(0.25), HexColor('#3586FC').withOpacity(0.5)],
shadowColor: HexColor('#133657'),
shadowMaxOpacity: 0.02);
final CircularSliderAppearance appearance09 = CircularSliderAppearance(
customWidths: customWidth09, customColors: customColors09, startAngle: 55, angleRange: 110, size: 230.0, counterClockwise: true);
final viewModel09 = ExampleViewModel(
appearance: appearance09, value: 50, pageColors: [HexColor('#FFFFFF'), HexColor('#EEEEEE'), HexColor('#FFFFFF'), HexColor('#DDDDDD')]);
final example09 = ExamplePage(
viewModel: viewModel09,
);
/// Example 09
final customWidth10 = CustomSliderWidths(trackWidth: 1, progressBarWidth: 28, shadowWidth: 60);
final customColors10 = CustomSliderColors(
dotColor: Colors.white.withOpacity(0.5),
trackColor: HexColor('#000000').withOpacity(0.1),
progressBarColors: [HexColor('#76E2FF').withOpacity(0.5), HexColor('#4E09ED').withOpacity(0.5), HexColor('#F7E4FF').withOpacity(0.3)],
dynamicGradient: true,
shadowColor: HexColor('#55B3E4'),
shadowMaxOpacity: 0.02);
final info10 = InfoProperties(
bottomLabelStyle: TextStyle(color: HexColor('#5F9DF5'), fontSize: 24, fontWeight: FontWeight.w200),
bottomLabelText: 'Volume',
mainLabelStyle: TextStyle(color: HexColor('#FF6BD9'), fontSize: 60.0, fontWeight: FontWeight.w100),
modifier: (double value) {
final volume = value.toInt();
return '$volume db';
});
final CircularSliderAppearance appearance10 = CircularSliderAppearance(
customWidths: customWidth10,
customColors: customColors10,
startAngle: 180,
angleRange: 240,
infoProperties: info10,
size: 280.0,
counterClockwise: true,
animDurationMultiplier: 3);
final viewModel10 = ExampleViewModel(
appearance: appearance10,
min: -25,
max: 0,
value: -17,
pageColors: [HexColor('#FFFFFF'), HexColor('#D7F2FD'), HexColor('#FFFFFF'), HexColor('#FFFFFF')]);
final example10 = ExamplePage(
viewModel: viewModel10,
);
String printDuration(Duration duration) {
String twoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
class Slick_indicator extends StatefulWidget {
Slick_indicator({Key? key}) : super(key: key);
_Slick_indicatorState createState() => _Slick_indicatorState();
}
class _Slick_indicatorState extends State<Slick_indicator> {
final controller = PageController(initialPage: 0);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
elevation: 2,
title: Text(
"Sleek Circular Slider",
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.blue[200],
),
body: Container(
child: PageView(
controller: controller,
children: <Widget>[
example04,
example01,
example10,
example03,
example02,
example05,
example09,
example08,
example06,
example07,
Clock(),
RandomValuePage(),
],
)),
);
}
}
double degreeToRadians(double degree) {
return (math.pi / 180) * degree;
}
class HexColor extends Color {
static int _getColorFromHex(String hexColor) {
hexColor = hexColor.toUpperCase().replaceAll('#', '');
if (hexColor.length == 6) {
hexColor = 'FF' + hexColor;
}
return int.parse(hexColor, radix: 16);
}
HexColor(final String hexColor) : super(_getColorFromHex(hexColor));
}
class ExampleViewModel {
final List<Color> pageColors;
final CircularSliderAppearance appearance;
final double min;
final double max;
final double value;
final InnerWidget? innerWidget;
ExampleViewModel({required this.pageColors, required this.appearance, this.min = 0, this.max = 100, this.value = 50, this.innerWidget});
}
class ExamplePage extends StatelessWidget {
final ExampleViewModel viewModel;
const ExamplePage({
Key? key,
required this.viewModel,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(colors: viewModel.pageColors, begin: Alignment.bottomLeft, end: Alignment.topRight, tileMode: TileMode.clamp)),
child: SafeArea(
child: Stack(
alignment: Alignment.bottomCenter,
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 60),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Slide right for more sleek\ncircular slider >>>>>",
style: TextStyle(color: Colors.amber, fontSize: 20, fontWeight: FontWeight.bold),
)
],
),
),
Center(
child: SleekCircularSlider(
onChangeStart: (double value) {},
onChangeEnd: (double value) {},
innerWidget: viewModel.innerWidget,
appearance: viewModel.appearance,
min: viewModel.min,
max: viewModel.max,
initialValue: viewModel.value,
)),
],
),
),
),
);
}
}
class RandomValuePage extends StatefulWidget {
@override
_RandomValuePageState createState() => _RandomValuePageState();
}
class _RandomValuePageState extends State<RandomValuePage> {
int _currentValue = 50;
void _generateRandomValue() {
final randomizer = Random();
_currentValue = randomizer.nextInt(100);
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.red, Colors.pink], begin: Alignment.bottomLeft, end: Alignment.topRight, tileMode: TileMode.clamp)),
child: SafeArea(
child: Align(
alignment: Alignment.center,
child: Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [
SleekCircularSlider(
appearance: appearance01,
initialValue: _currentValue.toDouble(),
),
MaterialButton(
height: 35.0,
highlightElevation: 2.0,
highlightColor: HexColor('#FED1CD'),
shape: StadiumBorder(),
color: HexColor('#FEA78D').withOpacity(0.9),
child: Text('New value'.toUpperCase(), style: TextStyle(fontSize: 18, fontWeight: FontWeight.w200, color: HexColor('#BD0016'))),
onPressed: () {
_generateRandomValue();
},
)
]),
))));
}
}
final customWidth01 = CustomSliderWidths(trackWidth: 2, progressBarWidth: 20, shadowWidth: 50);
final customColors01 = CustomSliderColors(
dotColor: Colors.white.withOpacity(0.8),
trackColor: HexColor('#FF8282').withOpacity(0.6),
progressBarColors: [HexColor('#FFE2E2').withOpacity(0.9), HexColor('#FFAD8D').withOpacity(0.9), HexColor('#FE6490').withOpacity(0.5)],
shadowColor: HexColor('#FFD7E2'),
shadowMaxOpacity: 0.08);
final info = InfoProperties(mainLabelStyle: TextStyle(color: Colors.white, fontSize: 60, fontWeight: FontWeight.w100));
class Clock extends StatefulWidget {
Clock({Key? key}) : super(key: key);
_ClockState createState() => _ClockState();
}
class _ClockState extends State<Clock> {
late Timer _timer;
late DateTime dateTime;
@override
void initState() {
super.initState();
dateTime = DateTime.now();
_timer = Timer.periodic(const Duration(seconds: 1), setTime);
}
void setTime(Timer timer) {
setState(() {
dateTime = DateTime.now();
});
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [HexColor('#FFFFFF'), HexColor('#F0F0F0')], begin: Alignment.bottomLeft, end: Alignment.topRight, tileMode: TileMode.clamp)),
child: SafeArea(
child: Center(
child: ClockWidget(
dateTime: dateTime,
)),
),
),
);
}
}
//example of clock
class ClockWidget extends StatelessWidget {
final DateTime dateTime;
const ClockWidget({Key? key, required this.dateTime}) : super(key: key);
@override
Widget build(BuildContext context) {
var seconds = dateTime.second.toDouble();
var minutes = dateTime.minute.toDouble();
var hours = dateTime.hour.toDouble();
return SleekCircularSlider(
appearance: appearance01,
min: 0,
max: 59,
initialValue: seconds,
innerWidget: (double value) {
return Align(
alignment: Alignment.center,
child: SleekCircularSlider(
appearance: appearance02,
min: 0,
max: 59,
initialValue: minutes,
innerWidget: (double value) {
return Align(
alignment: Alignment.center,
child: SleekCircularSlider(
appearance: appearance03,
min: 0,
max: 11,
initialValue: hours % 12,
innerWidget: (double value) {
final h = hours.toInt() < 12 ? 'AM ${hours.toInt() % 12}' : 'PM ${hours.toInt() % 12}';
final m = minutes.toInt() < 10 ? '0${minutes.toInt()}' : minutes.toInt().toString();
final s = seconds.toInt() < 10 ? '0${seconds.toInt()}' : seconds.toInt().toString();
return Center(
child: Text(
'$h : $m : $s',
style: TextStyle(color: HexColor('#A177B0'), fontSize: 20, fontWeight: FontWeight.w400),
));
},
),
);
},
),
);
},
);
}
}
Output:
Conclusion:
By following these steps, you can easily implement a sleek circular slider in Flutter using the sleek_circular_slider
package. Customize the appearance and behavior of the slider to fit your app’s design and functionality requirements.