6

Flutter 可拖动的悬浮动作按钮

 3 years ago
source link: https://segmentfault.com/a/1190000040526994
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

https://medium.com/flutterdev...

Flutter 允许您使用 FloatingActionButton 小部件添加一个浮动操作按钮。尽管如此,它不允许你拖动按钮。考虑一下你需要让它可拖动的可能性。本文有一个模型,它公开了制作一个浮动操作按钮需要做的事情,这个按钮可以在屏幕的任何地方拖动,只要它在父窗口小部件中。

在这个博客中,我们将探索 Flutter 的拖动浮动按钮。我们将看到如何实现一个演示程序的拖曳浮动行动按钮,并显示如何创建您的 Flutter 应用程序。

下面的演示视频显示了如何创建一个可拖动的漂浮动作按钮在 Flutter。它显示了如何拖动浮动行动按钮将在您的 Flutter 应用程序的工作。它显示当代码成功运行时,用户将一个浮动操作按钮拖动到屏幕周围的任何地方,只要它在父窗口小部件中。它会显示在你的设备上。

如何实现 dart 文件中的代码

你需要分别在你的代码中实现它:

在 lib 文件夹中创建一个名为 main.dart 的新 dart 文件。

首先,我们将创建一个 Globalkey,并将其命名为 _parentKey

final GlobalKey _parentKey = GlobalKey();

在正文中,我们将添加一个具有高度和宽度的 Container 小部件。它是子属性,我们将添加 Stack 小部件。在这个小部件中,我们将添加一个键、文本和一个 DraggableFloatingActionButton ()。在按钮内部,我们将添加一个具有高度和宽度的容器。在其子属性中添加图像。此外,我们还将添加 initialOffset、父键和 onPressed。我们将深入定义下面的代码。

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: () {},
      ),
    ],
  ),
)

创建一个名为 draggable_floating_action_button.dart 的代码文件。

我们将为这样的小部件创建一个类。我们需要处理的主要问题是使按钮在指针之后可拖动的能力。可以使用的小部件之一是监听器,它可以识别指针移动事件并给出移动细节。基本上,按钮应该作为侦听器的子级进行包装。

Listener 小部件具有 onPointerMove 争用,可以利用该争用来传递一个回调,该回调在指针移动时将被考虑。回调函数应该有一个边界 PointerMoveEvent,其中包含 x 和 y 标题中的开发增量(增量)。Dx 和 delta。).捕获物的偏移量应该通过移动三角洲来刷新。

下面是制作可拖动浮动操作按钮的类。它有几个争论,包括子,initialOffset,和 onPressed。子小部件是利用依赖于当前偏移量的定位小部件交付的。此外,它还被包装为监听器小部件的子部件。此外,还有一个策略 _updatePosition ,根据移动的增量刷新当前的偏移量。

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

您需要向父部件添加一个键,并将其传递给 DraggableFloatingActionButton 部件。您可以从 currentContext 属性中获得 RenderBox,该属性具有 findRenderObject 策略。然后,在这一点上,您可以从 RenderBox 的 size 属性获得父级的大小。您应该谨慎,因为应该在构建树之后调用 findRenderObject 技术。随后,您需要利用 WidgetsBinding 的 addPostFrameCallback 来调用它。

技术的 _updatePosition 也应该改变。如果新的偏移量小于最小偏移量,则该值必须设置为最小偏移量。如果新的偏移量比最大偏移量更值得注意,则该值必须设置为最大偏移量。对于 x 轴和 y 轴都需要这样做。

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

当我们运行应用程序时,我们应该得到屏幕的输出,就像下面的屏幕截图一样。

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: () {},
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

在这篇文章中,我已经解释了可拖动浮动按钮的基本结构,您可以根据自己的选择修改这个代码。这是一个小的介绍可拖动浮动操作按钮对用户交互从我这边,它的工作使用 Flutter。

我希望这个博客将提供给您充分的信息,尝试在您的 Flutter 项目的拖曳浮动行动按钮。我们将向您展示介绍是什么?.这就是在 Flutter 制作一个可拖动的浮动按钮的方法。从根本上讲,您可以利用 Listener 小部件来区分指针移动事件,并根据开发增量更新按钮偏移量。监听器小部件同样支持区分指针事件,除非按钮最近被拖动,否则应该在这些事件上执行按钮的活动。同样,您需要获得父按钮和按钮的大小,以防止按钮超出父按钮的范围。所以请尝试一下。


GetX Quick Start

https://github.com/ducafecat/...

新闻客户端

https://github.com/ducafecat/...

strapi 手册译文

https://getstrapi.cn

微信讨论群 ducafecat

https://ducafecat.tech/catego...

https://ducafecat.tech/catego...

Dart 编程语言基础

https://space.bilibili.com/40...

Flutter 零基础入门

https://space.bilibili.com/40...

Flutter 实战从零开始 新闻客户端

https://space.bilibili.com/40...

Flutter 组件开发

https://space.bilibili.com/40...

Flutter Bloc

https://space.bilibili.com/40...

Flutter Getx4

https://space.bilibili.com/40...

Docker Yapi

https://space.bilibili.com/40...


Recommend

  • 121
    • www.cocoachina.com 7 years ago
    • Cache

    悬浮按钮设计规范和经典实践

  • 147

    PHP+Javascript实现拖动滑块完成拼图验证码

  • 59
    • 掘金 juejin.im 5 years ago
    • Cache

    Flutter 仿掘金推特点赞按钮

    like_button 做这个按钮的起因是,产品突然说要改一下点赞效果,像下面这样。 但是我心中的审美不是这样的,不可以,坚决不行。 想起来群花拉面写过一个用Flutter实现一个仿Twitter的点赞效果. 看了下代码, 站在大佬们的肩膀 jd-alex

  • 8

    Apple - @Bananana - 13late 是我第一款 Mac,当时被三指拖动深深震惊了,居然触摸板能这么好用。然后某一年 Apple 开始向 Mac 推 3d touch 后,就默认把三指拖动给关了,而且藏在了很难找的地方。然鹅

  • 15
    • www.bugcatt.com 4 years ago
    • Cache

    Flutter 禁用按钮/禁止按钮点击

    需具备的条件 若要顺利阅读本篇文章, 需要你具备如下条件: 本篇文章的环境: 环境版本Windows10Android Studio3.5Flutter1.19.0-2.0.pre一定要注意环境的差异, 考虑不兼容的可能性; 并且具备以上条件. 否则阅读本篇...

  • 8

    在实际项目开发中, 我们在进行页面跳转时, 偶尔会跳到不可返回的页面(比如退出登录后). 本篇文章就来记录下 Flutter 如何隐藏/移除导航栏的默认返回按钮. 有图有真相, 先来看下实际效果: 移除导航栏的默认返回按钮适用于:

  • 7
    • segmentfault.com 3 years ago
    • Cache

    Flutter 自定义单选按钮

    Flutter 自定义单选按钮h...

  • 12

    【Flutter 专题】89 图解基本 Overlay 悬浮新手引导 #yyds干货盘点# 推荐 原创       随着业务的扩展和延伸,需要的功能...

  • 3

    MAUI,跨平台的 GUI 框架,基本介绍本文不再赘述。 话不多说,既然可以跨平台,那么我们就来实现一个在移动端很常用的控件:悬浮操作按钮(FAB,Floating Action Button)。 本文属于新手向、保姆级教程,大佬们请一笑而过。 相信看完...

  • 8

    我们在app的开发过程中经常会用到一些表示进度类的动画效果,比如一个下载按钮,我们希望按钮能够动态显示下载的进度,这样可以给用户一些直观的印象,那么在flutter中一个下载按钮的动画应该如何制作呢? 一起来看看吧。 定义下载的状态 我...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK