How can I add a drawer in the app bar in flutter? - flutter

I am trying to add a drawer in my appbar but i couldnt manage to fix it.
My code looks like this, please help!
Widget appBarMain(BuildContext context) {
return AppBar(
centerTitle: false,
title: Image.asset(
'assets/images/logox.png',
height: 45,
),
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[Colors.pink[400], Colors.blue[400]]),
),
),
);
}

add a drawer with Scaffold:
return Scaffold(
appBar: appBarMain(context),
body: Center(child: Text('My Page!')),
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('Item 1'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
);

Read https://flutter.dev/docs/cookbook/design/drawer
Do like this
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: appBarMain(context), // => appbar is an attribute in Scaffold
body: Center(
child: MyWidget(),
),
),
);
}
}

A drawer is added to Scaffold and not the AppBar. It is only its icon that is automatically shown in the AppBar.
See: https://flutter.dev/docs/cookbook/design/drawer

Related

Remove the top padding from ScrollBar when wrapping ListView

I am trying to add ScrollBar to ListView in Flutter but the ScrollBar still have padding on top when scrolling to the start of the ListView.
I included a snapshot of the application so you can understand the problem better. it`s in the indicator of the scrollbar widget the top padding should not be there ,so the start of the scrollbar indicator should touch the bottom edge of the blue DrawerHeader.
here is my code:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
final sc = ScrollController(initialScrollOffset: 0);
final res = MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text('Driver App'),
),
body: null,
drawer: Drawer(
child: Container(
padding: EdgeInsets.zero,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
margin: EdgeInsets.zero,
),
Expanded(
child: Scrollbar(
radius: Radius.circular(30),
thickness: 10,
controller: sc,
isAlwaysShown: true,
child: ListView(
shrinkWrap: false,
controller: sc,
padding: EdgeInsets.only(top: 0),
children: <Widget>[
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
},
),
...
],
),
),
),
],
),
), // Populate the Drawer in the next step.
),
),
);
return res;
}
}
result when scrolling position is 0:
use MediaQuery.removePadding widget with removeTop: true
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
final sc = ScrollController(initialScrollOffset: 0);
final res = MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text('Driver App'),
),
body: null,
drawer: Drawer(
child: Container(
padding: EdgeInsets.zero,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
margin: EdgeInsets.zero,
),
Expanded(
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: Scrollbar(
radius: Radius.circular(30),
thickness: 10,
controller: sc,
isAlwaysShown: true,
child: ListView(
shrinkWrap: false,
controller: sc,
padding: EdgeInsets.only(top: 0),
children: <Widget>[
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
},
)
],
),
),
),
),
],
),
), // Populate the Drawer in the next step.
),
),
);
return res;
}
}
Scrollbar padding is set as follows:
ScrollbarPainter _buildMaterialScrollbarPainter() {
return ScrollbarPainter(
color: _themeColor,
textDirection: _textDirection,
thickness: widget.thickness ?? _kScrollbarThickness,
radius: widget.radius,
fadeoutOpacityAnimation: _fadeoutOpacityAnimation,
padding: MediaQuery.of(context).padding,
);
}
The solution to remove the padding in your case would be to place your Scaffold inside the SafeArea.
home: SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('Driver App'),
),

How to make list view in card flutter

I am a new flutter developer.I try to make listview to view a set of data that comes from the database.The list now works, but as follows:
Now it is not presented separately.I need to display every element in the card.An example of what I'm trying to do:
In this picture, each item on the card is separate and separated from the second.How I can do it?If anyone knows the solution please help me.
my code now like that:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: Card(
child :FutureBuilder<List<Flowerdata>>(
future: fetchFlowers(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Center(
child: CircularProgressIndicator()
);
return ListView(
children: snapshot.data
.map((data) => Column(children: <Widget>[
GestureDetector(
onTap: ()=>{
getItemAndNavigate(data.id, context)
},
child: Row(
children: [
Container(
width: 100,
height: 100,
margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child:
Image.network(data.flowerImageURL,
width: 200, height: 100, fit: BoxFit.cover,))),
Flexible(child:
Text(data.flowerName,
style: TextStyle(fontSize: 18))
),
]),),
Divider(color: Colors.black),
],
))
.toList(),
);
},
)
),
),
]
)
);
}
You need to wrap your item's Column(not the FutureBuilder) in with Card
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: <Widget>[
Expanded(
child: FutureBuilder<List<Flowerdata>>(
future: fetchFlowers(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(child: CircularProgressIndicator());
return ListView(
children: snapshot.data
.map((data) => Card(
child: Column(
children: <Widget>[
GestureDetector(
onTap: () => {getItemAndNavigate(data.id, context)},
child: Row(children: [
Container(
width: 100,
height: 100,
margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.network(
data.flowerImageURL,
width: 200,
height: 100,
fit: BoxFit.cover,
))),
Flexible(
child: Text(data.flowerName,
style: TextStyle(fontSize: 18))),
]),
),
Divider(color: Colors.black),
],
),
))
.toList(),
);
},
),
),
]));
}
Setup
Start a new Flutter project. I'm calling mine flutter_listview.
Open main.dart and replace the code with the following:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ListViews',
theme: ThemeData(
primarySwatch: Colors.teal,
),
home: Scaffold(
appBar: AppBar(title: Text('ListViews')),
body: BodyLayout(),
),
);
}
}
class BodyLayout extends StatelessWidget {
#override
Widget build(BuildContext context) {
return _myListView(context);
}
}
// replace this function with the code in the examples
Widget _myListView(BuildContext context) {
return ListView();
}
Note the _myListView() function at the end. You will be replacing this with the code in the examples below
Basic types of ListViews
Static ListView
If you have a short list of items that don't change, then you can use the default ListView constructor to make it. This is useful for making something like a settings menu page.
Replace _myListView() with the following:
Widget _myListView(BuildContext context) {
return ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
);
}
Run the app and you should see the following image. (After this when refreshing, usually hot reload works fine, but I find at times I need to do a hot restart or even completely stop and restart the app.)
ListTile customization
The Flutter team designed the ListTile widget to handle the normal content that you would want in a list. This means that most of the time there is no need to define a custom layout. You can just use the default ListTile for each item in the list. When we made a ListView in the example above we only used the title option. But we can also show subtitles, images, and icons.
Replace _myListView() with the following
Widget _myListView(BuildContext context) {
return ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.wb_sunny),
title: Text('Sun'),
),
ListTile(
leading: Icon(Icons.brightness_3),
title: Text('Moon'),
),
ListTile(
leading: Icon(Icons.star),
title: Text('Star'),
),
],
);
}
The leading is for adding an icon or image at the start of the ListTile.
You can also add an icon at the end if you specify the trailing attribute.
ListTile(
leading: Icon(Icons.wb_sunny),
title: Text('Sun'),
trailing: Icon(Icons.keyboard_arrow_right),
)
The right arrow icon makes it look like the list items are clickable, but they aren't. Not yet. We will see how to add touch events in the next section. It's easy. (Hint: onTap )
Instead of icons, we can also use images. The recommended image option is to use a CircleAvatar widget.
Replace _myListView() with the following:
Widget _myListView(BuildContext context) {
return ListView(
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage('assets/sun.jpg'),
),
title: Text('Sun'),
),
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage('assets/moon.jpg'),
),
title: Text('Moon'),
),
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage('assets/stars.jpg'),
),
title: Text('Star'),
),
],
);
}
If you want MASTERING FLUTTER LISTVIEWS enter link description here

Bottom Widget overflow in Column layout?

I'm trying to display an ad using the admob_flutter package: https://pub.dev/packages/admob_flutter, which basically allows me to display the ad just like any other widget.
Following the documentation, I added a widget within a column layout as below (relevant code only):
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(fileName),
backgroundColor: Colors.teal,
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: (){
},
),
],
),
body: Container(
padding: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
TextField(
...
),
AdmobBanner(
adUnitId: 'ca-app-pub-39402560999XXXXXX/XXXXXXXXX',
adSize: AdmobBannerSize.BANNER,
),
],
),
),
bottomNavigationBar: BottomAppBar(...)
As per documentation, this is all I have to do, but I get an overflow error as seen in screenshot below:
I tried wrapping these in Expanded() and Flexible() but that did not fix my problem?
What am I doing wrong here?
You should wrap your Widgets in a Scrollable Widget so they can be scrolled when the contents exceeds the device screen's size.
I wrapped your widgets in a SingleChildScrollView, check the demo below:
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(fileName),
backgroundColor: Colors.teal,
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: (){
},
),
],
),
body: SingleChildScrollView( // new line
child: Container(
padding: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
TextField(
...
),
AdmobBanner(
adUnitId: 'ca-app-pub-39402560999XXXXXX/XXXXXXXXX',
adSize: AdmobBannerSize.BANNER,
),
],
),
),
)
bottomNavigationBar: BottomAppBar(...)
Just change Column to Listview
You can use ListView , SingleChildScrollView or ListView.builder if you want dynamic contents in place of Column
body: Container(
padding: EdgeInsets.all(5.0),
child: Column(..),),

Pass tap event to the child behind in Stack

After watching a tutorial video about creating a custom PageView in Flutter, I've come across a problem.
In order to achieve a custom PageView's page positions, I've used a stack of items that swipe left/right depending on the PageView that is placed in a Stack.fill() above every other element in the Stack.
Here's the example of the code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
);
}
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Test')),
body: Container(
height: 200.0,
child: Stack(
children: <Widget>[
Container(
color: Colors.blueGrey,
width: double.infinity,
height: double.infinity,
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () {
print('InkWell tapped');
},
),
),
),
Positioned.fill(
child: PageView.builder(
itemBuilder: (context, index) {
return Container(
child: Center(
child: Text(
'$index',
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
),
),
),
);
},
itemCount: 4,
),
),
],
),
),
);
}
}
The problem is that I want to trigger a Tap event on the InkWell behind the PageView, while still be able to swipe the PageView.
Is it possible to pass the tap event to the element behind the PageView?
Thanks.
EDIT:
Since you should not extend widgets in flutter, I've just made a copy of Scrollable class that uses a HitTestBehavior.translucent instead of HitTestBehavior.opaque. After that you create a copy of PageView using this new Scrollable.
With such modification - the children behind the PageView start receiving gestures.
SOLUTION:
Since you should not extend widgets in flutter, I've just made a copy of Scrollable class that uses a HitTestBehavior.translucent instead of HitTestBehavior.opaque. After that you create a copy of PageView using this new Scrollable.
With such modification - the children behind the PageView start receiving gestures.
This one is without using a stack,
Scaffold(
appBar: AppBar(title: Text('Test')),
body: Container(
color: Colors.red,
height: 200.0,
child: InkWell(
onTap: () {
print('InkWell tapped');
},
child: PageView.builder(
itemCount: 4,
itemBuilder: (context, index) {
return Container(
child: Center(
child: Text(
'$index',
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
),
),
),
);
},
),
),
),
),

Flutter change custom AppBar height

I tried this link and it didn't work.
In this code when I try to change height of AppBar, but it doesn't any change.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Container(
height: double.infinity,
child: Column(
children: <Widget>[
PreferredSize(
preferredSize: Size.fromHeight(150.0),
child: AppBar(
backgroundColor: Colors.white.withOpacity(0.9),
title: Container(height: 150.0,),
),
)
],
)),
);
}
Note: My AppBar(...) isn't used in appBar:
Just use toolbarHeight:
appBar: AppBar(
toolbarHeight: 150, // This is your height!
title: Text('AppBar'),
)
However, if you don't want to use appBar property
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Container(
height: double.infinity,
child: Column(
children: <Widget>[
Container(
height: 150, // height of AppBar
child: AppBar(
backgroundColor: Colors.blue.withOpacity(0.9),
title: Text("AppBar"),
),
)
],
),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
body: Stack(
children: <Widget>[
Container(
color: Colors.blue,
),
new Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: AppBar(
title: Text('App Bar'),
backgroundColor: Colors.green,
),
),
],
)),
);
}
}
For more controls , Use the PreferedSize widget to create your own appBar
Example :
appBar: PreferredSize(
preferredSize: Size(100, 80), //width and height
// The size the AppBar would prefer if there were no other constraints.
child: SafeArea(
child: Container(
height: 100,
color: Colors.red,
child: Center(child: Text('Fluter is great')),
),
),
),
Don't forget to use a SafeArea widget if you don't have a safeArea
Output :