Flutter can be dragged within the specified range and absorb edge components

The existing drag-and-drop components are basically drag-and-drop within the entire screen. This article shows that the drag-and-drop components can only be dragged within the scope of the parent component.

Realize the core: use the onPanUpdate gesture to update the dragging position in real time

import 'dart:ui';
import 'package:flutter/material.dart';

class AppFloatBox extends StatefulWidget {
    double fatherWidth; //父级组件宽度
    double fatherHeight; //父级组件高度
    Widget moveWidget; //可拖动的Widget
    double moveWidgetWidth; //可拖动的Widget宽度
    double moveWidgetHeight; //可拖动的Widget高度
    double offsetX; //初始化X轴
    double offsetY; //初始化Y轴
    Function complete; //可拖动的widgte点击事件
    AppFloatBox({
        @required this.fatherWidth,
        @required this.fatherHeight,
        @required this.moveWidget,
        @required this.moveWidgetWidth,
        @required this.moveWidgetHeight,
        @required this.offsetX,
        @required this.offsetY,
        this.complete
    });

    @override
    _AppFloatBoxState createState() => _AppFloatBoxState(fatherWidth, fatherHeight, moveWidget, moveWidgetWidth, moveWidgetHeight, offsetX, offsetY, complete);
}

class _AppFloatBoxState extends State<AppFloatBox> {
    double fatherWidth;
    double fatherHeight;
    Widget moveWidget;
    double moveWidgetWidth;
    double moveWidgetHeight;
    double offsetX;
    double offsetY;
    Function complete;
    _AppFloatBoxState(this.fatherWidth, this.fatherHeight, this.moveWidget, this.moveWidgetWidth, this.moveWidgetHeight, this.offsetX, this.offsetY, this.complete);

    Offset offset;

    Offset _calOffset(Offset offset, Offset nextOffset) {
        double dx = 0;
        //水平方向偏移量不能小于0不能大于父级组件宽度
        if (offset.dx + nextOffset.dx <= 0) {
            dx = 0;
        } else if (offset.dx + nextOffset.dx >= (fatherWidth - moveWidgetWidth)) {
            dx = fatherWidth - moveWidgetWidth;
        } else {
            dx = offset.dx + nextOffset.dx;
        }
        double dy = 0;
        //垂直方向偏移量不能小于0不能大于父级组件高度
        if (offset.dy + nextOffset.dy >= (fatherHeight - moveWidgetHeight)) {
            dy = fatherHeight - moveWidgetHeight;
        } else if (offset.dy + nextOffset.dy <= 0) {
            dy = 0;
        } else {
            dy = offset.dy + nextOffset.dy;
        }
        return Offset(
            dx,
            dy,
        );
    }

    @override
    void initState() {
        offset = Offset(offsetX, offsetY);
        super.initState();
    }


    @override
    Widget build(BuildContext context) {
        return  Positioned(
            left: offset.dx,
            top: offset.dy,
            child: GestureDetector(
                onPanUpdate: (detail) {
                    setState(() {
                        offset = _calOffset(offset, detail.delta);
                    });
                },
                onTap: (){
                    complete.call();
                },
                onPanEnd: (detail) {
                    setState(() {
                        // 移动位置小于父组件宽度一半,吸边左上角
                        if(offset.dx < fatherWidth / 2 - moveWidgetWidth / 2){
                            offset = Offset(offsetX, offsetY);
                        } else {
                        //移动位置大于父组件宽度一半,吸边右上角
                            offset = Offset(fatherWidth - moveWidgetWidth - offsetX, offsetY);
                        }
                    });
                },
                child: moveWidget
            ),
        );
    }
}

 The encapsulated drag suction edge component can be dragged anywhere within the scope of the parent component, but it only sucks in the upper left and upper right positions. If you need to suck the four corners, you can customize it in onPanEnd.

Guess you like

Origin blog.csdn.net/YML_426/article/details/128718690