how to add multiple sliders on one slider? #Flutter

140

Using Stack with three sliders did not work because it was being overlapped.

I have made this Slider3X of being curious. There are few things need to fix here, start and end points missing some fractional position.

Code on Gist, dart pad

class Slider3x extends StatefulWidget {
  const Slider3x({
    Key? key,
    required this.onSliderUpdate,
    this.size = const Size(5, 10),
    this.min = 0,
    this.max = 1.0,
    this.colorX = Colors.green,
    this.colorY = Colors.blue,
    this.colorZ = Colors.redAccent,
  }) : super(key: key);

  final Function(double? x, double? y, double? z) onSliderUpdate;

  ///size of moveable 3x point 😅, forgot the name maybe thumbs
  final Size size;
  final double? min;
  final double? max;

  final Color colorX;
  final Color colorY;
  final Color colorZ;

  @override
  State<Slider3x> createState() => _Slider3xState();
}

class _Slider3xState extends State<Slider3x> {
  /// three slider position
  double? x;
  double? y;
  double? z;

  final double tapSpacesArea = .05;

  // currect active slider , help to prevent overlLAp while sliding
  int activeSliderNumber = 0;

  //* Update sldier
  void _updateSlider(double dx, double maxWidth) {
    final tapPosition = dx;

    //* update logic
    if (tapPosition <= 0 || tapPosition >= maxWidth) {
      return;
    }

    //* update on UI based on slider number
    if (activeSliderNumber == 0) {
      setState(() {
        x = tapPosition;
      });
    } else if (activeSliderNumber == 1) {
      setState(() {
        y = tapPosition;
      });
    } else if (activeSliderNumber == 2) {
      setState(() {
        z = tapPosition;
      });
    }

    //pass value on main widget
    widget.onSliderUpdate(
      dp(_generateSliderValue(maxWidth: maxWidth, x: x!)),
      dp(_generateSliderValue(maxWidth: maxWidth, x: y!)),
      dp(_generateSliderValue(maxWidth: maxWidth, x: z!)),
    );
  }

  //round number
  double dp(double val, {int places = 2}) {
    num mod = pow(10.0, places);
    return ((val * mod).round().toDouble() / mod);
  }

  //* calculate slider value
  double _generateSliderValue({
    required double maxWidth,
    required double x,
  }) {
    // x is slider original position on width:maxWidth

    return (widget.max! - widget.min!) * (x / maxWidth) + widget.min!;
  }

  //* select ActiveSlider, fixed overLap issue
  //* slider Selector logic
  void _selectSlider({
    required double maxWidth,
    required double tapPosition,
  }) {
    final maxArea = maxWidth * tapSpacesArea;

    if ((tapPosition - x!).abs() < maxArea) {
      setState(() {
        activeSliderNumber = 0;
      });
    } else if ((tapPosition - y!).abs() < maxArea) {
      setState(() {
        activeSliderNumber = 1;
      });
    } else if ((tapPosition - z!).abs() < maxArea) {
      setState(() {
        activeSliderNumber = 2;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          SizedBox(
            height: 50,
            child: LayoutBuilder(builder: (context, constraints) {
              final maxWidth = constraints.maxWidth - 10;
              x = x ?? 0;
              y = y ?? constraints.maxWidth / 2;
              z = z ?? maxWidth;
              return Stack(
                alignment: Alignment.center,
                children: [
                  Positioned(
                    left: x,
                    child: Container(
                      height: activeSliderNumber == 0
                          ? widget.size.height * 1.5
                          : widget.size.height,
                      width: widget.size.width,
                      color: widget.colorX,
                    ),
                  ),
                  //* paint Y
                  Positioned(
                    left: y,
                    child: Container(
                      height: activeSliderNumber == 1
                          ? widget.size.height * 1.5
                          : widget.size.height,
                      width: widget.size.width,
                      color: widget.colorY,
                    ),
                  ),
                  //* paint z
                  Positioned(
                    left: z,
                    child: Container(
                      height: activeSliderNumber == 2
                          ? widget.size.height * 1.5
                          : widget.size.height,
                      width: widget.size.width,
                      color: widget.colorZ,
                    ),
                  ),

                  const Divider(
                    endIndent: 10,
                  ),

                  GestureDetector(
                    onTapDown: (details) => _selectSlider(
                        maxWidth: maxWidth,
                        tapPosition: details.localPosition.dx),
                    onPanUpdate: (details) =>
                        _updateSlider(details.localPosition.dx, maxWidth),
                  ),
                ],
              );
            }),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                widget.min.toString(),
              ),
              Text(
                widget.max.toString(),
              ),
            ],
          )
        ],
      ),
    );
  }
}

Share:
140
Suthura Sudharaka
Author by

Suthura Sudharaka

Developer

Updated on January 02, 2023

Comments

  • Suthura Sudharaka
    Suthura Sudharaka over 1 year

    I want to add multiple sliders in one slider. If you're not clear about what I'm asking please refer the below image

    enter image description here

    I want these three squares to be sliding and get the values of them. I did some searching and could not find any flutter widget or a plugin that has the support.

    I tried to use a stack and use multiple Slider widgets at the same location but it is also not working. (I know it's not a good approach.)

    How can I make this happen. To have multiple sliders on the same line and get the values. Any help or ideas are very much appreciated.