美文网首页
Flutter 全局可拖拽悬浮控件

Flutter 全局可拖拽悬浮控件

作者: 旺仔_100 | 来源:发表于2023-09-17 20:09 被阅读0次
    背景:项目中需要做一个可拖拽悬浮控件,松手后悬停到对应的两边。
    效果:似乎不能放视频,我放两张图片。红色的是可以拖动的控件。
    image.png image.png
    主要思路:
    • 通过创建OverlayManagerMixin对Overlay进行创建和销毁管理
    • DragHoverBothSidesWidget中通过GestureDetector的拖拽回调实时更新控件的x和y轴的距离。
    代码实现
    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    
    ///统一管理唯一Overlay
    mixin OverlayManagerMixin<T extends StatefulWidget> on State<T> {
      bool _overlayEntryInserted = false;
      OverlayState? _overlayState;
      OverlayEntry _overlayEntry = OverlayEntry(
        builder: (_) => const SizedBox.shrink(),
      );
    
      @override
      void initState() {
        super.initState();
        _overlayState = Overlay.of(context);
      }
    
      void injectOverlay(Widget widget, double width, double height) {
        if (_overlayEntryInserted) {
          debugPrint("overlay 没有销毁,不允许重复插入");
          return;
        }
        _overlayEntry = OverlayEntry(builder: (_) {
          return Material(
            type: MaterialType.transparency,
            child: DragHoverBothSidesWidget(widget, width, height),
          );
        });
        _overlayState?.insert(_overlayEntry);
        _overlayEntryInserted = true;
      }
    
      void removeOverlay() {
        // Call `remove` only when the entry has been inserted.
        if (_overlayEntryInserted) {
          _overlayEntry.remove();
          _overlayEntryInserted = false;
        }
      }
    }
    
    ///创建一个可以拖拽悬停两边控件
    class DragHoverBothSidesWidget extends StatefulWidget {
      Widget child;
    
      ///可拖拽控件的宽高
      double height;
      double width;
      double bottomDistance;
    
      DragHoverBothSidesWidget(this.child, this.width, this.height, {Key? key, this.bottomDistance = 68}) : super(key: key);
    
      @override
      State<StatefulWidget> createState() {
        return DragHoverBothSidesState();
      }
    }
    
    final double ratio = WidgetsBinding.instance.window.devicePixelRatio;
    
    class DragHoverBothSidesState extends State<DragHoverBothSidesWidget> {
      double _dx = 0;
      double _dy = 0;
      final Size _windowSize = WidgetsBinding.instance.window.physicalSize / ratio;
    
      @override
      void initState() {
        super.initState();
        _dx = _windowSize.width - widget.width;
        _dy = _windowSize.height - widget.height - widget.bottomDistance;
      }
    
      void dragEnd(DragEndDetails details) {
        if (_dx + widget.width / 2 < _windowSize.width / 2) {
          _dx = 0;
        } else {
          _dx = _windowSize.width - widget.width;
        }
        if (_dy + widget.height > _windowSize.height) {
          _dy = _windowSize.height - widget.height - widget.bottomDistance;
        } else if (_dy < 0) {
          _dy = 0;
        }
        setState(() {});
      }
    
      void dragEvent(DragUpdateDetails details) {
        _dx = details.globalPosition.dx - widget.width / 2;
        _dy = details.globalPosition.dy - widget.height / 2;
        setState(() {});
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          width: _windowSize.width,
          height: _windowSize.height,
          // color: Colors.green,
          child: Stack(
            alignment: Alignment.center,
            children: [Positioned(left: _dx, top: _dy, child: GestureDetector(onVerticalDragEnd: dragEnd, onHorizontalDragEnd: dragEnd, onHorizontalDragUpdate: dragEvent, onVerticalDragUpdate: dragEvent, child: widget.child))],
          ),
        );
      }
    }
    
    

    相关文章

      网友评论

          本文标题:Flutter 全局可拖拽悬浮控件

          本文链接:https://www.haomeiwen.com/subject/vvpwvdtx.html