Flutter custom range slider











up vote
6
down vote

favorite
4












I'm trying to create a range slider on top of a Row of Containers which should create an audio waveform, but I have no idea where to even start...



The main issue is that the range slider sits right on top of the row of containers and it should change their colors on the "selected" section.



enter image description here



Here's what I currently have:



enter image description here



The code to create the image and details.



class BeatLyricsPage extends StatefulWidget {
final Beat beat;
BeatLyricsPage(this.beat);

@override
_BeatLyricsPageState createState() => _BeatLyricsPageState(beat);
}

class _BeatLyricsPageState extends State<BeatLyricsPage> {
final Beat beat;


final _kPicHeight = 190.0;
// used in _buildPageHeading to add the beat key and beat bpm
Widget _buildBeatInfoItem(String text) => DecoratedBox(
decoration: BoxDecoration(
border: Border.all(color: MyColor.white, width: 1.0),
borderRadius: BorderRadius.circular(4.0),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 3.0, horizontal: 12.0),
child: Text(text, style: TextStyle(color: MyColor.white, fontSize: 10.0, fontWeight: FontWeight.w600)),
),
);

final _kAudioControlsWidth = 180.0;
final _kAudioControlsHeight = 36.0;
final _kAudioControlsMainButtonSize = 56.0;

Widget _buildAudioControls(BuildContext context) => Positioned(
left: (MediaQuery.of(context).size.width / 2) - (_kAudioControlsWidth / 2),
top: _kPicHeight - (_kAudioControlsHeight / 2),
child: Stack(
overflow: Overflow.visible,
children: [
Container(
width: _kAudioControlsWidth,
height: _kAudioControlsHeight,
decoration: BoxDecoration(color: MyColor.darkGrey, borderRadius: BorderRadius.circular(100.0)),
padding: EdgeInsets.symmetric(horizontal: LayoutSpacing.sm),
child: Row(
children: [
CButtonLike(beatId: beat.id),
Spacer(),
GestureDetector(
behavior: HitTestBehavior.opaque,
child: Icon(BeatPulseIcons.cart),
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => LicenseOptionsPage(beat))),
),
],
),
),
// ****** MAIN BUTTON (Play/Pause) ******
Positioned(
left: (_kAudioControlsWidth / 2) - (_kAudioControlsMainButtonSize / 2),
top: (_kAudioControlsHeight - _kAudioControlsMainButtonSize) / 2,
child: Container(
height: _kAudioControlsMainButtonSize,
width: _kAudioControlsMainButtonSize,
decoration: BoxDecoration(
gradient: LinearGradient(begin: Alignment.topLeft, colors: [MyColor.primary, Color(0xFFf80d0a)]),
borderRadius: BorderRadius.circular(100.0)),
child: CButtonPlay(),
),
)
],
),
);

Widget _buildWaveForm() {
// creates a random list of doubles, "fake data"
var rng = Random();
final List waveFormData = ;
for (var i = 0; i < 90; i++) {
waveFormData.add(rng.nextInt(45).toDouble());
}
// player bloc
final playerBloc = BlocProvider.getPlayerBloc(context);
// renders
return Container(
height: _kPicHeight,
padding: EdgeInsets.symmetric(vertical: LayoutSpacing.xxxl),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// current playing second
StreamBuilder<double>(
stream: playerBloc.playingSecond,
initialData: 0.0,
builder: (_, playingSecondSnapshot) {
// current beat playing
return StreamBuilder<Beat>(
stream: playerBloc.playingBeat,
builder: (_, playingBeatSnapshot) {
final playingBeat = playingBeatSnapshot.data;
// if the beat playing is the same as the beat selected for the lyrics, show playing seconds
if (playingBeat?.id == beat.id)
return Text(secondsToTime(playingSecondSnapshot.data), style: MyFontStyle.sizeXxs);
// otherwise show 0:00
else
return Text(secondsToTime(0), style: MyFontStyle.sizeXxs);
},
);
},
),
SizedBox(width: LayoutSpacing.xs),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: waveFormData
.map((waveFormDataIndex) => Container(
height: waveFormDataIndex > 5.0 ? waveFormDataIndex : 5.0,
width: 2,
color: MyColor.white,
margin: EdgeInsets.only(right: 1),
))
.toList(),
),
SizedBox(width: LayoutSpacing.xs),
Text(secondsToTime(beat.length), style: MyFontStyle.sizeXxs),
],
),
);
}

Widget _buildPageHeading(BuildContext context, {@required String imageUrl}) => Stack(
children: [
Column(
children: [
Hero(
tag: MyKeys.makePlayerCoverKey(beat.id),
child: Opacity(
opacity: 0.3,
child: Container(
height: _kPicHeight,
decoration: BoxDecoration(
image: DecorationImage(image: CachedNetworkImageProvider(imageUrl), fit: BoxFit.cover),
),
),
),
),
Container(color: MyColor.background, height: LayoutSpacing.xl)
],
),
Padding(
padding: EdgeInsets.all(LayoutSpacing.xs),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
_buildBeatInfoItem(beat.key),
SizedBox(width: 4.0),
_buildBeatInfoItem('${beat.bpm} BPM'),
],
),
),
_buildAudioControls(context),
_buildWaveForm(),
],
);
}









share|improve this question


























    up vote
    6
    down vote

    favorite
    4












    I'm trying to create a range slider on top of a Row of Containers which should create an audio waveform, but I have no idea where to even start...



    The main issue is that the range slider sits right on top of the row of containers and it should change their colors on the "selected" section.



    enter image description here



    Here's what I currently have:



    enter image description here



    The code to create the image and details.



    class BeatLyricsPage extends StatefulWidget {
    final Beat beat;
    BeatLyricsPage(this.beat);

    @override
    _BeatLyricsPageState createState() => _BeatLyricsPageState(beat);
    }

    class _BeatLyricsPageState extends State<BeatLyricsPage> {
    final Beat beat;


    final _kPicHeight = 190.0;
    // used in _buildPageHeading to add the beat key and beat bpm
    Widget _buildBeatInfoItem(String text) => DecoratedBox(
    decoration: BoxDecoration(
    border: Border.all(color: MyColor.white, width: 1.0),
    borderRadius: BorderRadius.circular(4.0),
    ),
    child: Padding(
    padding: EdgeInsets.symmetric(vertical: 3.0, horizontal: 12.0),
    child: Text(text, style: TextStyle(color: MyColor.white, fontSize: 10.0, fontWeight: FontWeight.w600)),
    ),
    );

    final _kAudioControlsWidth = 180.0;
    final _kAudioControlsHeight = 36.0;
    final _kAudioControlsMainButtonSize = 56.0;

    Widget _buildAudioControls(BuildContext context) => Positioned(
    left: (MediaQuery.of(context).size.width / 2) - (_kAudioControlsWidth / 2),
    top: _kPicHeight - (_kAudioControlsHeight / 2),
    child: Stack(
    overflow: Overflow.visible,
    children: [
    Container(
    width: _kAudioControlsWidth,
    height: _kAudioControlsHeight,
    decoration: BoxDecoration(color: MyColor.darkGrey, borderRadius: BorderRadius.circular(100.0)),
    padding: EdgeInsets.symmetric(horizontal: LayoutSpacing.sm),
    child: Row(
    children: [
    CButtonLike(beatId: beat.id),
    Spacer(),
    GestureDetector(
    behavior: HitTestBehavior.opaque,
    child: Icon(BeatPulseIcons.cart),
    onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => LicenseOptionsPage(beat))),
    ),
    ],
    ),
    ),
    // ****** MAIN BUTTON (Play/Pause) ******
    Positioned(
    left: (_kAudioControlsWidth / 2) - (_kAudioControlsMainButtonSize / 2),
    top: (_kAudioControlsHeight - _kAudioControlsMainButtonSize) / 2,
    child: Container(
    height: _kAudioControlsMainButtonSize,
    width: _kAudioControlsMainButtonSize,
    decoration: BoxDecoration(
    gradient: LinearGradient(begin: Alignment.topLeft, colors: [MyColor.primary, Color(0xFFf80d0a)]),
    borderRadius: BorderRadius.circular(100.0)),
    child: CButtonPlay(),
    ),
    )
    ],
    ),
    );

    Widget _buildWaveForm() {
    // creates a random list of doubles, "fake data"
    var rng = Random();
    final List waveFormData = ;
    for (var i = 0; i < 90; i++) {
    waveFormData.add(rng.nextInt(45).toDouble());
    }
    // player bloc
    final playerBloc = BlocProvider.getPlayerBloc(context);
    // renders
    return Container(
    height: _kPicHeight,
    padding: EdgeInsets.symmetric(vertical: LayoutSpacing.xxxl),
    child: Row(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.end,
    children: [
    // current playing second
    StreamBuilder<double>(
    stream: playerBloc.playingSecond,
    initialData: 0.0,
    builder: (_, playingSecondSnapshot) {
    // current beat playing
    return StreamBuilder<Beat>(
    stream: playerBloc.playingBeat,
    builder: (_, playingBeatSnapshot) {
    final playingBeat = playingBeatSnapshot.data;
    // if the beat playing is the same as the beat selected for the lyrics, show playing seconds
    if (playingBeat?.id == beat.id)
    return Text(secondsToTime(playingSecondSnapshot.data), style: MyFontStyle.sizeXxs);
    // otherwise show 0:00
    else
    return Text(secondsToTime(0), style: MyFontStyle.sizeXxs);
    },
    );
    },
    ),
    SizedBox(width: LayoutSpacing.xs),
    Row(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.end,
    children: waveFormData
    .map((waveFormDataIndex) => Container(
    height: waveFormDataIndex > 5.0 ? waveFormDataIndex : 5.0,
    width: 2,
    color: MyColor.white,
    margin: EdgeInsets.only(right: 1),
    ))
    .toList(),
    ),
    SizedBox(width: LayoutSpacing.xs),
    Text(secondsToTime(beat.length), style: MyFontStyle.sizeXxs),
    ],
    ),
    );
    }

    Widget _buildPageHeading(BuildContext context, {@required String imageUrl}) => Stack(
    children: [
    Column(
    children: [
    Hero(
    tag: MyKeys.makePlayerCoverKey(beat.id),
    child: Opacity(
    opacity: 0.3,
    child: Container(
    height: _kPicHeight,
    decoration: BoxDecoration(
    image: DecorationImage(image: CachedNetworkImageProvider(imageUrl), fit: BoxFit.cover),
    ),
    ),
    ),
    ),
    Container(color: MyColor.background, height: LayoutSpacing.xl)
    ],
    ),
    Padding(
    padding: EdgeInsets.all(LayoutSpacing.xs),
    child: Row(
    mainAxisAlignment: MainAxisAlignment.end,
    children: [
    _buildBeatInfoItem(beat.key),
    SizedBox(width: 4.0),
    _buildBeatInfoItem('${beat.bpm} BPM'),
    ],
    ),
    ),
    _buildAudioControls(context),
    _buildWaveForm(),
    ],
    );
    }









    share|improve this question
























      up vote
      6
      down vote

      favorite
      4









      up vote
      6
      down vote

      favorite
      4






      4





      I'm trying to create a range slider on top of a Row of Containers which should create an audio waveform, but I have no idea where to even start...



      The main issue is that the range slider sits right on top of the row of containers and it should change their colors on the "selected" section.



      enter image description here



      Here's what I currently have:



      enter image description here



      The code to create the image and details.



      class BeatLyricsPage extends StatefulWidget {
      final Beat beat;
      BeatLyricsPage(this.beat);

      @override
      _BeatLyricsPageState createState() => _BeatLyricsPageState(beat);
      }

      class _BeatLyricsPageState extends State<BeatLyricsPage> {
      final Beat beat;


      final _kPicHeight = 190.0;
      // used in _buildPageHeading to add the beat key and beat bpm
      Widget _buildBeatInfoItem(String text) => DecoratedBox(
      decoration: BoxDecoration(
      border: Border.all(color: MyColor.white, width: 1.0),
      borderRadius: BorderRadius.circular(4.0),
      ),
      child: Padding(
      padding: EdgeInsets.symmetric(vertical: 3.0, horizontal: 12.0),
      child: Text(text, style: TextStyle(color: MyColor.white, fontSize: 10.0, fontWeight: FontWeight.w600)),
      ),
      );

      final _kAudioControlsWidth = 180.0;
      final _kAudioControlsHeight = 36.0;
      final _kAudioControlsMainButtonSize = 56.0;

      Widget _buildAudioControls(BuildContext context) => Positioned(
      left: (MediaQuery.of(context).size.width / 2) - (_kAudioControlsWidth / 2),
      top: _kPicHeight - (_kAudioControlsHeight / 2),
      child: Stack(
      overflow: Overflow.visible,
      children: [
      Container(
      width: _kAudioControlsWidth,
      height: _kAudioControlsHeight,
      decoration: BoxDecoration(color: MyColor.darkGrey, borderRadius: BorderRadius.circular(100.0)),
      padding: EdgeInsets.symmetric(horizontal: LayoutSpacing.sm),
      child: Row(
      children: [
      CButtonLike(beatId: beat.id),
      Spacer(),
      GestureDetector(
      behavior: HitTestBehavior.opaque,
      child: Icon(BeatPulseIcons.cart),
      onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => LicenseOptionsPage(beat))),
      ),
      ],
      ),
      ),
      // ****** MAIN BUTTON (Play/Pause) ******
      Positioned(
      left: (_kAudioControlsWidth / 2) - (_kAudioControlsMainButtonSize / 2),
      top: (_kAudioControlsHeight - _kAudioControlsMainButtonSize) / 2,
      child: Container(
      height: _kAudioControlsMainButtonSize,
      width: _kAudioControlsMainButtonSize,
      decoration: BoxDecoration(
      gradient: LinearGradient(begin: Alignment.topLeft, colors: [MyColor.primary, Color(0xFFf80d0a)]),
      borderRadius: BorderRadius.circular(100.0)),
      child: CButtonPlay(),
      ),
      )
      ],
      ),
      );

      Widget _buildWaveForm() {
      // creates a random list of doubles, "fake data"
      var rng = Random();
      final List waveFormData = ;
      for (var i = 0; i < 90; i++) {
      waveFormData.add(rng.nextInt(45).toDouble());
      }
      // player bloc
      final playerBloc = BlocProvider.getPlayerBloc(context);
      // renders
      return Container(
      height: _kPicHeight,
      padding: EdgeInsets.symmetric(vertical: LayoutSpacing.xxxl),
      child: Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
      // current playing second
      StreamBuilder<double>(
      stream: playerBloc.playingSecond,
      initialData: 0.0,
      builder: (_, playingSecondSnapshot) {
      // current beat playing
      return StreamBuilder<Beat>(
      stream: playerBloc.playingBeat,
      builder: (_, playingBeatSnapshot) {
      final playingBeat = playingBeatSnapshot.data;
      // if the beat playing is the same as the beat selected for the lyrics, show playing seconds
      if (playingBeat?.id == beat.id)
      return Text(secondsToTime(playingSecondSnapshot.data), style: MyFontStyle.sizeXxs);
      // otherwise show 0:00
      else
      return Text(secondsToTime(0), style: MyFontStyle.sizeXxs);
      },
      );
      },
      ),
      SizedBox(width: LayoutSpacing.xs),
      Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.end,
      children: waveFormData
      .map((waveFormDataIndex) => Container(
      height: waveFormDataIndex > 5.0 ? waveFormDataIndex : 5.0,
      width: 2,
      color: MyColor.white,
      margin: EdgeInsets.only(right: 1),
      ))
      .toList(),
      ),
      SizedBox(width: LayoutSpacing.xs),
      Text(secondsToTime(beat.length), style: MyFontStyle.sizeXxs),
      ],
      ),
      );
      }

      Widget _buildPageHeading(BuildContext context, {@required String imageUrl}) => Stack(
      children: [
      Column(
      children: [
      Hero(
      tag: MyKeys.makePlayerCoverKey(beat.id),
      child: Opacity(
      opacity: 0.3,
      child: Container(
      height: _kPicHeight,
      decoration: BoxDecoration(
      image: DecorationImage(image: CachedNetworkImageProvider(imageUrl), fit: BoxFit.cover),
      ),
      ),
      ),
      ),
      Container(color: MyColor.background, height: LayoutSpacing.xl)
      ],
      ),
      Padding(
      padding: EdgeInsets.all(LayoutSpacing.xs),
      child: Row(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
      _buildBeatInfoItem(beat.key),
      SizedBox(width: 4.0),
      _buildBeatInfoItem('${beat.bpm} BPM'),
      ],
      ),
      ),
      _buildAudioControls(context),
      _buildWaveForm(),
      ],
      );
      }









      share|improve this question













      I'm trying to create a range slider on top of a Row of Containers which should create an audio waveform, but I have no idea where to even start...



      The main issue is that the range slider sits right on top of the row of containers and it should change their colors on the "selected" section.



      enter image description here



      Here's what I currently have:



      enter image description here



      The code to create the image and details.



      class BeatLyricsPage extends StatefulWidget {
      final Beat beat;
      BeatLyricsPage(this.beat);

      @override
      _BeatLyricsPageState createState() => _BeatLyricsPageState(beat);
      }

      class _BeatLyricsPageState extends State<BeatLyricsPage> {
      final Beat beat;


      final _kPicHeight = 190.0;
      // used in _buildPageHeading to add the beat key and beat bpm
      Widget _buildBeatInfoItem(String text) => DecoratedBox(
      decoration: BoxDecoration(
      border: Border.all(color: MyColor.white, width: 1.0),
      borderRadius: BorderRadius.circular(4.0),
      ),
      child: Padding(
      padding: EdgeInsets.symmetric(vertical: 3.0, horizontal: 12.0),
      child: Text(text, style: TextStyle(color: MyColor.white, fontSize: 10.0, fontWeight: FontWeight.w600)),
      ),
      );

      final _kAudioControlsWidth = 180.0;
      final _kAudioControlsHeight = 36.0;
      final _kAudioControlsMainButtonSize = 56.0;

      Widget _buildAudioControls(BuildContext context) => Positioned(
      left: (MediaQuery.of(context).size.width / 2) - (_kAudioControlsWidth / 2),
      top: _kPicHeight - (_kAudioControlsHeight / 2),
      child: Stack(
      overflow: Overflow.visible,
      children: [
      Container(
      width: _kAudioControlsWidth,
      height: _kAudioControlsHeight,
      decoration: BoxDecoration(color: MyColor.darkGrey, borderRadius: BorderRadius.circular(100.0)),
      padding: EdgeInsets.symmetric(horizontal: LayoutSpacing.sm),
      child: Row(
      children: [
      CButtonLike(beatId: beat.id),
      Spacer(),
      GestureDetector(
      behavior: HitTestBehavior.opaque,
      child: Icon(BeatPulseIcons.cart),
      onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => LicenseOptionsPage(beat))),
      ),
      ],
      ),
      ),
      // ****** MAIN BUTTON (Play/Pause) ******
      Positioned(
      left: (_kAudioControlsWidth / 2) - (_kAudioControlsMainButtonSize / 2),
      top: (_kAudioControlsHeight - _kAudioControlsMainButtonSize) / 2,
      child: Container(
      height: _kAudioControlsMainButtonSize,
      width: _kAudioControlsMainButtonSize,
      decoration: BoxDecoration(
      gradient: LinearGradient(begin: Alignment.topLeft, colors: [MyColor.primary, Color(0xFFf80d0a)]),
      borderRadius: BorderRadius.circular(100.0)),
      child: CButtonPlay(),
      ),
      )
      ],
      ),
      );

      Widget _buildWaveForm() {
      // creates a random list of doubles, "fake data"
      var rng = Random();
      final List waveFormData = ;
      for (var i = 0; i < 90; i++) {
      waveFormData.add(rng.nextInt(45).toDouble());
      }
      // player bloc
      final playerBloc = BlocProvider.getPlayerBloc(context);
      // renders
      return Container(
      height: _kPicHeight,
      padding: EdgeInsets.symmetric(vertical: LayoutSpacing.xxxl),
      child: Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
      // current playing second
      StreamBuilder<double>(
      stream: playerBloc.playingSecond,
      initialData: 0.0,
      builder: (_, playingSecondSnapshot) {
      // current beat playing
      return StreamBuilder<Beat>(
      stream: playerBloc.playingBeat,
      builder: (_, playingBeatSnapshot) {
      final playingBeat = playingBeatSnapshot.data;
      // if the beat playing is the same as the beat selected for the lyrics, show playing seconds
      if (playingBeat?.id == beat.id)
      return Text(secondsToTime(playingSecondSnapshot.data), style: MyFontStyle.sizeXxs);
      // otherwise show 0:00
      else
      return Text(secondsToTime(0), style: MyFontStyle.sizeXxs);
      },
      );
      },
      ),
      SizedBox(width: LayoutSpacing.xs),
      Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.end,
      children: waveFormData
      .map((waveFormDataIndex) => Container(
      height: waveFormDataIndex > 5.0 ? waveFormDataIndex : 5.0,
      width: 2,
      color: MyColor.white,
      margin: EdgeInsets.only(right: 1),
      ))
      .toList(),
      ),
      SizedBox(width: LayoutSpacing.xs),
      Text(secondsToTime(beat.length), style: MyFontStyle.sizeXxs),
      ],
      ),
      );
      }

      Widget _buildPageHeading(BuildContext context, {@required String imageUrl}) => Stack(
      children: [
      Column(
      children: [
      Hero(
      tag: MyKeys.makePlayerCoverKey(beat.id),
      child: Opacity(
      opacity: 0.3,
      child: Container(
      height: _kPicHeight,
      decoration: BoxDecoration(
      image: DecorationImage(image: CachedNetworkImageProvider(imageUrl), fit: BoxFit.cover),
      ),
      ),
      ),
      ),
      Container(color: MyColor.background, height: LayoutSpacing.xl)
      ],
      ),
      Padding(
      padding: EdgeInsets.all(LayoutSpacing.xs),
      child: Row(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
      _buildBeatInfoItem(beat.key),
      SizedBox(width: 4.0),
      _buildBeatInfoItem('${beat.bpm} BPM'),
      ],
      ),
      ),
      _buildAudioControls(context),
      _buildWaveForm(),
      ],
      );
      }






      dart flutter flutter-layout






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Oct 25 at 10:47









      Giacomo

      9119




      9119
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote













          To create a custom range slider, you can use the GestureRecognizer and save the position of each slider in variable inside a StatefulWidget. To decide wether a bar with the index i is inside the range, you can divide the pixel position of the limiter(bar1&bar2 in the source below) by the width of bars and compare it to i.



          Sadly I couldn't work with your code example. Instead I created a bare minimum example as you can see below. If you take a minute to read into, I'm sure you can transfer it to your application.



          Custom Range Slider



          import 'dart:math';

          import 'package:flutter/material.dart';

          List<int> bars = ;

          void main() {
          // generate random bars
          Random r = Random();
          for (var i = 0; i < 50; i++) {
          bars.add(r.nextInt(200));
          }

          runApp(MyApp());
          }

          class MyApp extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
          return MaterialApp(
          home: Home(),
          );
          }
          }

          class Home extends StatefulWidget {
          @override
          State<StatefulWidget> createState() => HomeState();
          }

          class HomeState extends State<Home> {
          static const barWidth = 5.0;
          double bar1Position = 60.0;
          double bar2Position = 180.0;

          @override
          Widget build(BuildContext context) {
          int i = 0;

          return Scaffold(
          body: Center(
          child: Stack(
          alignment: Alignment.centerLeft,
          children: <Widget>[
          Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.start,
          children: bars.map((int height) {
          Color color =
          i >= bar1Position / barWidth && i <= bar2Position / barWidth
          ? Colors.deepPurple
          : Colors.blueGrey;
          i++;

          return Container(
          color: color,
          height: height.toDouble(),
          width: 5.0,
          );
          }).toList(),
          ),
          Bar(
          position: bar2Position,
          callback: (DragUpdateDetails details) {
          setState(() {
          bar2Position += details.delta.dx;
          });
          },
          ),
          Bar(
          position: bar1Position,
          callback: (DragUpdateDetails details) {
          setState(() {
          bar1Position += details.delta.dx;
          });
          },
          ),
          ],
          ),
          ),
          );
          }
          }

          class Bar extends StatelessWidget {
          final double position;
          final GestureDragUpdateCallback callback;

          Bar({this.position, this.callback});

          @override
          Widget build(BuildContext context) {
          return Padding(
          padding: EdgeInsets.only(left: position >= 0.0 ? position : 0.0),
          child: GestureDetector(
          onHorizontalDragUpdate: callback,
          child: Container(
          color: Colors.red,
          height: 200.0,
          width: 5.0,
          ),
          ),
          );
          }
          }





          share|improve this answer





















            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














             

            draft saved


            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52987440%2fflutter-custom-range-slider%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            1
            down vote













            To create a custom range slider, you can use the GestureRecognizer and save the position of each slider in variable inside a StatefulWidget. To decide wether a bar with the index i is inside the range, you can divide the pixel position of the limiter(bar1&bar2 in the source below) by the width of bars and compare it to i.



            Sadly I couldn't work with your code example. Instead I created a bare minimum example as you can see below. If you take a minute to read into, I'm sure you can transfer it to your application.



            Custom Range Slider



            import 'dart:math';

            import 'package:flutter/material.dart';

            List<int> bars = ;

            void main() {
            // generate random bars
            Random r = Random();
            for (var i = 0; i < 50; i++) {
            bars.add(r.nextInt(200));
            }

            runApp(MyApp());
            }

            class MyApp extends StatelessWidget {
            @override
            Widget build(BuildContext context) {
            return MaterialApp(
            home: Home(),
            );
            }
            }

            class Home extends StatefulWidget {
            @override
            State<StatefulWidget> createState() => HomeState();
            }

            class HomeState extends State<Home> {
            static const barWidth = 5.0;
            double bar1Position = 60.0;
            double bar2Position = 180.0;

            @override
            Widget build(BuildContext context) {
            int i = 0;

            return Scaffold(
            body: Center(
            child: Stack(
            alignment: Alignment.centerLeft,
            children: <Widget>[
            Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.start,
            children: bars.map((int height) {
            Color color =
            i >= bar1Position / barWidth && i <= bar2Position / barWidth
            ? Colors.deepPurple
            : Colors.blueGrey;
            i++;

            return Container(
            color: color,
            height: height.toDouble(),
            width: 5.0,
            );
            }).toList(),
            ),
            Bar(
            position: bar2Position,
            callback: (DragUpdateDetails details) {
            setState(() {
            bar2Position += details.delta.dx;
            });
            },
            ),
            Bar(
            position: bar1Position,
            callback: (DragUpdateDetails details) {
            setState(() {
            bar1Position += details.delta.dx;
            });
            },
            ),
            ],
            ),
            ),
            );
            }
            }

            class Bar extends StatelessWidget {
            final double position;
            final GestureDragUpdateCallback callback;

            Bar({this.position, this.callback});

            @override
            Widget build(BuildContext context) {
            return Padding(
            padding: EdgeInsets.only(left: position >= 0.0 ? position : 0.0),
            child: GestureDetector(
            onHorizontalDragUpdate: callback,
            child: Container(
            color: Colors.red,
            height: 200.0,
            width: 5.0,
            ),
            ),
            );
            }
            }





            share|improve this answer

























              up vote
              1
              down vote













              To create a custom range slider, you can use the GestureRecognizer and save the position of each slider in variable inside a StatefulWidget. To decide wether a bar with the index i is inside the range, you can divide the pixel position of the limiter(bar1&bar2 in the source below) by the width of bars and compare it to i.



              Sadly I couldn't work with your code example. Instead I created a bare minimum example as you can see below. If you take a minute to read into, I'm sure you can transfer it to your application.



              Custom Range Slider



              import 'dart:math';

              import 'package:flutter/material.dart';

              List<int> bars = ;

              void main() {
              // generate random bars
              Random r = Random();
              for (var i = 0; i < 50; i++) {
              bars.add(r.nextInt(200));
              }

              runApp(MyApp());
              }

              class MyApp extends StatelessWidget {
              @override
              Widget build(BuildContext context) {
              return MaterialApp(
              home: Home(),
              );
              }
              }

              class Home extends StatefulWidget {
              @override
              State<StatefulWidget> createState() => HomeState();
              }

              class HomeState extends State<Home> {
              static const barWidth = 5.0;
              double bar1Position = 60.0;
              double bar2Position = 180.0;

              @override
              Widget build(BuildContext context) {
              int i = 0;

              return Scaffold(
              body: Center(
              child: Stack(
              alignment: Alignment.centerLeft,
              children: <Widget>[
              Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.start,
              children: bars.map((int height) {
              Color color =
              i >= bar1Position / barWidth && i <= bar2Position / barWidth
              ? Colors.deepPurple
              : Colors.blueGrey;
              i++;

              return Container(
              color: color,
              height: height.toDouble(),
              width: 5.0,
              );
              }).toList(),
              ),
              Bar(
              position: bar2Position,
              callback: (DragUpdateDetails details) {
              setState(() {
              bar2Position += details.delta.dx;
              });
              },
              ),
              Bar(
              position: bar1Position,
              callback: (DragUpdateDetails details) {
              setState(() {
              bar1Position += details.delta.dx;
              });
              },
              ),
              ],
              ),
              ),
              );
              }
              }

              class Bar extends StatelessWidget {
              final double position;
              final GestureDragUpdateCallback callback;

              Bar({this.position, this.callback});

              @override
              Widget build(BuildContext context) {
              return Padding(
              padding: EdgeInsets.only(left: position >= 0.0 ? position : 0.0),
              child: GestureDetector(
              onHorizontalDragUpdate: callback,
              child: Container(
              color: Colors.red,
              height: 200.0,
              width: 5.0,
              ),
              ),
              );
              }
              }





              share|improve this answer























                up vote
                1
                down vote










                up vote
                1
                down vote









                To create a custom range slider, you can use the GestureRecognizer and save the position of each slider in variable inside a StatefulWidget. To decide wether a bar with the index i is inside the range, you can divide the pixel position of the limiter(bar1&bar2 in the source below) by the width of bars and compare it to i.



                Sadly I couldn't work with your code example. Instead I created a bare minimum example as you can see below. If you take a minute to read into, I'm sure you can transfer it to your application.



                Custom Range Slider



                import 'dart:math';

                import 'package:flutter/material.dart';

                List<int> bars = ;

                void main() {
                // generate random bars
                Random r = Random();
                for (var i = 0; i < 50; i++) {
                bars.add(r.nextInt(200));
                }

                runApp(MyApp());
                }

                class MyApp extends StatelessWidget {
                @override
                Widget build(BuildContext context) {
                return MaterialApp(
                home: Home(),
                );
                }
                }

                class Home extends StatefulWidget {
                @override
                State<StatefulWidget> createState() => HomeState();
                }

                class HomeState extends State<Home> {
                static const barWidth = 5.0;
                double bar1Position = 60.0;
                double bar2Position = 180.0;

                @override
                Widget build(BuildContext context) {
                int i = 0;

                return Scaffold(
                body: Center(
                child: Stack(
                alignment: Alignment.centerLeft,
                children: <Widget>[
                Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.start,
                children: bars.map((int height) {
                Color color =
                i >= bar1Position / barWidth && i <= bar2Position / barWidth
                ? Colors.deepPurple
                : Colors.blueGrey;
                i++;

                return Container(
                color: color,
                height: height.toDouble(),
                width: 5.0,
                );
                }).toList(),
                ),
                Bar(
                position: bar2Position,
                callback: (DragUpdateDetails details) {
                setState(() {
                bar2Position += details.delta.dx;
                });
                },
                ),
                Bar(
                position: bar1Position,
                callback: (DragUpdateDetails details) {
                setState(() {
                bar1Position += details.delta.dx;
                });
                },
                ),
                ],
                ),
                ),
                );
                }
                }

                class Bar extends StatelessWidget {
                final double position;
                final GestureDragUpdateCallback callback;

                Bar({this.position, this.callback});

                @override
                Widget build(BuildContext context) {
                return Padding(
                padding: EdgeInsets.only(left: position >= 0.0 ? position : 0.0),
                child: GestureDetector(
                onHorizontalDragUpdate: callback,
                child: Container(
                color: Colors.red,
                height: 200.0,
                width: 5.0,
                ),
                ),
                );
                }
                }





                share|improve this answer












                To create a custom range slider, you can use the GestureRecognizer and save the position of each slider in variable inside a StatefulWidget. To decide wether a bar with the index i is inside the range, you can divide the pixel position of the limiter(bar1&bar2 in the source below) by the width of bars and compare it to i.



                Sadly I couldn't work with your code example. Instead I created a bare minimum example as you can see below. If you take a minute to read into, I'm sure you can transfer it to your application.



                Custom Range Slider



                import 'dart:math';

                import 'package:flutter/material.dart';

                List<int> bars = ;

                void main() {
                // generate random bars
                Random r = Random();
                for (var i = 0; i < 50; i++) {
                bars.add(r.nextInt(200));
                }

                runApp(MyApp());
                }

                class MyApp extends StatelessWidget {
                @override
                Widget build(BuildContext context) {
                return MaterialApp(
                home: Home(),
                );
                }
                }

                class Home extends StatefulWidget {
                @override
                State<StatefulWidget> createState() => HomeState();
                }

                class HomeState extends State<Home> {
                static const barWidth = 5.0;
                double bar1Position = 60.0;
                double bar2Position = 180.0;

                @override
                Widget build(BuildContext context) {
                int i = 0;

                return Scaffold(
                body: Center(
                child: Stack(
                alignment: Alignment.centerLeft,
                children: <Widget>[
                Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.start,
                children: bars.map((int height) {
                Color color =
                i >= bar1Position / barWidth && i <= bar2Position / barWidth
                ? Colors.deepPurple
                : Colors.blueGrey;
                i++;

                return Container(
                color: color,
                height: height.toDouble(),
                width: 5.0,
                );
                }).toList(),
                ),
                Bar(
                position: bar2Position,
                callback: (DragUpdateDetails details) {
                setState(() {
                bar2Position += details.delta.dx;
                });
                },
                ),
                Bar(
                position: bar1Position,
                callback: (DragUpdateDetails details) {
                setState(() {
                bar1Position += details.delta.dx;
                });
                },
                ),
                ],
                ),
                ),
                );
                }
                }

                class Bar extends StatelessWidget {
                final double position;
                final GestureDragUpdateCallback callback;

                Bar({this.position, this.callback});

                @override
                Widget build(BuildContext context) {
                return Padding(
                padding: EdgeInsets.only(left: position >= 0.0 ? position : 0.0),
                child: GestureDetector(
                onHorizontalDragUpdate: callback,
                child: Container(
                color: Colors.red,
                height: 200.0,
                width: 5.0,
                ),
                ),
                );
                }
                }






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 10 at 23:00









                Niklas

                3447




                3447






























                     

                    draft saved


                    draft discarded



















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52987440%2fflutter-custom-range-slider%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Full-time equivalent

                    さくらももこ

                    13 indicted, 8 arrested in Calif. drug cartel investigation