Draggable FloatingActionButton in Flutter - dart

I want to make a draggable floating button and if possible to print the drag position in the console.

Due to the ability to compose Flutter widgets in whatever way you want to, you can simply do it like this:
Draggable(
feedback: FloatingActionButton(child: Icon(Icons.drag_handle), onPressed: () {}),
child: FloatingActionButton(child: Icon(Icons.drag_handle), onPressed: () {}),
childWhenDragging: Container(),
onDragEnd: (details) => print(details.offset))
This Draggable can be passed as the floatingActionButton argument to a Scaffold.
The feedback parameter controls how the widget that is dragged about in the end will look like and child specifies how the stationary Draggable should look like. As you probably only want to see one FloatingActionButton at a time, you can pass an empty Container to childWhenDragging.
The Offset (position) of the drag will be printed to the console when releasing the drag.

I needed to add a positioned widget to set the position of my button
class _MyHomePageState extends State<MyHomePage> {
Offset position =Offset(20.0, 20.0);
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Stack(
children: <Widget>[
Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("data_repo/img/bg1.jpg"),
fit: BoxFit.cover,
),
),
),
Positioned(
left : position.dx,
top : position.dy ,
child : Draggable(
feedback: Container(
child : FloatingActionButton(child: Icon(Icons.add), onPressed: () {})
),
child: Container(
child : FloatingActionButton(child: Icon(Icons.add), onPressed: () {}),
),
childWhenDragging: Container(),
onDragEnd: (details){
setState(() {
position = details.offset;
});
print(position);
print(position.dx);
print(position.dy);
}))
],
));
}
}

You can use the DraggableFloatingButton package: https://pub.dartlang.org/packages/draggable_floating_button

Related

How expand text and container according text size?

I'm trying to create a card with a text within a container but I would like to show only a part of the text and when the user click on "show more", show the rest. I saw a Widget to construct text like this here, but I need expand the card container either and I don't know how to do that because I need to know how many lines the text have to expand with the correctly size. Exists a way to calculate the size according the number of lines or characters?
I tried to create the card as follows, where the DescriptionText is the Widget on the link and specify a minHeight in the Container in the hope of expanding the container along with the text but did not work.
Widget _showAnswerCard(Answer answer, User user) {
return Card(
elevation: 3.0,
color: Theme.of(context).backgroundColor,
child: Container(
constraints: BoxConstraints(minHeight: 90),
padding: EdgeInsets.all(10.0),
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(flex: 1, child: _showUserAvatar(answer)),
Expanded(flex: 3, child: _showAnswerDetails(answer, user)),
],
),
));
}
Widget _showAnswerDetails(Answer answer, User user) {
return Flex(
direction: Axis.vertical,
children: <Widget>[
Expanded(
flex: 3,
child: DescriptionTextWidget(text: answer.content),
),
Expanded(
flex: 1,
child: _showAnswerOptions(),
)
],
);
}
I'll really appreciate if someone could help me with that.
Just use Wrap widget to wrap your Card widget.
Based on your link for suggested answer. I did change to use Wrap widget.
Jus do copy/paste below code and check.
import 'package:flutter/material.dart';
class ProductDetailPage extends StatelessWidget {
final String description =
"Flutter is Google’s mobile UI framework for crafting high-quality native interfaces on iOS and Android in record time. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.";
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text("Demo App"),
),
body: new Container(
child: new DescriptionTextWidget(text: description),
),
);
}
}
class DescriptionTextWidget extends StatefulWidget {
final String text;
DescriptionTextWidget({#required this.text});
#override
_DescriptionTextWidgetState createState() =>
new _DescriptionTextWidgetState();
}
class _DescriptionTextWidgetState extends State<DescriptionTextWidget> {
bool flag = true;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Wrap(
children: <Widget>[
Card(
margin: EdgeInsets.all(8),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
child: Column(
children: <Widget>[
Container(
child: Text(
widget.text,
overflow: flag ? TextOverflow.ellipsis : null,
style: TextStyle(
fontSize: 15,
),
),
),
InkWell(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
flag ? "show more" : "show less",
style: new TextStyle(color: Colors.blue),
),
],
),
onTap: () {
setState(() {
flag = !flag;
});
},
),
],
)),
),
],
);
}
}
Result:
The solution I can think of is to use two labels, one for displaying only one line of text and one for displaying all the text. When the button is clicked, the two labels are alternately displayed in an animated manner. There is no computer at the moment, it is not convenient to verify, I hope to give you some help in the implementation of the program.

flutter : Get Local position of Gesture Detector

I have problems to get real local position on gesture detector widget using pan update.
new Center(
child new Container(
height: 150.0,
width: 150.0,
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(5.0),
color: Colors.white,
),
child: new GestureDetector(
onPanUpdate: (details) => onPanUpdate(context, details),
child: new CustomPaint(
painter: new MyPainter(
points: points,
limitBottom:height - 125.0,
limitTop: 10.0,
limitLeft: 5.0,
limitRight: width - 55.0
),
),
),
),
)
when I print the the Offset of global position && local position, I've got same value for both of them. in Result it was painted outside of my Container widget. Is there anything I missed to get local position?
I assume you're using something like this to get the local position:
RenderBox getBox = context.findRenderObject();
var local = getBox.globalToLocal(start.globalPosition);
The reason you'd be getting the wrong offset after doing that has to do with the context you're using to find the local position.
If you're using the overall widget's context, essentially what you're doing is calculating the offset within the overall widget. i.e.
YourWidget <-- context
Center
Container
GestureDetector
...
Let's say that the screen looks something like this:
1__________________________
| | <--- YourWidget
| 2_________ |
| | gesture | |
| | detector| |
| | 3. | |
| |_________| |
| |
|__________________________|
With 1 being the top left of your overall widget (and the screen), 2 being the top left of your gesture detector, and 3 being the point where you tap.
By using the context of YourWidget, you're calculating the position of the tap based on the difference between 1 and 3. If 1 happens to be at the top left of the screen, the result will match the global coordinates.
By using the context for your gesture detector, you'd instead be measuring the distance between 2 and 3, which will give you the offset you want.
There's two ways to fix this - either you can wrap your GestureDetector in a Builder widget, or you can create a new Stateful/Stateless widget that encapsulates just the GestureDetector. I'd personally recommend creating a new widget.
I was having a problem with my "tap position" being offset. I believe it was the same issue mentioned above. I was able to solve this similar problem by reading about keys and finding the location/size of widgets here:
https://medium.com/#diegoveloper/flutter-widget-size-and-position-b0a9ffed9407
So I didn't have to create another widget or layout builder as mentioned above, but I was able to just add a global key and then grab the position of the tap by doing the following with "currentContext" that comes from the key. Very cool!
void _handleLongPress(LongPressStartDetails details) {
final RenderBox referenceBox = _keyRink.currentContext.findRenderObject();
var x = referenceBox.globalToLocal(details.globalPosition);
if (x == tapPosition) {
Vibration.vibrate(duration: 50);
setState(() {
_shots[_homeShotCount] = tapPosition;
});
}
}
Here was my main scaffold where you can see the spot I added the key.
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GestureDetector(
key: _keyRink,
onTapDown: _getTapPosition,
onLongPressStart: _handleLongPress,
child: Stack(
children: <Widget>[
AnimatedOpacity(
duration: Duration(milliseconds: 2500),
opacity: _rinkOpacity,
child: Center(
child: Image.asset('assets/rink.png',
width: size.width, height: size.height, fit: BoxFit.fill),
),
),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Transform.rotate(
angle: animationRotate.value,
child: Transform.scale(
scale: animationDrop.value,
child: FlatButton(
onPressed: null,
padding: EdgeInsets.all(0.0),
child: Image.asset('assets/puck.png'))),
)
],
),
),
CustomPaint(
painter: ShapesPainter(),
child: FractionallySizedBox(heightFactor: 1.0,widthFactor: 1.0,),
),
],
),
),
drawer: Drawer(
child: drawerItems,
),
);
}
Wrapping it with a StatelessWidget works fine for me, thanks to #rmtmckenzie
Here my code:
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(),
body: _Foo(),
);
}
}
class _Foo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GestureDetector(
onLongPressDragStart: (details) => _onLongPressDragStart(details, context),
onLongPressDragUpdate: (details) => _onLongPressDragUpdate(details, context),
onLongPressDragUp: (details) => _onLongPressDragUp(details, context),
child: FlareActor(
"assets/test.flr",
alignment: Alignment.center,
fit: BoxFit.contain,
),
);
}
void _onLongPressDragStart(GestureLongPressDragStartDetails details, BuildContext context) {
print('_onLongPressDragStart details: ${details.globalPosition}');
}
void _onLongPressDragUpdate(GestureLongPressDragUpdateDetails details, BuildContext context) {
var localTouchPosition = (context.findRenderObject() as RenderBox).globalToLocal(details.globalPosition);
print('_onLongPressDragUpdate details: ${details.globalPosition} - localTouchPosition: $localTouchPosition');
}
void _onLongPressDragUp(GestureLongPressDragUpDetails details, BuildContext context) {
print('_onLongPressDragUp details: ${details.globalPosition}');
}
}
The important things happen in the _Foo class.
You can get the local position of a GestureDetector using the DragUpdateDetails.localPosition
GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
print('onPanUpdate');
print(details.localPosition);
},
)

Flutter: Banner Ad Overlapping The Main Screen

I am doing a Flutter app and managed to show the AdMob banner ad, however the ad overlaps the bottom of my app's main screen:
By following this article, I managed to make the app screen's bottom properly displayed, but the persistentFooterButtons is sacrificed, which I think is not an ideal solution.
I am thinking about putting the Scaffold object and a fixed height area into a column that is contained by a Center object, something similar to the following:
#override
Widget build(BuildContext context) {
return new Center(
child: new Column (
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Expanded (
child: _getScaffold(),
),
new Expanded (
child: new Container(height: 50.0,)
)
],
),
);
}
But in this way I get the exception "A RenderFlex overflowed by 228 pixels on the bottom":
Anybody can show me how to build such layout? I want every component of my scaffold properly displayed, with a fixed height dummy footer that is ok to be overlapped by the Admob's banner ad.
Any help is much welcome.
Jimmy
Also we can add some trick like bottomNavigationBar under the Scaffold
bottomNavigationBar: Container(
height: 50.0,
color: Colors.white,
),
This will take floating button up.
Finally I got it:
#override
Widget build(BuildContext context) {
return new Center(
child: new Column (
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Expanded (
child: _getScaffold(),
),
new Container(height: 50.0,
child: new Placeholder(color:Colors.blue))
],
),
);
}
The trick is Expanded here is for the Scaffold only, but for the dummy footer just a fixed height Container is required. Now I can display everything available from the Scaffold object.
Layout building of Flutter sometimes really confuses me...
If I understand your question well, I think you want to have your ad shown from the bottom while using a FAB. I think using a Stack widget here is a good solution, I created this example in a rush but should be enough to show you what I mean:
class AdBar extends StatefulWidget {
#override
_AdBarState createState() => new _AdBarState();
}
class _AdBarState extends State<AdBar> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
body: new ListView(
children: new List.generate(50, (int index) {
return new Text("widgets$index");
}),
),
persistentFooterButtons:
<Widget>[
new Stack(
children: <Widget>[
new Container (
color: Colors.transparent,
child: new Material(
color: Colors.cyanAccent,
child: new InkWell(
onTap: () {
},
child: new Container(
//color: Colors.cyanAccent,
width: MediaQuery
.of(context)
.size
.width * 0.90,
height: MediaQuery
.of(context)
.size
.height * 0.25,
),
),),),
new Positioned(
right: 0.0,
child: new FloatingActionButton(
onPressed: () {}, child: new Icon(Icons.fastfood)))
],
)
]
);
}
}

How to limit scroll distance in a scroll view in Flutter?

I've made a page that contains several textfields and buttons in a column which is contained in a container that has a background image. And this container is itself the child of a scrollview widget.
So when a person clicks on one of the fields, their keyboard will pop up (taking a portion of the screen), which means some buttons/fields are offscreen, which is where the scrollview widget serves its purpose.
The problem here is that I want to limit how far the scroll view allows a user to scroll.
There are some blank space under the lowest button, and I don't want the user to be able to scroll all the way there. This is too keep the experience simple and not have the user "overscroll" past the fields he should be typing in.
But since the background image is part of the scroll view the view will allow a user to scroll as far down as the bottom of the image. I want to limit this.
As a follow-up I'm trying to figure out how to set an initial scroll position. (So that when clicking on a field the scroll view scrolls down to very first text field, so all fields are in view. without the user needing to scroll down to them. However I don't want this scroll position to be re-applied every time the user clicks on a field, of course.)
Here is the relevant (if any of my code looks really bad please say so, I'm new to programming in general and accept any advice to improve):
class LoginPageConstructor extends StatelessWidget {
#override
Widget build(BuildContext context) {
AssetImage loginBackgroundAsset =
new AssetImage("assets/loginscreen/backgroundrock.png");
// var _scrollController = new ScrollController(
// initialScrollOffset: 200.0,
// keepScrollOffset: true);
return new Scaffold(
body: new Container(
child: new ListView(key: new PageStorageKey("Divider 1"),
// controller: _scrollController,
children: <Widget>[
new Stack(children: <Widget>[
new Container(
constraints: new BoxConstraints.expand(height: 640.0),
decoration: new BoxDecoration(
image: new DecorationImage(
image: loginBackgroundAsset, fit: BoxFit.cover)),
child: new Column(
children: <Widget>[
new Divider(height: 300.0,),
new Center(child: new UsernameText(),),
new Divider(height: 8.0,),
new Center(child: new PasswordText(),),
new Divider(),
new LoginButton(),
new Divider(),
new SignUpButton(),
],
))
])
],
),
));
}
}
For auto-scrolling the fields into view, it sounds like you are wrestling with issue 10826. I posted a workaround on that issue. I adapted the workaround to your sample code; see below. (You may want to tweak it a little.)
If you want to prevent users from scrolling, you might want to just ensure that all the fields are visible using the same techniques below and then use a NeverScrollableScrollPhysics as the physics of the ListView. Or if you're feeling ambitious you could implement a custom scroll physics as shown in the Gallery example. If I were you I'd hold out for #10826 to be fixed, though.
import 'package:meta/meta.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(new MaterialApp(home: new LoginPage()));
}
/// A widget that ensures it is always visible when focused.
class EnsureVisibleWhenFocused extends StatefulWidget {
const EnsureVisibleWhenFocused({
Key key,
#required this.child,
#required this.focusNode,
this.curve: Curves.ease,
this.duration: const Duration(milliseconds: 100),
}) : super(key: key);
/// The node we will monitor to determine if the child is focused
final FocusNode focusNode;
/// The child widget that we are wrapping
final Widget child;
/// The curve we will use to scroll ourselves into view.
///
/// Defaults to Curves.ease.
final Curve curve;
/// The duration we will use to scroll ourselves into view
///
/// Defaults to 100 milliseconds.
final Duration duration;
EnsureVisibleWhenFocusedState createState() => new EnsureVisibleWhenFocusedState();
}
class EnsureVisibleWhenFocusedState extends State<EnsureVisibleWhenFocused> {
#override
void initState() {
super.initState();
widget.focusNode.addListener(_ensureVisible);
}
#override
void dispose() {
super.dispose();
widget.focusNode.removeListener(_ensureVisible);
}
Future<Null> _ensureVisible() async {
// Wait for the keyboard to come into view
// TODO: position doesn't seem to notify listeners when metrics change,
// perhaps a NotificationListener around the scrollable could avoid
// the need insert a delay here.
await new Future.delayed(const Duration(milliseconds: 600));
if (!widget.focusNode.hasFocus)
return;
final RenderObject object = context.findRenderObject();
final RenderAbstractViewport viewport = RenderAbstractViewport.of(object);
assert(viewport != null);
ScrollableState scrollableState = Scrollable.of(context);
assert(scrollableState != null);
ScrollPosition position = scrollableState.position;
double alignment;
if (position.pixels > viewport.getOffsetToReveal(object, 0.0)) {
// Move down to the top of the viewport
alignment = 0.0;
} else if (position.pixels < viewport.getOffsetToReveal(object, 1.0)) {
// Move up to the bottom of the viewport
alignment = 1.0;
} else {
// No scrolling is necessary to reveal the child
return;
}
position.ensureVisible(
object,
alignment: alignment,
duration: widget.duration,
curve: widget.curve,
);
}
Widget build(BuildContext context) => widget.child;
}
class LoginPage extends StatefulWidget {
LoginPageState createState() => new LoginPageState();
}
class LoginPageState extends State<LoginPage> {
FocusNode _usernameFocusNode = new FocusNode();
FocusNode _passwordFocusNode = new FocusNode();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Example App'),
),
body: new Container(
child: new ListView(
physics: new NeverScrollableScrollPhysics(),
key: new PageStorageKey("Divider 1"),
children: <Widget>[
new Container(
constraints: new BoxConstraints.expand(height: 640.0),
decoration: new BoxDecoration(
image: new DecorationImage(
image: new NetworkImage(
'https://flutter.io/images/flutter-mark-square-100.png',
),
fit: BoxFit.cover,
),
),
child: new Column(
children: <Widget>[
new Container(
height: 300.0,
),
new Center(
child: new EnsureVisibleWhenFocused(
focusNode: _usernameFocusNode,
child: new TextFormField(
focusNode: _usernameFocusNode,
decoration: new InputDecoration(
labelText: 'Username',
),
),
),
),
new Container(height: 8.0),
new Center(
child: new EnsureVisibleWhenFocused(
focusNode: _passwordFocusNode,
child: new TextFormField(
focusNode: _passwordFocusNode,
obscureText: true,
decoration: new InputDecoration(
labelText: 'Password',
),
),
),
),
new Container(),
new RaisedButton(
onPressed: () {},
child: new Text('Log in'),
),
new Divider(),
new RaisedButton(
onPressed: () {},
child: new Text('Sign up'),
),
],
),
),
],
),
),
);
}
}

Flutter - FloatingActionButton in the center

Is it possible to make the FloatingActionButton in the centre instead of the right side?
import 'package:flutter/material.dart';
import 'number.dart';
import 'keyboard.dart';
class ContaPage extends StatelessWidget {
#override
Widget build(BuildContext context) => new Scaffold(
body: new Column(
children: <Widget>[
new Number(),
new Keyboard(),
],
),
floatingActionButton: new FloatingActionButton(
elevation: 0.0,
child: new Icon(Icons.check),
backgroundColor: new Color(0xFFE57373),
onPressed: (){}
)
);
}
I don't know if this was added since this question was first answered, but there's now floatingActionButtonLocation property on the Scaffold class.
It would work like this in your original question:
class ContaPage extends StatelessWidget {
#override
Widget build(BuildContext context) => new Scaffold(
// ...
floatingActionButton: new FloatingActionButton(
// ...FloatingActionButton properties...
),
// Here's the new attribute:
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
Also see the documentation:
Scaffold class (search floatingActionButtonLocation): https://docs.flutter.dev/flutter/material/Scaffold-class.html
...and the FloatingActionButtonLocation class: https://docs.flutter.dev/flutter/material/FloatingActionButtonLocation-class.html
With the new flutter API you do that very easily just change the floatingActionButtonLocation property in the Scaffold to
FloatingActionButtonLocation.centerFloat
Example :
return new Scaffold(
floatingActionButton: new FloatingActionButton(
child: const Icon(Icons.add),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
bottomNavigationBar: new BottomAppBar(
color: Colors.white,
child: new Row(...),
),
);
Use the Property floatingActionButtonLocation of scaffold class.
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
Full Example:
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: HomePage()
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(child: Center(child: Text('Hello World')),),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.camera, color: Colors.white, size: 29,),
backgroundColor: Colors.black,
tooltip: 'Capture Picture',
elevation: 5,
splashColor: Colors.grey,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
Use this property with floatingActionButtonLocation property in Scaffold.
FloatingActionButton Flutter - More Details
Try wrapping it in a Center widget or use a crossAxisAlignment of CrossAxisAlignment.center on your Column.
You should pick one part of your Column to be wrapped in a Flexible that will collapse to avoid overflow, or replace some or all of it with a ListView so users can scroll to see the parts that are hidden.
You can use Container and Align widgets as below:
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Center(
),
floatingActionButton: Container(
padding: EdgeInsets.only(bottom: 100.0),
child: Align(
alignment: Alignment.bottomCenter,
child: FloatingActionButton.extended(
onPressed: _getPhoneAuthResult,
icon: Icon(Icons.phone_android),
label: Text("Authenticate using Phone"),
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
Align(
alignment: Alignment.center,
child: Container(
child: FloatingActionButton(
hoverColor: Colors.black,
elevation: 10,
onPressed: () {},
backgroundColor: Colors.pink,
child: Icon(Icons.add,),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
),
),
),
Here I used "Align" widget to make the FloatingActionButton center. You can see it here.
after end of the floating action button widget, you can Use floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
For Example
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
File _image;
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
title: "Camera App",
home: Scaffold(
appBar: AppBar(
title: Text("Camera App"),
),
body: Center(
child: Center(
child: _image == null
? Text('No image selected.')
: Image.file(_image,
alignment: Alignment.topLeft,
),
),
),
floatingActionButton: FloatingActionButton(
elevation: 50,
hoverColor: Colors.red,
autofocus: true,
onPressed: () {
imagepicker();
},
child: Icon(Icons.camera_alt),
tooltip: 'Pick Image',
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
),
);
}
Future imagepicker() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = image;
});
}
}
The above examples are great, but if you want to have full control over the exact location of the floating action button, you should wrap your FloatingActionButton widget with Align widget and use Alignment(x axis, y axis) to set the exact location.
Align(
alignment: Alignment(0.0, 0.8),
//control the location by changing the numbers here to anything between 1 and -1
child: FloatingActionButton()
)
By changing the logic to use crossAxisAlignment, the mainAxisAlignment and the Flexible the FloatingActionButton were centered at the bottom of the screen
import 'package:flutter/material.dart';
import 'number.dart';
import 'keyboard.dart';
class ContaPage extends StatelessWidget {
#override
Widget build(BuildContext context) => new Scaffold(
body: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Number(),
new Keyboard(),
new Flexible(
child: new Container(
padding: new EdgeInsets.only(bottom: 16.0),
child: new FloatingActionButton(
elevation: 0.0,
child: new Icon(Icons.check),
backgroundColor: new Color(0xFFE57373),
onPressed: (){}
)
)
)
],
),
);
}
For more freedom of alignment and more than 2 FAB use Stack
Stack(
children: <Widget>[
Center(
child: Center(
child: _image == null
? Text('No image selected.')
: Image.file(_image,
alignment: Alignment.topLeft,
),
),
),
Align(
alignment: Alignment.centerLeft,
child: new FloatingActionButton(
child: const Icon(Icons.skip_previous),
onPressed: () {
}),
),
Align(
alignment: Alignment.centerRight,
child: new FloatingActionButton(
child: const Icon(Icons.skip_next),
onPressed: () {
}),
),
],
)
I modified the code, now the button is in the bottom center but I do not know if it will always stay in the bottom, regardless of the size of the screen.
import 'package:flutter/material.dart';
import 'number.dart';
import 'keyboard.dart';
class ContaPage extends StatelessWidget {
#override
Widget build(BuildContext context) => new Scaffold(
body: new Column(
children: <Widget>[
new Number(),
new Keyboard(),
new Stack(
alignment: new FractionalOffset(0.5, 1.0),
children: <Widget>[
new FloatingActionButton(
elevation: 0.0,
child: new Icon(Icons.check),
backgroundColor: new Color(0xFFE57373),
onPressed: (){}
)
],
)
],
),
);
}
Since Scaffold.floatingActionButton just asks for a Widget, you can wrap your FloatingActionButton with the standard classes for more control if the Scaffold.floatingActionButtonLocation property isn't enough (which already gives you many standard placements, that can also play nicely with your appBar or bottomNavigationBar).
Container is a classic component, but a little overkill given that it combines a variety of widgets.
As others mentioned, Align is handy when you want to position relative to the Align widget itself (which if unconstrained fills to its parent). It can take a variety of preset Alignment constants, or use the Alignment constructor to specify your own relative position, e.g. Alignment(0.0, 0.0) represents the center of the rectangle, (1,1) the bottom right corner, and (-1,-1) the upper left. However, the parent of your FAB is influenced by the Scaffold's floatingActionButtonLocation:, so one way to help take it into account is by setting it to FloatingActionButtonLocation.centerDocked, which when used with Align lets you think about positioning relative to the screen's center.
But maybe you like the basic positioning provided by floatingActionButtonLocation, but just want to shift the FAB by a known number of logical pixels, e.g. to compensate for other widgets on the screen. In that case wrapping in a Padding with the appropriate EdgeInsets should work fine.
Depending on your design simply you can use persistentFooterButtons which accepts a list of widgets as children.
just like here for an example:
persistentFooterButtons: [
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
child: Align(
alignment: Alignment.center,
child: FloatingActionButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => InstallationPage()),);
},
child: new Icon(Icons.add, color: SysColors.ICON_COLOR, size: 34.w,),
),
),
],
)
],

Resources