original

https://medium.com/flutterdevs/draggable-floating-action-button-in-flutter-2149a7e47f06

refer to

text

Flutter allows you to add a floating action button using the FloatingActionButton widget. Nevertheless, it does not allow you to drag the button. Consider the possibility that you need to make it draggable. This article has a model that exposes what needs to be done to make a floating action button. This button can be dragged anywhere on the screen as long as it is in the parent widget.

In this blog, we will explore Flutter's drag floating button. We will see how to implement a drag-and-drop action button for a demo program and show how to create your Flutter application.

Introduction

The following demo video shows how to create a draggable floating action button in Flutter. It shows how dragging the floating action button will work in your Flutter application. It shows that when the code runs successfully, the user drags a floating action button anywhere around the screen, as long as it is in the parent widget. It will be displayed on your device.

How to implement the code in the dart file

You need to implement it in your code separately:

Create a new dart file named main.dart in the lib folder.

First, we will create a Globalkey and name it _parentKey

final GlobalKey _parentKey = GlobalKey();

In the body, we will add a Container widget with height and width. It is a sub-attribute and we will add the Stack widget. In this widget, we will add a key, text, and a DraggableFloatingActionButton (). Inside the button, we will add a container with height and width. Add images in its sub-attributes. In addition, we will add initialOffset, parent key, and onPressed. We will define the following code in depth.

Container(
  width: 300,
  height: 300,
  child: Stack(
    key: _parentKey,
    children: [
      Container(color: Colors.cyan),
      Center(
        child: const Text(
          "FlutterDev's.com",
          style: const TextStyle(color: Colors.white, fontSize: 24),
        ),
      ),
      DraggableFloatingActionButton(
        child: Container(
          width: 60,
          height: 60,
          decoration: ShapeDecoration(
            shape: CircleBorder(),
            color: Colors.white,
          ),
          child: Image.asset("assets/logo.png"),
        ),
        initialOffset: const Offset(120, 70),
        parentKey: _parentKey,
        onPressed: () {},
      ),
    ],
  ),
)
Create a code file draggable_floating_action_button.dart

We will create a class for such widgets. The main issue we need to deal with is the ability to make the button draggable behind the pointer. One of the widgets that can be used is a listener, which can recognize pointer movement events and give movement details. Basically, the button should be wrapped as a child of the listener.

The Listener widget has onPointerMove contention, which can be used to pass a callback that will be considered when the pointer moves. The callback function should have a boundary PointerMoveEvent , which contains the development increment (increment) in the x and y titles. Dx and delta. ). The offset of the catch should be refreshed by moving the delta.

The following is a class for making draggable floating operation buttons. It has several arguments, including sub, initialOffset, and onPressed. The child widgets are delivered using positioning widgets that depend on the current offset. In addition, it is also packaged as a sub-component of the listener widget. In addition, there is a strategy _updatePosition to refresh the current offset according to the increment of movement.

class DraggableFloatingActionButton extends StatefulWidget {

  final Widget child;
  final Offset initialOffset;
  final VoidCallback onPressed;

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

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

class _DraggableFloatingActionButtonState extends State<DraggableFloatingActionButton> {

  bool _isDragging = false;
  late Offset _offset;

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

  void _updatePosition(PointerMoveEvent pointerMoveEvent) {
    double newOffsetX = _offset.dx + pointerMoveEvent.delta.dx;
    double newOffsetY = _offset.dy + pointerMoveEvent.delta.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: widget.child,
      ),
    );
  }
}

You need to add a key to the parent widget and pass it to the DraggableFloatingActionButton widget. You can get the RenderBox from the currentContext property, which has a findRenderObject strategy. Then, at this point, you can get the size of the parent from the size property of the RenderBox. You should be cautious because the findRenderObject technique should be called after building the tree. Later, you need to use the addPostFrameCallback of WidgetsBinding to call it.

The technology of _updatePosition should also be changed. If the new offset is less than the minimum offset, the value must be set to the minimum offset. If the new offset is more noteworthy than the maximum offset, the value must be set to the maximum offset. This is required for both the x-axis and y-axis.

class DraggableFloatingActionButton extends StatefulWidget {

  final Widget child;
  final Offset initialOffset;
  final VoidCallback onPressed;

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

  @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,
        ),
      ),
    );
  }
}

When we run the application, we should get the output of the screen, just like the screenshot below.

All codes

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_draggable_floating/draggable_floating_action_button.dart';
import 'package:flutter_draggable_floating/splash_screen.dart';

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

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Splash(),
    );
  }
}

class DraggableFloatingActionButtonDemo extends StatelessWidget {

  final GlobalKey _parentKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        title: const Text('Flutter Draggable Floating Action Button'),
        backgroundColor: Colors.cyan,
      ),
      body: Column(
        children: [
          Container(
            height: 150,
          ),
          Container(
            width: 300,
            height: 300,
            child: Stack(
              key: _parentKey,
              children: [
                Container(color: Colors.cyan),
                Center(
                  child: const Text(
                    "FlutterDev's.com",
                    style: const TextStyle(color: Colors.white, fontSize: 24),
                  ),
                ),
                DraggableFloatingActionButton(
                  child: Container(
                    width: 60,
                    height: 60,
                    decoration: ShapeDecoration(
                      shape: CircleBorder(),
                      color: Colors.white,
                    ),
                    child: Image.asset("assets/logo.png"),
                  ),
                  initialOffset: const Offset(120, 70),
                  parentKey: _parentKey,
                  onPressed: () {},
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

Concluding remarks

In this article, I have explained the basic structure of the draggable floating button, you can modify this code according to your choice. This is a small introduction to draggable floating operation buttons for user interaction. From my side, it works using Flutter.

I hope this blog will provide you with sufficient information, try to drag the floating action button in your Flutter project. We will show you what the introduction is? This is how to make a draggable floating button in Flutter. Fundamentally, you can use the Listener widget to distinguish pointer movement events and update the button offset based on the development increment. The listener widget also supports distinguishing pointer events. Unless the button has been dragged recently, the button's activity should be performed on these events. Similarly, you need to obtain the parent button and the size of the button to prevent the button from exceeding the scope of the parent button. So please try it.


© Cat brother

Past

Open source

GetX Quick Start

https://github.com/ducafecat/getx_quick_start

News client

https://github.com/ducafecat/flutter_learn_news

strapi manual translation

https://getstrapi.cn

WeChat discussion group ducafecat

Series collection

Translation

https://ducafecat.tech/categories/%E8%AF%91%E6%96%87/

Open source project

https://ducafecat.tech/categories/%E5%BC%80%E6%BA%90/

Dart programming language basics

https://space.bilibili.com/404904528/channel/detail?cid=111585

Getting started with Flutter zero foundation

https://space.bilibili.com/404904528/channel/detail?cid=123470

Flutter actual combat from scratch news client

https://space.bilibili.com/404904528/channel/detail?cid=106755

Flutter component development

https://space.bilibili.com/404904528/channel/detail?cid=144262

Flutter Bloc

https://space.bilibili.com/404904528/channel/detail?cid=177519

Flutter Getx4

https://space.bilibili.com/404904528/channel/detail?cid=177514

Docker Yapi

https://space.bilibili.com/404904528/channel/detail?cid=130578


独立开发者_猫哥
669 声望129 粉丝