Created
November 13, 2024 20:56
-
-
Save hectorAguero/22870093e29b55e1b758e33d3cb84722 to your computer and use it in GitHub Desktop.
flutter-shadcn-ui slider
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return const MaterialApp( | |
debugShowCheckedModeBanner: false, | |
home: Scaffold( | |
body: Center(child: ShadSlider(initialValue: 1)), | |
), | |
); | |
} | |
} | |
class ShadSliderController extends ValueNotifier<double> { | |
ShadSliderController({ | |
required double initialValue, | |
}) : super(initialValue); | |
} | |
class ShadSlider extends StatefulWidget { | |
const ShadSlider({ | |
super.key, | |
this.initialValue, | |
this.onChanged, | |
this.enabled = true, | |
this.min, | |
this.max, | |
this.focusNode, | |
this.autofocus = false, | |
this.mouseCursor, | |
this.disabledMouseCursor, | |
this.thumbColor, | |
this.disabledThumbColor, | |
this.thumbBorderColor, | |
this.disabledThumbBorderColor, | |
this.activeTrackColor, | |
this.inactiveTrackColor, | |
this.disabledActiveTrackColor, | |
this.disabledInactiveTrackColor, | |
this.trackHeight, | |
this.thumbRadius, | |
this.onChangeStart, | |
this.onChangeEnd, | |
this.divisions, | |
this.label, | |
this.semanticFormatterCallback, | |
this.allowedInteraction, | |
this.controller, | |
}) : assert( | |
(initialValue != null) ^ (controller != null), | |
'Either initialValue or controller must be specified', | |
); | |
final double? initialValue; | |
final ValueChanged<double>? onChanged; | |
final bool enabled; | |
final double? min; | |
final double? max; | |
final FocusNode? focusNode; | |
final bool autofocus; | |
final MouseCursor? mouseCursor; | |
final MouseCursor? disabledMouseCursor; | |
final Color? thumbColor; | |
final Color? disabledThumbColor; | |
final Color? thumbBorderColor; | |
final Color? disabledThumbBorderColor; | |
final Color? activeTrackColor; | |
final Color? inactiveTrackColor; | |
final Color? disabledActiveTrackColor; | |
final Color? disabledInactiveTrackColor; | |
final double? trackHeight; | |
final double? thumbRadius; | |
final ValueChanged<double>? onChangeStart; | |
final ValueChanged<double>? onChangeEnd; | |
final int? divisions; | |
final String? label; | |
final SemanticFormatterCallback? semanticFormatterCallback; | |
final SliderInteraction? allowedInteraction; | |
final ShadSliderController? controller; | |
@override | |
State<ShadSlider> createState() => _ShadSliderState(); | |
} | |
class _ShadSliderState extends State<ShadSlider> { | |
late final controller = widget.controller ?? | |
ShadSliderController( | |
initialValue: widget.initialValue!, | |
); | |
@override | |
void initState() { | |
super.initState(); | |
controller.addListener(onChanged); | |
} | |
@override | |
void dispose() { | |
controller.removeListener(onChanged); | |
// dispose the internal controller | |
if (widget.controller == null) { | |
controller.dispose(); | |
} | |
super.dispose(); | |
} | |
void onChanged() { | |
widget.onChanged?.call(controller.value); | |
} | |
@override | |
Widget build(BuildContext context) { | |
final mTheme = Theme.of(context); | |
final effectiveMouseCursor = widget.mouseCursor ?? SystemMouseCursors.click; | |
final effectiveDisabledMouseCursor = | |
widget.disabledMouseCursor ?? SystemMouseCursors.forbidden; | |
final effectiveMin = widget.min ?? 0; | |
final effectiveMax = widget.max ?? 1; | |
final effectiveThumbColor = widget.thumbColor ?? | |
mTheme.sliderTheme.thumbColor ?? | |
mTheme.colorScheme.surface; | |
final effectiveThumbBorderColor = | |
widget.thumbBorderColor ?? mTheme.colorScheme.primary; | |
final effectiveDisabledThumbColor = widget.disabledThumbColor ?? | |
mTheme.sliderTheme.disabledThumbColor ?? | |
mTheme.colorScheme.surface; | |
final effectiveDisabledThumbBorderColor = widget.disabledThumbBorderColor ?? | |
mTheme.colorScheme.primary.withOpacity(.5); | |
final effectiveActiveTrackColor = widget.activeTrackColor ?? | |
mTheme.sliderTheme.activeTrackColor ?? | |
mTheme.colorScheme.primary; | |
final effectiveInactiveTrackColor = widget.inactiveTrackColor ?? | |
mTheme.sliderTheme.inactiveTrackColor ?? | |
mTheme.colorScheme.secondary; | |
final effectiveDisabledActiveTrackColor = widget.disabledActiveTrackColor ?? | |
mTheme.sliderTheme.disabledActiveTrackColor ?? | |
mTheme.colorScheme.primary.withOpacity(.5); | |
final effectiveDisabledInactiveTrackColor = | |
widget.disabledInactiveTrackColor ?? | |
mTheme.sliderTheme.disabledInactiveTrackColor ?? | |
mTheme.colorScheme.secondary.withOpacity(.5); | |
final effectiveTrackHeight = | |
widget.trackHeight ?? mTheme.sliderTheme.trackHeight ?? 8; | |
final effectiveThumbRadius = widget.thumbRadius ?? 10.0; | |
return Theme( | |
data: mTheme.copyWith( | |
sliderTheme: mTheme.sliderTheme.copyWith( | |
trackHeight: effectiveTrackHeight, | |
thumbShape: ShadSliderThumbShape( | |
radius: effectiveThumbRadius, | |
borderColor: effectiveThumbBorderColor, | |
disabledBorderColor: effectiveDisabledThumbBorderColor, | |
thumbColor: effectiveThumbColor, | |
disabledThumbColor: effectiveDisabledThumbColor, | |
), | |
overlayShape: SliderComponentShape.noOverlay, | |
activeTrackColor: effectiveActiveTrackColor, | |
disabledActiveTrackColor: effectiveDisabledActiveTrackColor, | |
inactiveTrackColor: effectiveInactiveTrackColor, | |
disabledInactiveTrackColor: effectiveDisabledInactiveTrackColor, | |
disabledThumbColor: effectiveDisabledThumbColor, | |
), | |
), | |
child: ValueListenableBuilder( | |
valueListenable: controller, | |
builder: (context, value, child) { | |
return Slider( | |
value: value, | |
min: effectiveMin, | |
max: effectiveMax, | |
mouseCursor: widget.enabled | |
? effectiveMouseCursor | |
: effectiveDisabledMouseCursor, | |
onChanged: widget.enabled ? (v) => controller.value = v : null, | |
autofocus: widget.autofocus, | |
focusNode: widget.focusNode, | |
onChangeStart: widget.onChangeStart, | |
onChangeEnd: widget.onChangeEnd, | |
divisions: widget.divisions, | |
label: widget.label, | |
semanticFormatterCallback: widget.semanticFormatterCallback, | |
allowedInteraction: widget.allowedInteraction, | |
); | |
}, | |
), | |
); | |
} | |
} | |
class ShadSliderThumbShape extends SliderComponentShape { | |
const ShadSliderThumbShape({ | |
required this.radius, | |
required this.borderColor, | |
required this.disabledBorderColor, | |
required this.thumbColor, | |
required this.disabledThumbColor, | |
}); | |
final double radius; | |
final Color borderColor; | |
final Color disabledBorderColor; | |
final Color thumbColor; | |
final Color disabledThumbColor; | |
@override | |
Size getPreferredSize(bool isEnabled, bool isDiscrete) { | |
return Size.fromRadius(radius); | |
} | |
@override | |
void paint( | |
PaintingContext context, | |
Offset center, { | |
required Animation<double> activationAnimation, | |
required Animation<double> enableAnimation, | |
required bool isDiscrete, | |
required TextPainter labelPainter, | |
required RenderBox parentBox, | |
required SliderThemeData sliderTheme, | |
required TextDirection textDirection, | |
required double value, | |
required double textScaleFactor, | |
required Size sizeWithOverflow, | |
}) { | |
final canvas = context.canvas; | |
final colorTween = ColorTween( | |
begin: disabledThumbColor, | |
end: thumbColor, | |
); | |
final color = colorTween.evaluate(enableAnimation)!; | |
canvas.drawCircle( | |
center, | |
radius, | |
Paint()..color = color, | |
); | |
final borderColorTween = ColorTween( | |
begin: disabledBorderColor, | |
end: borderColor, | |
); | |
final effectiveBorderColor = borderColorTween.evaluate(enableAnimation)!; | |
final paintBorder = Paint() | |
..color = effectiveBorderColor | |
..strokeWidth = 2 | |
..style = PaintingStyle.stroke; | |
canvas.drawCircle(center, radius, paintBorder); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment