Skip to content
Eldiiar Almazbek edited this page Dec 7, 2023 · 1 revision

Animation Slider

import 'package:flutter/material.dart';

class AnimationSlider extends StatefulWidget {
  const AnimationSlider({
    this.progressValue = 0.0,
    this.thumbIconData,
    this.thumbRadius,
    this.thumbIconSize,
    this.thumbBorderRadius,
    this.thumbColor,
    this.thumbIconColor,
    this.trackColor,
    this.activeTrackColor,
    this.inactiveTrackColor,
    this.trackHeight,
    this.fullActiveIconData,
    this.fullActiveThumbRadius,
    this.fullActiveThumbIconSize,
    this.fullActiveThumbBorderRadius,
    this.fullActiveThumbColor,
    this.fullActiveThumbIconColor,
    this.inActiveThumbColor,
    this.onChanged,
    super.key,
  });

  final double progressValue;
  final IconData? thumbIconData;
  final IconData? fullActiveIconData;
  final double? thumbRadius;
  final double? fullActiveThumbRadius;
  final double? thumbIconSize;
  final double? fullActiveThumbIconSize;
  final double? thumbBorderRadius;
  final double? fullActiveThumbBorderRadius;
  final Color? thumbColor;
  final Color? fullActiveThumbColor;
  final Color? thumbIconColor;
  final Color? fullActiveThumbIconColor;
  final Color? trackColor;
  final Color? activeTrackColor;
  final Color? inactiveTrackColor;
  final Color? inActiveThumbColor;
  final double? trackHeight;
  final void Function(double)? onChanged;

  @override
  State<AnimationSlider> createState() => _AnimationSliderState();
}

class _AnimationSliderState extends State<AnimationSlider>
    with TickerProviderStateMixin {
  late final AnimationController controller;

  static const minValue = 0.001;
  static const maxValue = 1.0;

  @override
  void initState() {
    controller = AnimationController(
      vsync: this,
      value: minValue,
    )..addListener(() => setState(() {}));

    final value = widget.progressValue == 0.0 ? minValue : widget.progressValue;
    controller.animateTo(
      value,
      curve: Curves.easeIn,
      duration: const Duration(milliseconds: 800),
    );
    super.initState();
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SliderTheme(
      data: SliderThemeData(
        trackHeight: widget.trackHeight,
        activeTrackColor: widget.activeTrackColor,
        inactiveTrackColor: widget.inactiveTrackColor,
        thumbShape: AppSliderShape(
          thumbIconData: controller.value == maxValue
              ? widget.fullActiveIconData
              : widget.thumbIconData,
          thumbRadius: controller.value == maxValue
              ? widget.fullActiveThumbRadius
              : controller.value == minValue
                  ? widget.thumbRadius
                  : null,
          thumbIconSize: controller.value == maxValue
              ? widget.fullActiveThumbIconSize
              : widget.thumbIconSize,
          thumbBorderRadius: controller.value == maxValue
              ? widget.fullActiveThumbBorderRadius
              : widget.thumbBorderRadius,
          thumbColor: controller.value == minValue
              ? widget.inActiveThumbColor
              : widget.activeTrackColor,
          thumbIconColor: controller.value == maxValue
              ? widget.fullActiveThumbIconColor
              : widget.thumbIconColor,
        ),
      ),
      child: Slider(
        min: 0.0,
        max: 1.0,
        value: controller.value,
        onChanged: widget.onChanged ??
            (v) {
              controller.animateTo(
                v == 0.0 ? minValue : v,
                curve: Curves.easeIn,
                duration: const Duration(milliseconds: 100),
              );
            },
      ),
    );
  }
}

class AppSliderShape extends SliderComponentShape {
  const AppSliderShape({
    this.thumbIconData,
    this.thumbRadius,
    this.thumbIconSize,
    this.thumbBorderRadius,
    this.thumbColor,
    this.thumbIconColor,
  });

  final IconData? thumbIconData;
  final double? thumbRadius;
  final double? thumbIconSize;
  final double? thumbBorderRadius;
  final Color? thumbColor;
  final Color? thumbIconColor;

  @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 paint = Paint()
      ..style = PaintingStyle.fill
      ..color = thumbColor ?? sliderTheme.thumbColor!;

    final textPainter = TextPainter(
      textDirection: TextDirection.rtl,
      text: TextSpan(
        text: thumbIconData != null
            ? String.fromCharCode(thumbIconData!.codePoint)
            : '',
        style: TextStyle(
          fontSize: thumbIconSize,
          fontFamily: thumbIconData?.fontFamily,
          color: thumbIconColor,
        ),
      ),
    )..layout();

    final size = thumbRadius ?? sliderTheme.trackHeight ?? 0;

    final rect =
        Rect.fromCenter(center: center, width: size * 2, height: size * 2);

    context.canvas.drawRRect(RRect.fromRectXY(rect, size, size), paint);

    final textCenter = Offset(
      center.dx - (textPainter.width / 2),
      center.dy - (textPainter.height / 2),
    );

    textPainter.paint(context.canvas, textCenter);
  }

  @override
  Size getPreferredSize(bool isEnabled, bool isDiscrete) =>
      Size.fromRadius(thumbRadius ?? 0);
}
Clone this wiki locally