Can FlutterLogo be made to stretch-to-fill? - dart

I would like to display a large FlutterLogo in my app:
https://docs.flutter.io/flutter/material/FlutterLogo-class.html
In order to account for varying screen sizes I would like to make it stretch-to fill. Is that possible? Or do I need to use a MediaQuery to determine the parent's size and pass that into FlutterLogo(size:)?
My current code:
Widget build(BuildContext context) {
return new Center(
child: new FlutterLogo(size: 800.0, style: FlutterLogoStyle.horizontal, textColor: Colors.white),
);
}

You can accomplish this with a ConstrainedBox:
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData.dark(),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text('Example App')),
body: new ConstrainedBox(
constraints: new BoxConstraints.expand(),
child: new FlutterLogo(
style: FlutterLogoStyle.horizontal,
textColor: Colors.white,
),
),
);
}
}

I believe I have answered a similar question
How to stretch an icon to fill parent?
https://docs.flutter.io/flutter/widgets/Expanded-class.html
https://groups.google.com/forum/#!msg/flutter-dev/lsgdU1yl7xc/0pYS2qrzBQAJ
https://docs.flutter.io/flutter/widgets/FittedBox-class.html
https://docs.flutter.io/flutter/painting/BoxFit-class.html
new Expanded(
child: new FittedBox(
fit: BoxFit.fill,
child: new FlutterLogo( style: FlutterLogoStyle.horizontal, textColor: Colors.white),
),
),
I feel kinda strange. Looking at the OP profile ID, I wonder if I answer the question correctly.
I hope this helps.
used this code to run it
import 'package:flutter/material.dart';
class MyAppBar extends StatelessWidget {
MyAppBar({this.title});
// Fields in a Widget subclass are always marked "final".
final Widget title;
#override
Widget build(BuildContext context) {
return new Container(
height: 56.0, // in logical pixels
padding: const EdgeInsets.symmetric(horizontal: 8.0),
decoration: new BoxDecoration(color: Colors.blue[500]),
// Row is a horizontal, linear layout.
child: new Row(
// <Widget> is the type of items in the list.
children: <Widget>[
new IconButton(
icon: new Icon(Icons.menu),
tooltip: 'Navigation menu',
onPressed: null, // null disables the button
),
// Expanded expands its child to fill the available space.
new Expanded(
child: title,
),
new IconButton(
icon: new Icon(Icons.search),
tooltip: 'Search',
onPressed: null,
),
],
),
);
}
}
class MyScaffold extends StatelessWidget {
#override
Widget build(BuildContext context) {
// Material is a conceptual piece of paper on which the UI appears.
return new Material(
// Column is a vertical, linear layout.
child: new Column(
children: <Widget>[
new MyAppBar(
title: new Text(
'Example title',
style: Theme.of(context).primaryTextTheme.title,
),
),
new Expanded(
child: new FittedBox(
fit: BoxFit.fill,
child: new FlutterLogo( style: FlutterLogoStyle.horizontal, textColor: Colors.white),
),
),
],
),
);
}
}
void main() {
runApp(new MaterialApp(
title: 'My app', // used by the OS task switcher
home: new MyScaffold(),
));
}
edit: I posted complete code just for darky, since I forgot to mention that expanded needs to be wrapped into row, column, or flex container to expand

Related

Flutter FlatButton does not show tap animation / ripple effect

I have the following code:
return new ListTile(
leading: new CircleAvatar(
backgroundColor: Colors.blue,
child: new Image.network(
"http://res.cloudinary.com/kennyy/image/upload/v1531317427/avatar_z1rc6f.png")),
title: new Row(
children: <Widget>[
new Expanded(child: new Text(message)),
new FlatButton(onPressed: null, child: new Text("Delete"))
]
),
subtitle: new Text(from),
);
which created a tile in my ListView.
Each tile should have a button.
When I tap the button - I don't see any ripple effect or animation that I actually clicked. I was pretty sure it's a part of the Material theme as a gesture for FlatButtons, but I tried a solution I found, using InkWell:
return new ListTile(
leading: new CircleAvatar(
backgroundColor: Colors.blue,
child: new Image.network(
"http://res.cloudinary.com/kennyy/image/upload/v1531317427/avatar_z1rc6f.png")),
title: new Row(
children: <Widget>[
new Expanded(child: new Text(message)),
InkWell(
child: FlatButton(onPressed: null, child: new Text("Delete"), color: Colors.amber))
]
),
subtitle: new Text(from),
);
But still - my listview button does not have any ripple effect when tapped.
Any idea?
Flutter buttons are disabled by default. To enable a button, set its onPressed or onLongPress properties to a non-null value.
The ripple is not visible because you've set the property of your onPressed to null.
new FlatButton(onPressed: null, child: new Text("Delete"))
Change the onPressed property to something like this:
new FlatButton(onPressed: (){}, child: new Text("Delete"))
To compare here is an example of a no-null onPressed and a null valued onPressed.
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 MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListTile(
leading: new CircleAvatar(
backgroundColor: Colors.blue,
child: new Image.network(
"http://res.cloudinary.com/kennyy/image/upload/v1531317427/avatar_z1rc6f.png")),
title: new Row(children: <Widget>[
//new Expanded(child: new Text(message)),
new TextButton(
onPressed: () {},
child: new Text("Delete"),
),
new TextButton(
onPressed: null,
child: new Text("Delete"),
)
]),
//subtitle: new Text(from),
),
);
}
}
*Note that the FlatButton is now deprecated so I've used TextButton in the example.

Persisting AppBar Drawer across all Pages Flutter

I am trying to create a uniform drawer that is accessible across all pages in my app. How do I make it persist throughout all these pages without having to recreate my custom Drawer widget in every single dart file?
There are a few different options for this. The most basic is hopefully something you've already done, but I'll list it anyways:
1: Create a class for your drawer
Your widget should be its own stateful or stateless widget. This way, you just have to instantiate it each time.
class MyDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(...);
}
}
And then when using it in each page:
Scaffold(
drawer: MyDrawer(...),
...
)
I hope you're already doing this; if not you should be. A class's build function shouldn't be too large or it can lead to poor performance and harder to maintain code; splitting things into logical units will help you in the long run.
2: Create a class for your scaffold
If having to include the same drawer in a scaffold for each page is still too much code, you can instead use a class that encapsulates your scaffold. It would essentially take inputs for each of the scaffold inputs you actually use.
class MyScaffold extends StatelessWidget {
final Widget body;
MyScaffold({this.body});
#override
Widget build(BuildContext context) {
return Scaffold(
body: body,
drawer: MyDrawer(...),
);
}
}
And then instead of using Scaffold in your code, use MyScaffold (but please name it something better =D).
3: Multi level scaffold
I'm only including this way of doing it to be complete, and I don't recommend it. That being said, there are certain things you can't get to work within flutter's normal workflow that you could do by doing this - for example if you want a custom animation for when the user taps on different items in the drawer.
Basically, what you'd do in this case is to have a Scaffold outside of your MaterialApp or Navigator (which I believe would also mean you'd have to have another Navigator outside that, but I'm not 100% sure). You would have the scaffold that's outside your navigation show the drawer while the other one (on each page within the navigation) would do whatever else you need it to do. There's a few caveats - you'd have to make sure you get the right scaffold (i.e. Scaffold.of(context) by itself wouldn't cut it - you'd have to get the context of the first scaffold and use it to find the higher-level one), and you'd probably need to pass a GlobalKey (of the lower-level scaffold) to the Drawer so that it could actually change pages within it.
As I said, I don't recommend this approach, so I'm not going to go into any more detail than that but rather leave it as an exercise for the reader if they want to go down that rabbit hole!
rmtmckenzie is very correct.
Although if you are curious about the multi scaffold solution, this can be more elegant than you think.
To share a drawer between all pages we could add a builder in our MaterialApp instance.
This will instantiate a Scaffold under Navigator but above all routes.
MaterialApp(
title: 'Flutter Demo',
builder: (context, child) {
return Scaffold(
drawer: MyDrawer(),
body: child,
);
},
home: MyHome()
)
Inside your page, you can instantiate another Scaffold without restriction as you'd usually do.
You can then show the shared drawer by doing the following in any widget under MaterialApp :
final ScaffoldState scaffoldState = context.rootAncestorStateOfType(TypeMatcher<ScaffoldState>());
scaffoldState.openDrawer();
Code which you can extract into a nice helper :
class RootScaffold {
static openDrawer(BuildContext context) {
final ScaffoldState scaffoldState =
context.rootAncestorStateOfType(TypeMatcher<ScaffoldState>());
scaffoldState.openDrawer();
}
}
Then reuse using RootScaffold.openDrawer(context)
In Addition to #Rémi Rousselet Answer
MaterialApp(
title: 'Flutter Demo',
builder: (context, child) {
return Scaffold(
drawer: MyDrawer(),
body: child,
);
},
home: MyHome()
)
For Navigation in root drawer if you use Navigator.of(context) // push or pop that will throw error and for that you must use child widget to navigate to different pages
Like that
(child.key as GlobalKey<NavigatorState>).currentState // push or pop
Demo project in Github
if somebody looking for fancy stuff while navigating look here. What I use as a drawer for my project is flutter_inner_drawer package.
I created a stateful class named CustomDrawer.
class CustomDrawer extends StatefulWidget {
final Widget scaffold;
final GlobalKey<InnerDrawerState> innerDrawerKey;
CustomDrawer({
Key key,
this.scaffold,
this.innerDrawerKey,
}) : super(key: key);
#override
_CustomDrawerState createState() => _CustomDrawerState();
}
class _CustomDrawerState extends State<CustomDrawer> {
MainPageIcons assets = MainPageIcons();//From my actual code dont care it
final vars = GlobalVars.shared; //From my actual code dont care it
#override
Widget build(BuildContext context) {
return InnerDrawer(
key: widget.innerDrawerKey,
onTapClose: true, // default false
tapScaffoldEnabled: true,
swipe: true, // default true
colorTransition: Colors.teal, // default Color.black54
//innerDrawerCallback: (a) => print(a ),// return bool
leftOffset: 0.2, // default 0.4
leftScale: 1,// default 1
boxShadow: [
BoxShadow(color: Colors.teal,blurRadius: 20.0, // has the effect of softening the shadow
spreadRadius: 10.0, // has the effect of extending the shadow
offset: Offset(
10.0, // horizontal, move right 10
10.0, // vertical, move down 10
),)],
borderRadius: 20, // default 0
leftAnimationType: InnerDrawerAnimation.quadratic, // default static
//when a pointer that is in contact with the screen and moves to the right or left
onDragUpdate: (double val, InnerDrawerDirection direction) =>
setState(() => _dragUpdate = val),
//innerDrawerCallback: (a) => print(a),
// innerDrawerCallback: (a) => print(a), // return true (open) or false (close)
leftChild: menus(), // required if rightChild is not set
scaffold:widget.scaffold
);
}
double _dragUpdate = 0;
Widget menus(){
return
Material(
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
ColorTween(
begin: Colors.blueAccent,
end: Colors.blueGrey[400].withRed(100),
).lerp(_dragUpdate),
ColorTween(
begin: Colors.green,
end: Colors.blueGrey[800].withGreen(80),
).lerp(_dragUpdate),
],
),
),
child: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 30),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 10, bottom: 15),
width: 80,
child: ClipRRect(
child: Image.network(
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrWfWLnxIT5TnuE-JViLzLuro9IID2d7QEc2sRPTRoGWpgJV75",
),
borderRadius: BorderRadius.circular(60),
),
),
Text(
"User",
style: TextStyle(color: Colors.white, fontSize: 18),
)
],
//mainAxisAlignment: MainAxisAlignment.center,
),
Padding(
padding: EdgeInsets.all(10),
),
ListTile(
onTap: ()=>navigate(Profile.tag),
title: Text(
"Profile",
style: TextStyle(color: Colors.white, fontSize: 14),
),
leading: Icon(
Icons.dashboard,
color: Colors.white,
size: 22,
),
),
ListTile(
title: Text(
"Camera",
style: TextStyle(fontSize: 14,color:Colors.white),
),
leading: Icon(
Icons.camera,
size: 22,
color: Colors.white,
),
onTap: ()=>navigate(Camera.tag)
),
ListTile(
title: Text(
"Pharmacies",
style: TextStyle(fontSize: 14,color:Colors.white),
),
leading: Icon(
Icons.add_to_photos,
size: 22,
color: Colors.white,
),
onTap: ()=>navigate(Pharmacies.tag)
),
],
),
),
Positioned(
bottom: 20,
child: Container(
alignment: Alignment.bottomLeft,
margin: EdgeInsets.only(top: 50),
padding: EdgeInsets.symmetric(vertical: 15, horizontal: 25),
width: double.maxFinite,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(
Icons.all_out,
size: 18,
color: Colors.grey,
),
Text(
" LogOut",
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
],
),
),
)
],
),
),
_dragUpdate < 1
? BackdropFilter(
filter: ImageFilter.blur(
sigmaX: (10 - _dragUpdate * 10),
sigmaY: (10 - _dragUpdate * 10)),
child: Container(
decoration: BoxDecoration(
color: Colors.black.withOpacity(0),
),
),
)
: null,
].where((a) => a != null).toList(),
));
}
navigate(String route) async{
await navigatorKey.currentState.pushNamed(route).then((_){
Timer(Duration(milliseconds: 500),()=>widget.innerDrawerKey.currentState.toggle() );
});
}
}
I copied example from package and didnt touch original much. only aded a function to toggle after turn back.
navigate(String route) async{
await navigatorKey.currentState.pushNamed(route).then((_){
Timer(Duration(milliseconds: 500),()=>widget.innerDrawerKey.currentState.toggle() );
});
}
to navigate from all over pages aded GlobalKey globally so that reachable from every class
final GlobalKey<NavigatorState> navigatorKey = GlobalKey(debugLabel: "Main Navigator");
inner_drawer also needs a globalkey for state to toogle but if you create only one when navigate between pages it gives duplicate global key error. to avoid I created a global variable named innerKeys
Map<String,GlobalKey<InnerDrawerState>>innerKeys={
'main':GlobalKey<InnerDrawerState>(),
'profile':GlobalKey<InnerDrawerState>(),
'pharmacies':GlobalKey<InnerDrawerState>(),
};
finally I added this CustomDrawer to every pages
#override
Widget build(BuildContext context) {
return CustomDrawer(
innerDrawerKey: vars.innerKeys['profile'],
scaffold:Scaffold(
appBar: CustomAppBar(
title: 'Profile',
actions: <Widget>[
],),
body: Stack(
children: <Widget>[
Background(),
])));
}
I hope it will helps to someone.
NOTE: please check original flutter pack if anything updated. Be avare that this example is not perfect and needs to taken care that if many navigation over this drawer then widget tree will have many pages and performance will be impacted. any tuning suggestion will be appriciated.
My Solution Navigation Drawer with Multiple Fragments using bloc package
First, add below dependencies in your pubspec.yaml file
flutter_bloc: ^4.0.0
Now create below files
drawer_event.dart
import 'nav_drawer_state.dart';
abstract class NavDrawerEvent {
const NavDrawerEvent();
}
class NavigateTo extends NavDrawerEvent {
final NavItem destination;
const NavigateTo(this.destination);
}
nav_drawer_bloc.dart
import 'package:bloc/bloc.dart';
import 'drawer_event.dart';
import 'nav_drawer_state.dart';
class NavDrawerBloc extends Bloc<NavDrawerEvent, NavDrawerState> {
#override
NavDrawerState get initialState => NavDrawerState(NavItem.homePage);
#override
Stream<NavDrawerState> mapEventToState(NavDrawerEvent event) async* {
if (event is NavigateTo) {
if (event.destination != state.selectedItem) {
yield NavDrawerState(event.destination);
}
}
}
}
nav_drawer_state.dart
class NavDrawerState {
final NavItem selectedItem;
const NavDrawerState(this.selectedItem);
}
enum NavItem {
homePage,
profilePage,
orderPage,
myCart,
}
drawer_widget.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterdrawerwithbloc/bloc/drawer_event.dart';
import 'package:flutterdrawerwithbloc/bloc/nav_drawer_bloc.dart';
import 'package:flutterdrawerwithbloc/bloc/nav_drawer_state.dart';
class NavDrawerWidget extends StatelessWidget {
final String accountName;
final String accountEmail;
final List<_NavigationItem> _listItems = [
_NavigationItem(true, null, null, null),
_NavigationItem(false, NavItem.homePage, "Home", Icons.home),
_NavigationItem(false, NavItem.profilePage, "Profile Page", Icons.person),
_NavigationItem(false, NavItem.orderPage, "My Orders", Icons.list),
_NavigationItem(false, NavItem.myCart, "My Cart", Icons.shopping_cart),
];
NavDrawerWidget(this.accountName, this.accountEmail);
#override
Widget build(BuildContext context) => Drawer(
child: Container(
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: _listItems.length,
itemBuilder: (BuildContext context, int index) =>
BlocBuilder<NavDrawerBloc, NavDrawerState>(
builder: (BuildContext context, NavDrawerState state) =>
_buildItem(_listItems[index], state),
)),
));
Widget _buildItem(_NavigationItem data, NavDrawerState state) =>
data.header ? _makeHeaderItem() : _makeListItem(data, state);
Widget _makeHeaderItem() => UserAccountsDrawerHeader(
accountName: Text(accountName, style: TextStyle(color: Colors.white)),
accountEmail: Text(accountEmail, style: TextStyle(color: Colors.white)),
decoration: BoxDecoration(color: Colors.indigo),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,
foregroundColor: Colors.amber,
child: Icon(
Icons.person,
size: 54,
),
),
);
Widget _makeListItem(_NavigationItem data, NavDrawerState state) => Card(
shape: ContinuousRectangleBorder(borderRadius: BorderRadius.zero),
borderOnForeground: true,
elevation: 0,
margin: EdgeInsets.zero,
child: Builder(
builder: (BuildContext context) => ListTile(
title: Text(
data.title,
style: TextStyle(
color: data.item == state.selectedItem ? Colors.green : Colors.blueGrey,
),
),
leading: Icon(
data.icon,
color: data.item == state.selectedItem ? Colors.green : Colors.blueGrey,
),
onTap: () => _handleItemClick(context, data.item),
),
),
);
void _handleItemClick(BuildContext context, NavItem item) {
BlocProvider.of<NavDrawerBloc>(context).add(NavigateTo(item));
Navigator.pop(context);
}
}
class _NavigationItem {
final bool header;
final NavItem item;
final String title;
final IconData icon;
_NavigationItem(this.header, this.item, this.title, this.icon);
}
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterdrawerwithbloc/bloc/nav_drawer_bloc.dart';
import 'package:flutterdrawerwithbloc/bloc/nav_drawer_state.dart';
import 'package:flutterdrawerwithbloc/drawer_widget.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Navigation Drawer Demo',
theme: ThemeData(primarySwatch: Colors.blue, scaffoldBackgroundColor: Colors.white),
home: MyHomePage(),
);
;
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
NavDrawerBloc _bloc;
Widget _content;
#override
void initState() {
super.initState();
_bloc = NavDrawerBloc();
_content = _getContentForState(_bloc.state.selectedItem);
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) => BlocProvider<NavDrawerBloc>(
create: (BuildContext context) => _bloc,
child: BlocListener<NavDrawerBloc, NavDrawerState>(
listener: (BuildContext context, NavDrawerState state) {
setState(() {
_content = _getContentForState(state.selectedItem);
});
},
child: BlocBuilder<NavDrawerBloc, NavDrawerState>(
builder: (BuildContext context, NavDrawerState state) => Scaffold(
drawer: NavDrawerWidget("AskNilesh", "rathodnilsrk#gmail.com"),
appBar: AppBar(
title: Text(_getAppbarTitle(state.selectedItem)),
centerTitle: false,
brightness: Brightness.light,
backgroundColor: Colors.indigo,
),
body: AnimatedSwitcher(
switchInCurve: Curves.easeInExpo,
switchOutCurve: Curves.easeOutExpo,
duration: Duration(milliseconds: 300),
child: _content,
),
),
),
));
_getAppbarTitle(NavItem state) {
switch (state) {
case NavItem.homePage:
return 'Home';
case NavItem.profilePage:
return 'Profile Page';
case NavItem.orderPage:
return 'My Orders';
case NavItem.myCart:
return 'My Cart';
default:
return '';
}
}
_getContentForState(NavItem state) {
switch (state) {
case NavItem.homePage:
return Center(
child: Text(
'Home Page',
style: TextStyle(fontWeight: FontWeight.bold),
),
);
case NavItem.profilePage:
return Center(
child: Text(
'Profile Page',
style: TextStyle(fontWeight: FontWeight.bold),
),
);
case NavItem.orderPage:
return Center(
child: Text(
'My Orders',
style: TextStyle(fontWeight: FontWeight.bold),
),
);
case NavItem.myCart:
return Center(
child: Text(
'My Cart',
style: TextStyle(fontWeight: FontWeight.bold),
),
);
default:
return Center(
child: Text(
'Home Page',
style: TextStyle(fontWeight: FontWeight.bold),
),
);
}
}
}
You can find complete project here Navigation Drawer with Multiple Fragments using bloc
In Addition to #Rémi Rousselet Answer, the code has slightly changed (2022) - due to null safety amends.
Replace this:
class RootScaffold {
static openDrawer(BuildContext context) {
final ScaffoldState scaffoldState =
context.rootAncestorStateOfType(TypeMatcher<ScaffoldState>());
scaffoldState.openDrawer();
}
}
...with...
class RootScaffold {
static openDrawer(BuildContext context) {
final ScaffoldState? scaffoldState = context.findRootAncestorStateOfType<ScaffoldState>();
scaffoldState?.openDrawer();
}
}
You can create the ScaffoldCustom when you ensure that all pages have only the body differently.
But I feel that this approach is too restrictive.
So, I am using this.
For the AppBar:
class AppBarPattern1 extends StatelessWidget implements PreferredSizeWidget {
const AppBarPattern1({Key? key}) : super(key: key);
#override
// TODO: implement preferredSize
Size get preferredSize => const Size.fromHeight(kToolbarHeight); // You can change it.
/*
/// The height of the toolbar component of the [AppBar].
const double kToolbarHeight = 56.0;
*/
#override
Widget build(BuildContext context) {
return AppBar();
}
}
For the Drawer:
class DrawerPattern1 extends StatelessWidget {
const DrawerPattern1({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const Drawer();
}
}
Using like this:
class ExamplePage extends StatelessWidget {
const ExamplePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: const AppBarPattern1(),
endDrawer: const DrawerPattern1(),
body: SafeArea(child: Container()),
);
}
}
As you see these custom widgets can be const.

Flutter - SingleChildScrollView interfering in columns

I created a screen that works well with the columns, but I needed to scroll because of the keyboard.
When you insert the SingleChildScrollView or the ListView attribute the MainAxisAlignment.spaceBetween, it no longer works.
Was there any solution for that?
Gif without the SingleChildScrollView the screen does not roll and the FloatingActionButton is at the bottom of the screen
Gif with SingleChildScrollView the screen roll and he FloatingActionButton is not in bottom of the screen
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(backgroundColor: new Color(0xFF26C6DA)),
body: new SingleChildScrollView(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
child: new Column(
children: <Widget>[
new TextField(
decoration: const InputDecoration(
labelText: "Description",
),
style: Theme.of(context).textTheme.title,
),
new TextField(
decoration: const InputDecoration(
labelText: "Description",
),
style: Theme.of(context).textTheme.title,
),
new TextField(
decoration: const InputDecoration(
labelText: "Description",
),
style: Theme.of(context).textTheme.title,
),
],
)
),
new Container(
margin: new EdgeInsets.only(bottom: 16.0),
child: new FloatingActionButton(
backgroundColor: new Color(0xFFE57373),
child: new Icon(Icons.check),
onPressed: (){}
),
)
],
),
)
);
}
}
I would recommend against using FloatingActionButton in the way you are doing here. FloatingActionButton should be used for actions that always need to always be on screen at all times. See the Material guidelines on button usage for suggestions on other button types that can be scrolled, like RaisedButton and FlatButton. You could use a RaisedButton here, but I think it would be better to make your screen a dialog and put the save action in the AppBar as I suggested in your other question.
If you do decide to use a RaisedButton or FlatButton, keep in mind that scrollables don't normally change their item spacing based on the size of their container. Instead of using MainAxisAlignment.spaceBetween, you could put some Padding around your RaisedButton to separate it from the TextField elements. This will ensure that they are spaced the same distance apart regardless of rotation, screen size, and regardless of whether the keyboard is up.
Follow the code below to register.
MainAxisAlignment.spaceBetween has been replaced with dynamic padding, depending on screen size.
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
final ui.Size logicalSize = MediaQuery.of(context).size;
final double _height = logicalSize.height;
return new Scaffold(
appBar: new AppBar(backgroundColor: new Color(0xFF26C6DA)),
body: new SingleChildScrollView(
child: new Column(
//mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
height: 300.0,
child: new Column(
children: <Widget>[
new TextField(
decoration: const InputDecoration(
labelText: "Description",
),
style: Theme.of(context).textTheme.title,
),
new TextField(
decoration: const InputDecoration(
labelText: "Description",
),
style: Theme.of(context).textTheme.title,
),
new TextField(
decoration: const InputDecoration(
labelText: "Description",
),
style: Theme.of(context).textTheme.title,
),
],
)
),
new Container(
padding: new EdgeInsets.only(top: (_height - 450.0)),
margin: new EdgeInsets.only(bottom: 16.0),
child: new FloatingActionButton(
backgroundColor: new Color(0xFFE57373),
child: new Icon(Icons.check),
onPressed: (){}
),
)
],
),
)
);
}
}

Re: create a dropdown button in flutter

I have used a DropDownButton in my build but i want the arrow to be displayed at the end and the dropdown items to be displayed from arrow, but in my app they are displaying from the top. i have attached the screenshots for your reference.
please can you tell me how to change this or is there any other way to simply create a drop down menu.
An example would be much appreciated.
Please excuse my code as I am new to programming and any comments or suggestions are most welcome.
Many Thanks,
Mahi.
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'dart:ui';
void main(){
runApp(new BranchSetup());
}
class BranchSetup extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new _BranchSetupState();
}
}
class _BranchSetupState extends State<BranchSetup> with
WidgetsBindingObserver {
#override
Widget build(BuildContext context){
return new MaterialApp(
theme: new ThemeData(
primaryColor: const Color(0xFF229E9C),
),
title: 'Branch Setup',
home: new Scaffold(
body: new Container(
child: new ListView(
children: <Widget>[
new Container(
margin: const EdgeInsets.all(16.0),
child: new Row(
children: <Widget>[
new Expanded(
child: new TextFormField(
decoration: new InputDecoration(
labelText: 'Branch Name',
),
),
),
],
),
),
new Container(
margin: const EdgeInsets.all(16.0),
child:
new DropdownButton<String>(
items: <String>['Mens','Womans']
.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}
).toList(),
onChanged: null,
),
),
],
),
),
),
);
}
}
This looks like a bug in Flutter. I filed an issue.
In the meantime, you can work around it by wrapping your DropdownButton in a Column.
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new DemoApp()));
}
class DemoApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text('DropdownButton Example')),
body: new ListView(
children: [
new Column(
children: <Widget>[
new DropdownButton<String>(
items: <String>['Foo', 'Bar'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (_) {},
),
],
),
],
),
);
}
}
You can try out the plugin that I created : flutter_search_panel. Not a dropdown plugin, but you can display the items with the search functionality.
Use the following code for using the widget :
FlutterSearchPanel(
padding: EdgeInsets.all(10.0),
selected: 'a',
title: 'Demo Search Page',
data: ['This', 'is', 'a', 'test', 'array'],
icon: new Icon(Icons.label, color: Colors.black),
color: Colors.white,
textStyle: new TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 20.0, decorationStyle: TextDecorationStyle.dotted),
onChanged: (value) {
print(value);
},
),

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