Flutterexperts

Empowering Vision with FlutterExperts' Expertise
Draggable Floating Action Button In Flutter

Flutter permits you to add a floating action button utilizing the FloatingActionButton widget. Nonetheless, it doesn’t permit you to drag the button. Consider the possibility that you need to make it draggable. This article has a model that discloses what you need to do to make a floating action button that can be hauled anyplace around the screen as long as it’s inside the parent widget.

In this blog, we will explore the Draggable Floating Action Button In Flutter. We will see how to implement a demo program of the draggable floating action button and show how to create it in your flutter applications.

Table Of Contents::

Introduction

Code Implement

Code File

Conclusion



Introduction:

The below demo video shows how to create a draggable floating action button in a flutter. It shows how the draggable floating action button will work in your flutter applications. It shows when the code successfully runs, then the user dragged a floating action button anywhere around the screen as long as it’s within the parent widget. It will be shown on your devices.

Demo Module :

How to implement code in dart file :

You need to implement it in your code respectively:

Create a new dart file called main.dart inside the lib folder.

First, we will create a Globalkey and name it called _parentKey

final GlobalKey _parentKey = GlobalKey();

In the body, we will add a Container widget with height and width. It’s child property, 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 image on its child property. Also, we will add initialOffset, parent key, and onPressed. We will deeply define the below code.

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 new dart file called draggable_floating_action_button.dart inside the lib folder.

We will make a class for such a widget. The main thing we need to deal with is the capacity to make the button draggable after the pointer. One of the widgets that can be utilized is Listener, which can identify pointer move events and give the movement detail. Essentially, the button should be wrapped as the child of a Listener.

The Listener widget has onPointerMove the contention which can be utilized to pass a callback that will be considered when the pointer is moving. The callback function should have a boundary PointerMoveEvent that contains the development delta in x and y headings (delta. dx and delta. dy). The offset of the catch should be refreshed by the movement delta.

The following is the class for making draggable floating action buttons. It has a few contentions which incorporate child, initialOffset, and onPressed. The child widget is delivered utilizing Positioned the widget dependent on the current offset. It’s additionally wrapped as the child of a Listener widget. There’s additionally a strategy _updatePosition that refreshes the current offset dependent on the movement delta.

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. From the key, you can get the RenderBox from the currentContext property, which has findRenderObject a strategy. Then, at that 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 the tree is built. Subsequently, you need to summon it utilizing addPostFrameCallback of WidgetsBinding.

The _updatePosition the technique should be changed as well. On the off chance that the new offset is lower than the minimum offset, the value must be set to the minimum offset. On the off chance that the new offset is more noteworthy than the maximum offset, the value must be set to the most maximum offset. You need to do that for both x and y axes.

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 ought to get the screen’s output like the underneath screen capture.

Final Output

Code File:

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

Conclusion:

In the article, I have explained the basic structure of the Draggable Floating Action Button in a flutter; you can modify this code according to your choice. This was a small introduction to Draggable Floating Action Button On User Interaction from my side, and it’s working using Flutter.

I hope this blog will provide you with sufficient information on Trying up the Draggable Floating Action Button in your flutter projectsWe will show you what the Introduction is?. That is the way to make a draggable floating action button in Flutter. Fundamentally, you can utilize Listener the widget to distinguish pointer move events and update the button offset dependent on the development delta. The Listener widget likewise upholds distinguishing pointer-up events at which the button’s activity ought to be performed except if it has recently been dragged. You likewise need to get the size of the parent and the button to keep the button from being out of the parent’s box. So please try it.

❤ ❤ Thanks for reading this article ❤❤

If I got something wrong? Let me know in the comments. I would love to improve.

Clap 👏 If this article helps you.


Feel free to connect with us:
And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! You can connect with us on FacebookGitHubTwitter, and LinkedIn for any flutter-related queries.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.


Leave comment

Your email address will not be published. Required fields are marked with *.