flutter:可拖动的widget,使用PointerMoveEvent

一,代码:

import 'package:flutter/material.dart';

class DragPage extends StatefulWidget {
  @override
  State<DragPage> createState() => _DragPageState();
}

class _DragPageState extends State<DragPage>  {
  final GlobalKey _parentKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('拖动例子'),
      ),
      body: Column(
          children: [
             //容器,占用一定高度
             Container(
                color: Colors.orange,
                 height: 100,
             ),
             //下面的容器是被拖动widget可以移动的范围
             Container(
                width: 360,
                height: 360,
                child: Stack(
                   key: _parentKey,
                   children: [
                      Container(color: Colors.teal),   //背景容器
                      //可拖动按钮在这里
                      DraggableFloatingActionButton(
                         child: Container(
                             width: 150,
                             height: 150,
                             decoration: ShapeDecoration(
                                shape: CircleBorder(),
                                color: Colors.red,
                             ),
                             //按钮上的内容
                             child: Center(
                               child:const Text(
                                 '可拖动',
                                 style: const TextStyle(color: Colors.white, fontSize: 24),
                               ),
                             ),
                          ),
                         initialOffset: const Offset(100, 100),
                         parentKey: _parentKey,
                         onPressed: () {     //点击事件
                            print('Button is clicked');
                         },
                      ),
                   ],
               ),
             ),
      ],
      ),
    );
  }
}

//自定义可拖动的按钮
class DraggableFloatingActionButton extends StatefulWidget {
  final Widget child;
  final Offset initialOffset;
  final VoidCallback onPressed;
  final GlobalKey parentKey;

  DraggableFloatingActionButton({
    required this.child,
    required this.initialOffset,
    required this.onPressed,
    required this.parentKey,
  });

  @override
  State<StatefulWidget> createState() => _DraggableFloatingActionButtonState();
}

class _DraggableFloatingActionButtonState extends State<DraggableFloatingActionButton> {
  final GlobalKey _key = GlobalKey();

  bool _isDragging = false;
  late Offset _offset;
  late Offset _minOffset;
  late Offset _maxOffset;

  @override
  void initState() {
    super.initState();
    _offset = widget.initialOffset;

    WidgetsBinding.instance?.addPostFrameCallback(_setBoundary);
  }

  void _setBoundary(_) {
    final RenderBox parentRenderBox =
    widget.parentKey.currentContext?.findRenderObject() as RenderBox;
    final RenderBox renderBox =
    _key.currentContext?.findRenderObject() as RenderBox;

    try {
      final Size parentSize = parentRenderBox.size;
      final Size size = renderBox.size;

      setState(() {
        _minOffset = const Offset(0, 0);
        _maxOffset = Offset(
            parentSize.width - size.width, parentSize.height - size.height);
      });
    } catch (e) {
      print('catch: $e');
    }
  }

  void _updatePosition(PointerMoveEvent pointerMoveEvent) {
    double newOffsetX = _offset.dx + pointerMoveEvent.delta.dx;
    double newOffsetY = _offset.dy + pointerMoveEvent.delta.dy;

    if (newOffsetX < _minOffset.dx) {
      newOffsetX = _minOffset.dx;
    } else if (newOffsetX > _maxOffset.dx) {
      newOffsetX = _maxOffset.dx;
    }

    if (newOffsetY < _minOffset.dy) {
      newOffsetY = _minOffset.dy;
    } else if (newOffsetY > _maxOffset.dy) {
      newOffsetY = _maxOffset.dy;
    }

    setState(() {
      _offset = Offset(newOffsetX, newOffsetY);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      left: _offset.dx,
      top: _offset.dy,
      child: Listener(
        onPointerMove: (PointerMoveEvent pointerMoveEvent) {
          _updatePosition(pointerMoveEvent);

          setState(() {
            _isDragging = true;
          });
        },
        onPointerUp: (PointerUpEvent pointerUpEvent) {
          print('onPointerUp');

          if (_isDragging) {
            setState(() {
              _isDragging = false;
            });
          } else {
            widget.onPressed();
          }
        },
        child: Container(
          key: _key,
          child: widget.child,
        ),
      ),
    );
  }
}

 

二,测试效果:

 

posted @ 2025-04-19 10:49  刘宏缔的架构森林  阅读(25)  评论(0)    收藏  举报