Flutter: Undock the FAB in BottomSheet - flutter

I have read the flutter documentations and I have a specific widget behavior I need to implement. However I wasn't able to reproduce it. I would like to undock the floating action button in the bottom sheet. I thought it would be easy with the use of
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
Unfortunately it only works on the BottomNavigationBar not in the BottomSheet.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Text('loc'),
),
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
appBar: AppBar(title: const Text(_title)),
body: const MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
Scaffold.of(context).showBottomSheet((BuildContext context){
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Modal BottomSheet'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () => Navigator.pop(context),
)
],
),
),
);
},
);
},
),
);
}
}
But my expected result should be the FAB is undocked/floating in the bottom sheet instead of being docked. I don't want to overwork myself for this behavior by making my own implementation of bottom sheet or via gesture widget as much as possible. But if its really necessary I would like some advice or answer in this regards. Thank you and advance.

I have created the widget behavior I wanted. Please refer to the answer in this post. The answer has opened up a lot of new ideas and other flexible implementations.
Move up floating action button
Closing the issue.

Related

Flutter Web: How to reach the changeNotifier from a page on a new tab

I am building a Flutter web app and using Provider package for app state.
I need to open a page (details page) in a new tab on the browser and I can do achieve this with the code below:
onPressed: () {
html.window.open('/#/details', 'new tab');
},
child: const Text('Go to the Details screen'),
),
However, I can not reach the the changeNotifier, which holds the app state, from this new page via context. As far as I understand from the minimal example below, this new tab somehow reaches a new instance of the ChangeNotifier. As a result two tabs are on two separate contexts and reaching two different instances of changeNotifier.
Here is the ChangeNotifier and how I Provide it to the widget tree.
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<AppState>(
create: (context) => AppState(),
child: MaterialApp.router(
routerConfig: _router,
),
);
}
}
class AppState extends ChangeNotifier {
int counter = 0;
void increment() {
counter++;
notifyListeners();
}
}
HomePage:
class HomeScreen extends StatelessWidget {
/// Constructs a [HomeScreen]
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Screen')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
html.window.open('/#/details', 'new tab');
},
child: const Text('Go to the Details screen'),
),
Text(context.watch<AppState>().counter.toString())
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<AppState>().increment();
},
child: const Icon(Icons.add),
),
);
}
}
DetailsPage:
class DetailsScreen extends StatelessWidget {
const DetailsScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Details Screen')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => context.go('/'),
child: const Text('Go back to the Home screen'),
),
Text(context.watch<AppState>().counter.toString())
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<AppState>().increment();
},
child: const Icon(Icons.add),
),
);
}
}
I also tried to inject the already existing instance of AppState via constructor, ==> DetailsPage(state: appState). However this also does not work.

Flutter: hide navbar when drawer is open

I followed this tutorial on how to create a bottom navbar and it works great apart from the fact that I dont know how to appropriately add a drawer.
Currently my code looks something like this for the screen that holds the navigational bar:
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async =>
!await navigatorKeys[currentTab].currentState.maybePop(),
child: Scaffold(
body: Stack(children: <Widget>[
_buildOffstageNavigator(TabItem.red),
_buildOffstageNavigator(TabItem.green),
_buildOffstageNavigator(TabItem.blue),
]),
bottomNavigationBar: BottomNavigation(
currentTab: currentTab,
onSelectTab: _selectTab,
),
),
);
}
And like this for my home screen:
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
endDrawer: const NavigationDrawerWidget(),
body: const _HomePageBody(),
);
}
}
All of this is functioning, however, the drawer does not hide the navigational bar when its opened. I have thought about placing the drawer instead on the screen that holds the but that introduces more problems than it fixes. Such as the hamburger icon does not appear unless I also add an appbar to the said screen and I only want it to be present on the homepage and not its "subpages" (pages that I can access through the homepage but are not the pages present on the navbar).
My next thought is that I could possibly hide the navbar when the drawer opens and reveal it when the drawer is closed again. But then there is the difficulty of animating in such a way to make it look nice and seems like a long winded solution.
At this point it seems like the navbar is the problem but I have tried redoing it so many times such that the end result would be a bar that is present on all pages (+ subpages) and saves state that it would be unfortunate to change it up again.
I would appreciate any suggestions or links to other projects/tutorials that are doing something similar. Thanks :)
Edit
here is a reproducible example, I wipped it up quite quickly so sorry for it being a bit messy
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int pageIndex = 0;
final pages = [
const Page(
title: "page 1",
drawer: true,
),
const Page(
title: "page 2",
drawer: false,
),
const Page(
title: "page 3",
drawer: false,
),
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: pages[pageIndex],
bottomNavigationBar: Container(
color: Theme.of(context).primaryColor,
height: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
onPressed: () {
setState(() {
pageIndex = 0;
});
},
icon: const Icon(
Icons.home_outlined,
),
),
IconButton(
onPressed: () {
setState(() {
pageIndex = 1;
});
},
icon: const Icon(
Icons.work_outline_outlined,
),
),
IconButton(
onPressed: () {
setState(() {
pageIndex = 2;
});
},
icon: const Icon(
Icons.widgets_outlined,
),
),
],
),
),
);
}
}
class Page extends StatelessWidget {
const Page({Key? key, required this.title, required this.drawer})
: super(key: key);
final String title;
final bool drawer;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
endDrawer: drawer ? const Drawer() : null,
body: Center(
child: Text(
title,
style: const TextStyle(
fontSize: 45,
fontWeight: FontWeight.w500,
),
),
),
);
}
}
I think you can use single scaffold and include your drawer and appBar on 1st scaffold.
return Scaffold(
endDrawer: pageIndex == 0 ? const Drawer() : null,
body: pages[pageIndex],
appBar: AppBar(),
bottomNavigationBar: Container(

How to Make half screen like google assistant in flutter

Like this half screen
How can I achieve it in flutter? Please guide me in making this
many thanks for considering my request.
These are called bottom sheets. Please try the code below.
Bottom Sheet
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Modal BottomSheet'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () => Navigator.pop(context),
)
],
),
),
);
},
);
},
),
);
}
}

Flutter: How to Auto-Fit Text Inside (Expanded) Floating Action Button?

Let's say in Flutter you have:
return Row(
children: [
Expanded(
child: FloatingActionButton(
onPressed: () {},
child: Text(myObject.unknownUntilRunTimeText),
),
),
Expanded(
child: FloatingActionButton(
onPressed: () {},
child: Text(myObject.unknownUntilRunTimeText),
),
),
],
);
How do you make sure that text auto-fits (shrinks, presumably) to fit the button?
I tried to use FittedBox, but what it appears is happening in this case is that the FABS effective width is larger than the FAB (due to the expansion in a row, presumably)... and so even if you resize the text, it is still too large:
The vertical scribbles indicate where I assume Flutter is considering where the edges are.
Use FittedBox.
Example
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: Center(
child: Container(),
),
floatingActionButton: FloatingActionButton(
onPressed:(){},
child: FittedBox(
child: Text("Your text")
),
),
),
);
}
}
You can use FloatingActionButtom.extended()

How can i make full menu come out while mouse hover in the AppBar in flutter?

This is what I am trying to achieve:
I've thought about onHover in MouseRegion widget and trying to see if this code works in body part.
I was going to implement this in AppBar in scaffold after i see this works in body part but i couldn't.
Does anyone know correct way?
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: Center(
child: MyStatefulWidget(),
),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
showMenus(BuildContext context) async {
await showMenu(
context: context,
position: RelativeRect.fromLTRB(100, 100, 100, 100),
items: [
PopupMenuItem(
child: Text("View"),
),
PopupMenuItem(
child: Text("Edit"),
),
PopupMenuItem(
child: Text("Delete"),
),
],
);
}
#override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints.tight(Size(300.0, 200.0)),
child: MouseRegion(
onHover: showMenus(context),
child: Container(
color: Colors.lightBlueAccent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have entered or exited this box this many times:'),
],
),
),
),
);
}
}
Your only problem is incorrectly invoking the method.
On your MouseRegion onHover it should have a () => before invoking the method:
// the onHover event gives you an event object
onHover: (event) => showMenus(context),