Custom BottomNavigationBar in Flutter - flutter

I tried to implement a custom bottom navigation bar. I use a pageview to navigate between the pages. Now the bottom navigation bar is not absolutely above the page view but cuts off part of the page view. Can anyone help me here?
Here is the associated code:
Scaffold buildHomePage() {
return Scaffold(
body: PageView(
children: <Widget>[
PopularScreen(),
DiscoverScreen(),
ActivityScreen(),
ProfileScreen()
],
controller: pageController,
onPageChanged: onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: buildBottomNavigationBar(),
);
}
Widget buildBottomNavigationBar() {
return BottomAppBar(
child: Container(
height: 65,
margin: EdgeInsets.only(left: 30, bottom: 40, right: 30),
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 5,
)
],
color: Colors.white,
borderRadius: BorderRadius.circular(50),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: items.map((item) {
var itemIndex = items.indexOf(item);
return GestureDetector(
onTap: () => onTap(itemIndex),
child: _buildNavBarItem(item, pageIndex == itemIndex),
);
}).toList(),
),
),
);
}

You can use the Stack Widget to position the your BottomNavigationBar on top of the PageView:
Scaffold(
body: Stack(
children: <Widget>[
PageView(...),
Align(
alignment: Alignment.bottomCenter,
child: buildBottomNavigationBar(pageController),
),
],
),
);
Then you can remove the BottomAppBar from the buildBottomNavigationBar() or set
the elevation property to 0 and the color to Colors.transparent:
BottomAppBar(
color: Colors.transparent,
elevation: 0,
child: ...
);
Result:

Your answer is Stack class, which will help you build your BottomNavigationBar on top of your PageView
Basic layout of the Page
Stack(
children: [
PageView(
....
)
Positioned(
top: ..,
left: ..,
bottom: ..,
right: ..,
child: BottomNavigationBar()
)
]
)
If that make sense to you

Related

Expanded ListView not working inside of TabBarView

Here's a picture of what I'm trying to acheive.
However I want both lists in the TabBarView to expand to the bottom of the screen. The only way I can get it to work now, is with a Container with a fixed height. If I use MediaQuery.of(context).size.height, then it expands off the bottom of the page and I get the yellow black overflow thing.
If I wrap the TabBarView in an Expanded widget instead of the fixed size Container, I get a RenderFlex children have non-zero flex but incoming height constraints are unbounded. error. If I wrap each ListView in Expanded (while the fixed height Container is removed), I get a Horizontal viewport was given unbounded height. error. Any idea what I should try next?
Here's the code.
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
alignment: Alignment.centerLeft,
margin: const EdgeInsets.only(bottom: 15, top: 6),
padding: const EdgeInsets.only(left: 15),
child: const Text('Home'),
),
DefaultTabController(
length: 2,
initialIndex: 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
child: TabBar(
isScrollable: true,
tabs: [
Tab(text: 'Subscriptions'),
Tab(text: 'Recently Visited'),
],
),
),
Container(
height: 500,
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: Colors.grey, width: 0.5))),
child: TabBarView(
children: <Widget>[
buildAList(),
buildAList()
],
),
),
],
),
),
],
),
),
);
}
Widget buildAList() {
return ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: List<Widget>.generate(
100,
(i) => Text(
'Item $i',
style: TextStyle(fontSize: 20),
),
).toList(),
);
}
All I changed in the code below is I wrapped your TabBarView's Container widget with an Expanded widget and then wrapped the DefaultTabController with another Expanded widget. If you're going to put an Expanded widget somewhere, you should probably wrap it's parent with an Expanded widget too if it's inside of a flexible widget such as a Row or Column.
I also changed your buildAList function to use a ListView.builder so that you didn't have to "generate" a list.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
alignment: Alignment.centerLeft,
margin: const EdgeInsets.only(bottom: 15, top: 6),
padding: const EdgeInsets.only(left: 15),
child: const Text('Home'),
),
Expanded(
child: DefaultTabController(
length: 2,
initialIndex: 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
child: TabBar(
isScrollable: true,
tabs: [
Tab(text: 'Subscriptions'),
Tab(text: 'Recently Visited'),
],
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: Colors.grey, width: 0.5),
),
),
child: TabBarView(
children: <Widget>[
buildAList(),
buildAList(),
],
),
),
),
],
),
),
),
],
),
),
);
}
Widget buildAList() {
return ListView.builder(
shrinkWrap: true,
itemCount: 100,
itemBuilder: (c, i) {
return Text(
"Item $i",
style: TextStyle(fontSize: 20),
);
},
);
}

How to focus on spesific section on keyboar pops up in flutter

I'm bit more thinking a bout UX in this app and wandering how I can achieve below behavior in flutter. so far what I have done is just making sections using Rows, Columns and Expanded widgets. but when the keyboard opens it overlaps content. I have my custom widgets so its simplified as below.
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
flex: 6,
child: Container(
// Image goes here
),
Expanded(
flex: 5,
child: Container(
child: Column(
children: [
Container(
margin: EdgeInsets.only(left: 20, right: 20),
padding: EdgeInsets.only(left: 20, right: 20, top: 5),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(10)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 5,
blurRadius: 8,
offset:
Offset(0, 4), // changes position of shadow
),
],
),
child: Column(
children: [
// Form goes here
],
),
),
Button(
label: "Sign In",
)
],
),
),
),
Expanded(
flex: 2,
child: Button(
label: "Don’t have an account? Sign Up",
type: 'text',
align: 'center'),
),
],
),
));
I did something similar, with FocusScope.of(context).hasFocus to detect if keyboard is showing or not and change my UI accordingly.
Found the solution. Just needs to add reverse: true to SingleChildScrollView then it scroll down the SingleChildScrollView to bottom when focus on TextField
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFF9FDFF),
body: SafeArea(
child: SingleChildScrollView(
reverse: true, // <---- Add this
child: Column(
child: // Your content
),
),
),
);

Align a button the bottom center in flutter

I want to align a button to the bottomcenter of the screen
I created a buttomappbar in a scaffold i want to include a round button but i don't want to use the default fab. Im using another round button and i tried to align the button to the buttomcenter using the Align widget but it stays in the center.
class _MainActivityState extends State<MainActivity> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
backgroundColor: HexColor("ECEDEF"),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Icon(Icons.threed_rotation)
],
),
shape: CircularNotchedRectangle(),
color: Colors.white,
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Align(
alignment: Alignment.bottomCenter,
child: CircularGradientButton(
child: Icon(Icons.gradient),
callback: (){},
gradient: Gradients.rainbowBlue,
shadowColor: Gradients.rainbowBlue.colors.last.withOpacity(0.5),
),
)
)
);
}
}
I want the CircularGradientButton to come to the bottomcenter above the BottomAppBar
With a stack you can achieve that. Set fit property to: StackFit.expand then use a positioned with bottom:0 and width: MediaQuery.of(context).size.width.
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned(
bottom: 0,
width: MediaQuery.of(context).size.width,
child: Center(
child: MaterialButton(
onPressed: () {},
color: Colors.red,
),
),
)
],
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[Icon(Icons.threed_rotation)],
),
shape: CircularNotchedRectangle(),
color: Colors.white,
),
);

How to overlay Widget over background widget in flutter?

I want to overlay a add to cart button on background restaurants list, Overlay card widget on container explains it can be done by Stack but I tried and still not getting how to do it. Kindly help me to know how can I do it?
Expected Design
Result Image
detailpage.dart
#override
Widget build(BuildContext context) {
return Scaffold(
body: Wrap(
children: <Widget>[
Container(...),
Container(...),
Stack(
children: <Widget>[
Center(
child: MaterialButton(
onPressed: () {},
textColor: Colors.white,
padding: const EdgeInsets.all(0.0),
child: Container(
width: 88,
height: 30,
decoration: BoxDecoration(
color: Color(0xff00D99E),
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
blurRadius: 8,
offset: Offset(0, 15),
color: Color(0xff00D99E).withOpacity(.6),
spreadRadius: -9)
]),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset('assets/icon-chat-notification.png'),
SizedBox(width: 6),
Text("CART",
style: TextStyle(
fontSize: 10,
color: Colors.white,
letterSpacing: 1,
))
],
),
),
),
)
],
)
],
),
bottomNavigationBar: bottomNavigationBar,
);
}
The problem is that your Stack only composes the Button itself instead of the entire view, you use it to put the Text and the Icon on top of the MaterialButton. Side note: that's actually not necessary, you can just put the text and the icon directly into the MaterialButton and get rid of the Stack.
To solve your problem you have to put your button and your List onto the same Stack (your button can still stay a Stack itself but I don't encourage you to do that).
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand
children: <Widget>[
Container(...),
// Use Positioned around your List to expand it in all dimensions
Positioned(
bottom: 0,
top: 0,
left: 0,
right: 0,
child: Container(...), // This is your container with the list
)
// Position the button at the bottom
Positioned(
bottom: 0,
child: Stack(...), // This is your button
)
],
),
bottomNavigationBar: bottomNavigationBar,
);
}

How to put scroll view inside stack widget in flutter

I am making a flutter application in which i uses body as a stack and in this stack i have two child.One is main body and other is back button which is at top of screen.The first child of stack is scrollview.Here is my build method.
Widget build(BuildContext context) {
return Scaffold(
//debugShowCheckedModeBanner: false,
key: scaffoldKey,
backgroundColor: Color(0xFF5E68A6),
body: Stack(
children: <Widget>[
Container(
margin: const EdgeInsets.fromLTRB(0.0, 10.0 , 0.0 , 0.0 ),
height: double.infinity,
child:CustomScrollView(
slivers: <Widget>[
new Container(
margin: EdgeInsets.all(15.0),
child:Text(getTitle(),
style: TextStyle(fontSize: 20.0,fontWeight: FontWeight.bold,color: Colors.white),
),
),
//middle section
_isLoading == false ?
new Expanded(child: GridView.builder(
itemCount: sub_categories_list.length,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (context, position){
return InkWell(
child: new Container(
//color: Colors.white,
padding: EdgeInsets.all(20),
margin: EdgeInsets.all(10),
height: 130,
width: 130,
child: new Center(
child :
Text(sub_categories_list[position].name,
style: TextStyle(fontSize: 18.0,fontWeight: FontWeight.bold),
)
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(16)),
// border: Border.all(color: Colors.black, width: 3),
),
),
onTap: () {
//write here
// Fluttertoast.showToast(msg: "You clicked id :"+sub_categories_list[position].cat_id.toString());
Navigator.pushNamed(context, '/advicemyself');
},
);
}
))
:
CircularProgressIndicator(),
Container(
margin: EdgeInsets.all(18.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Column(
children: <Widget>[
Image.asset('assets/bt1.png'),
Container(
margin: EdgeInsets.all(10.0),
child: Text("FIND HELP",
style: TextStyle(fontSize: 18.0,color: Colors.white),
),
)
],
),
new Column(
children: <Widget>[
Image.asset('assets/bt2.png'),
Container(
margin: EdgeInsets.all(10.0),
child: Text("HOME",
style: TextStyle(fontSize: 18.0,color: Colors.white),
),
)
],
),
new Column(
mainAxisAlignment:MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset('assets/bt3.png'),
Container(
margin: EdgeInsets.all(10.0),
child: Text("CALL 999",
style: TextStyle(fontSize: 18.0,color: Colors.white),
),
)
],
),
],
),
),
],
),
),
Positioned(
left: 10,
top: 30,
child: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => {
//go back
},
color: Colors.white,
iconSize: 30,
),
),
// makeview()
],
),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
I have also tried using SingleChildScrollView but that also does not works.What i am doing wrong here ?
Here is link to the design which i want to make.
https://imgur.com/a/w7nLmKC
The back should be above scroll view so i used stack widget.
Running your sample code, there doesn't seem to be a need for overlapping widgets. Using Stack seems to be unnecessary. One way you could do is by using Column widget, and using Expanded as you see fit.
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Widget(), // back button goes here
CustomScrollView(...),
],
),
);
}
Otherwise, if you really need to use Stack, the scroll function should work fine. I've tried this locally and the Stack widget doesn't interfere with scrolling of Slivers, ListView, and GridView.
Stack(
children: [
/// Can be GridView, Slivers
ListView.builder(),
/// Back button
Container(),
],
),