Flutter: How to set boundaries for a Draggable widget? Flutter: How to set boundaries for a Draggable widget? flutter flutter

Flutter: How to set boundaries for a Draggable widget?


Try this. I tweaked this from: Constraining Draggable area .

  ValueNotifier<List<double>> posValueListener = ValueNotifier([0.0, 0.0]);  ValueChanged<List<double>> posValueChanged;  double _horizontalPos = 0.0;  double _verticalPos = 0.0;  @override  void initState() {    super.initState();      posValueListener.addListener(() {      if (posValueChanged != null) {        posValueChanged(posValueListener.value);      }    });  }  @override  Widget build(BuildContext context) {   return Scaffold(      body: Stack(        children: <Widget>[           _buildDraggable(),        ]));  }    _buildDraggable() {    return SafeArea(      child: Container(        margin: EdgeInsets.only(bottom: 100),        color: Colors.green,        child: Builder(          builder: (context) {            final handle = GestureDetector(                onPanUpdate: (details) {                  _verticalPos =                      (_verticalPos + details.delta.dy / (context.size.height))                          .clamp(.0, 1.0);                  _horizontalPos =                      (_horizontalPos + details.delta.dx / (context.size.width))                          .clamp(.0, 1.0);                  posValueListener.value = [_horizontalPos, _verticalPos];                },                child: Container(                  child: Container(                    margin: EdgeInsets.all(12),                    width: 110.0,                    height: 170.0,                    child: Container(                      color: Colors.black87,                    ),                    decoration: BoxDecoration(color: Colors.black54),                  ),                ));            return ValueListenableBuilder<List<double>>(              valueListenable: posValueListener,              builder:                  (BuildContext context, List<double> value, Widget child) {                return Align(                  alignment: Alignment(value[0] * 2 - 1, value[1] * 2 - 1),                  child: handle,                );              },            );          },        ),      ),    );  }


I've found a workaround for this issue. It's not exactly the output I was looking for but I thought this could be useful to somebody else.

Instead of trying to control the drag object during dragging, I just let it go outside of my screen and I placed it back to its original position in case it goes outside of the screen.

Just a quick note if someone tries my code, I forgot to mention that I'm trying to develop a game for the web. The output on a mobile device might be a little bit odd!

import 'package:flutter/material.dart';void main() { runApp(MyApp());}class MyApp extends StatelessWidget {  @override  Widget build(BuildContext context) {    return MaterialApp(      title: 'Draggable Test',      home: GamePlay(),    );  }}class GamePlay extends StatelessWidget {  @override  Widget build(BuildContext context) {    return Scaffold(      body: Stack(        children: <Widget>[          Row(            children: [              Container(                width: 360,                height: 400,                decoration: BoxDecoration(                  color: Colors.lightGreen,                  border: Border.all(                    color: Colors.green,                    width: 2.0,                  ),                ),              ),              Container(                width: 190,                height: 400,                decoration: BoxDecoration(                  color: Colors.white,                  border: Border.all(                    color: Colors.purple,                    width: 2.0,                  ),                ),              ),            ],          ),          DragObject(              key: GlobalKey(),              initPos: Offset(365, 0.0),              id: 'Item 1',              itmColor: Colors.orange),          DragObject(            key: GlobalKey(),            initPos: Offset(450, 0.0),            id: 'Item 2',            itmColor: Colors.pink,          ),        ],      ),    );  }}class DragObject extends StatefulWidget {  final String id;  final Offset initPos;  final Color itmColor;  DragObject({Key key, this.id, this.initPos, this.itmColor}) : super(key: key);  @override  _DragObjectState createState() => _DragObjectState();}class _DragObjectState extends State<DragObject> {  GlobalKey _key;  Offset position;  Offset posOffset = Offset(0.0, 0.0);  @override  void initState() {    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);    _key = widget.key;    position = widget.initPos;    super.initState();  }  void _getRenderOffsets() {    final RenderBox renderBoxWidget = _key.currentContext.findRenderObject();    final offset = renderBoxWidget.localToGlobal(Offset.zero);    posOffset = offset - position;  }  void _afterLayout(_) {    _getRenderOffsets();  }  @override  Widget build(BuildContext context) {    return Positioned(      left: position.dx,      top: position.dy,      child: Listener(        child: Draggable(          child: Container(            width: 80,            height: 80,            color: widget.itmColor,          ),          feedback: Container(            width: 82,            height: 82,            color: widget.itmColor,          ),          childWhenDragging: Container(),          onDragEnd: (drag) {            setState(() {              if (drag.offset.dx > 0) {                position = drag.offset - posOffset;              } else {                position = widget.initPos;              }            });          },        ),      ),    );  }}

I'm still interested if someone can find a proper solution to the initial issue :-)