Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constraining Draggable area

Tags:

flutter

dart

I'm attempting to create a draggable slider-like widget (like a confirm slider). My question is if there is a way to constrain the draggable area?

import 'package:flutter/material.dart';

import 'confirmation_slider.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        body: new ListView(
          children: <Widget>[
            new Container(
              margin: EdgeInsets.only(
                top: 50.0
              ),
            ),

            new Container(
              margin: EdgeInsets.only(
                left: 50.0,
                right: 50.0
              ),
              child: new Draggable(
                axis: Axis.horizontal,
                child: new FlutterLogo(size: 50.0),
                feedback: new FlutterLogo(size: 50.0),
              ),

              height: 50.0,
              color: Colors.green
            ),
          ],
        ),
      ),
    );
  }
}

I imagined that the container class would constrain the draggable area, but it doesn't appear to do that.

like image 263
Valdemar Avatar asked Jul 06 '18 19:07

Valdemar


1 Answers

No. That's not the goal of Draggable widget. Instead, use a GestureDetector to detect drag. Then combine it with something like Align to move your content around

Here's a fully working slider based on your current code.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Slider(),
        ),
      ),
    );
  }
}

class Slider extends StatefulWidget {
  final ValueChanged<double> valueChanged;

  Slider({this.valueChanged});

  @override
  SliderState createState() {
    return new SliderState();
  }
}

class SliderState extends State<Slider> {
  ValueNotifier<double> valueListener = ValueNotifier(.0);

  @override
  void initState() {
    valueListener.addListener(notifyParent);
    super.initState();
  }

  void notifyParent() {
    if (widget.valueChanged != null) {
      widget.valueChanged(valueListener.value);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      height: 50.0,
      padding: EdgeInsets.symmetric(horizontal: 40.0),
      child: Builder(
        builder: (context) {
          final handle = GestureDetector(
            onHorizontalDragUpdate: (details) {
              valueListener.value = (valueListener.value +
                      details.delta.dx / context.size.width)
                  .clamp(.0, 1.0);
            },
            child: FlutterLogo(size: 50.0),
          );

          return AnimatedBuilder(
            animation: valueListener,
            builder: (context, child) {
              return Align(
                alignment: Alignment(valueListener.value * 2 - 1, .5),
                child: child,
              );
            },
            child: handle,
          );
        },
      ),
    );
  }
}
like image 172
Rémi Rousselet Avatar answered Nov 03 '22 13:11

Rémi Rousselet