onTap event only regonized by widget behind button - flutter

I have a strange issue with my BottomAppBar and an overlapping ElevatedButton.
If I click on the upper half of the + Button the onTap event is fired for the widget behind the + Button. I tried different things but non are working, help is very appreciated, thanks :)
HomePage
return Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: _pages,
),
bottomNavigationBar: const _BottomAppBar(),
);
_BottomAppBar
#override
Widget build(BuildContext context) {
return BottomAppBar(
child: IconTheme(
data: IconThemeData(color: Theme.of(context).colorScheme.onPrimary),
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
clipBehavior: Clip.none,
children: [
Positioned(
top: -30,
child: ElevatedButton(
clipBehavior: Clip.hardEdge,
onPressed: () {
...
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(20),
primary: lightGreen),
child: const Icon(
Icons.add,
size: 30,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
tooltip: 'Home',
iconSize: 28,
icon: SvgPicture.asset(
'assets/svg/home-aktiv.svg'
),
onPressed: () {
...
}),
IconButton(
tooltip: 'Profile',
iconSize: 32,
icon: SvgPicture.asset(
'assets/svg/profil-aktiv.svg'
),
onPressed: () {
...
}),
],
),
],
),
),
);
}

Did you try with a FloatingActionButton?
return Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: _pages,
),
bottomNavigationBar: _BottomAppBar(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);

Related

Flexible making widgets overflow in Flutter

I am building a Flutter web-app, where I have a menu interface with 4 Iconbuttons and 1 MaterialButton that is the users profile, like this:
I am using Flexible to make sure there is no overflow, but if I minimise the window, the Iconbuttons overflow, like this:
Is there any way to prevent this from happening? This is my code:
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Flexible(
flex: 2,
child: IconButton(
icon: Icon(
Icons.chat_bubble_outline_rounded,
color: Colors.white,
),
onPressed: null),
),
Flexible(
flex: 2,
child: IconButton(
icon: Icon(
Icons.settings_outlined,
color: Colors.white,
),
onPressed: null),
),
Flexible(
flex: 2,
child: IconButton(
icon: Icon(
FontAwesomeIcons.wallet,
color: Colors.white,
),
onPressed: null),
),
Flexible(
flex: 2,
child: IconButton(
icon: Icon(
Icons.notifications_outlined,
color: Colors.white,
),
onPressed: null),
),
MaterialButton(
shape: CircleBorder(),
onPressed: () {
print('click');
},
child: CircleAvatar(
backgroundImage: NetworkImage(user.photoURL.toString()),
),
)
],
),
Thank you for your help!
Is this what you want to achieve?
You could achieve this with a SingleChildScrollView.
I combined the SingleChildScrollView with a ConstrainedBox to allow the spread of the icons if the screen is larger than needed.
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: constraints.maxWidth),
child: Row(...),
),
);
},
),
Full source code for easy copy-paste
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
);
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(width: 800, child: MyBar()),
const SizedBox(height: 16.0),
Container(width: 400, child: MyBar()),
const SizedBox(height: 16.0),
Container(width: 200, child: MyBar()),
const SizedBox(height: 16.0),
Container(
width: 100,
child: SingleChildScrollView(child: MyBar()),
),
],
),
),
);
}
}
class MyBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 8.0),
color: Colors.amber.shade300,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: constraints.maxWidth,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(
Icons.chat_bubble_outline_rounded,
color: Colors.white,
),
onPressed: null),
IconButton(
icon: Icon(
Icons.settings_outlined,
color: Colors.white,
),
onPressed: null),
IconButton(
icon: Icon(
FontAwesomeIcons.wallet,
color: Colors.white,
),
onPressed: null),
IconButton(
icon: Icon(
Icons.notifications_outlined,
color: Colors.white,
),
onPressed: null),
MaterialButton(
shape: CircleBorder(),
onPressed: () {
print('click');
},
child: CircleAvatar(
child: Text('X'),
),
)
],
),
),
);
},
),
);
}
}
I don't think Flexible will solve the problem here. Instead of this I have two options for you.
1) Replace Row with ListView (also provide scrollDirection as horizontal).
This will prevent the overflow and the list will be scrollable when the screen will be resized to a smaller width. I will prefer doing this.
2) Scale all the buttons with respect to the screen width.
This will provide you a responsive layout as the buttons will resize as the screen width changes. But you need to make sure that they don't get so small that user will find it difficult to press them.

extendBody with custom BottomNavBar and FAB not working properly

I've searched around for similar problems like this but couldn't find any.
I made a custom bottom navigation bar with a docked FAB. As far as i understand, to make the notch for the FAB transparent I need to add extendBody = true; to the Scaffold, which i did. The result is that out of the four navbar icons, only one of them are showing the transparent notch.
Code and images below. Images are showing second and third navbar icon.
Scaffold(
drawerEnableOpenDragGesture: true,
extendBody: true,
appBar: AppBar(
title: Text('Some text'),
drawer: AppDrawer(),
bottomNavigationBar: BottomAppBar(
color: Colors.blue,
shape: CircularNotchedRectangle(),
notchMargin: 2.0,
child: Container(
height: MediaQuery.of(context).size.width * 0.15,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 4,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(icon: Icon(Icons.account_box), // extendBody not working!
onPressed: () {
setState(() {
_selectedPageIndex = 0;
});
},
),
IconButton(icon: Icon(Icons.account_box), // extendBody working!
onPressed: () {
setState(() {
_selectedPageIndex = 1;
});
},
),
],
),
),
Expanded(flex: 2, child: SizedBox()),
Expanded(
flex: 4,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(icon: Icon(Icons.email), // extendBody not working!
onPressed: () {
setState(() {
_selectedPageIndex = 2;
});
},
),
IconButton(
icon: Icon(Icons.email), // extendBody not working!
onPressed: () {
setState(() {
_selectedPageIndex = 3;
});
},
),
],
),
),
],
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
body: _pages[_selectedPageIndex]['page'],
floatingActionButton: FloatingActionButton(
mini: true,
onPressed: () {
if (_selectedPageIndex == 0)
Navigator.of(context).pushReplacementNamed(
Screen1.routeName);
if (_selectedPageIndex == 1)
Navigator.of(context).pushReplacementNamed(
Screen2.routeName);
if (_selectedPageIndex == 2)
Navigator.of(context).pushReplacementNamed(
Screen3.routeName);
if (_selectedPageIndex == 3)
Navigator.of(context).pushReplacementNamed(
Screen4.routeName);
},
child: _pages[_selectedPageIndex]['icon'],
backgroundColor: Theme.of(context).accentColor,
),
)
What am I missing? Thank you!
I solved it. extendBody: true, is correct, however the child cannot be wrapped in SafeArea.

How to add a FAB using stack when floatingActionButtonLocation is defined?

In my application I have defined a FAB with the property floatingActionButtonLocation set to FloatingActionButtonLocation.centerDocked. I have defined a bottom app bar that holds the centerDocked FAB. I also want to use a Stack widget to position two additional FABs on the top right of the screen. It should look something similar to this - expected result
But when I tried to use a Stack, the FAB which is present in the bottom app bar is displayed but the two FABs under the stack widget are invisible.
docked FAB
FABs under stack widget
code where I have defined the Stack
return new Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: Stack(
children: <Widget>[
Positioned(
// the below values for stack are experimental at the moment
left: MediaQuery.of(context).copyWith().size.width * 0.60,
right: MediaQuery.of(context).copyWith().size.width * 0.01,
// top: MediaQuery.of(context).copyWith().size.height * 0.20,
// bottom: MediaQuery.of(context).copyWith().size.height * 0.7,
child: Row(
children: <Widget>[
// invisible FABs
FloatingActionButton(
onPressed: (){
_animate2Pagenegative();
// print(widget.date);
},
child: Icon(Icons.fast_rewind),
heroTag: UniqueKey(),
),
FloatingActionButton(
onPressed: (){
_animate2Pageforward();
// print(widget.date);
},
heroTag: UniqueKey(),
child: Icon(Icons.fast_forward),
),
],
),
),
// FAB which is displayed correctly
FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () async{
String result1 = await Navigator.push( // string which stores the user entered value
context,
MaterialPageRoute(
builder: (context) => InputScreen(), //screen which has TextField
));
setState(() {
addItem(result1, false, "");
});
},
tooltip: 'Add a task',
child: Icon(Icons.add),
elevation: 0.0,
),
],
),
)
body of Scaffold:
body: new Column(
children: <Widget>[
new Expanded(
child: new DaysPageView(
// onDaysChanged: getDatestring,
physics: new NeverScrollableScrollPhysics(),
dayoverride: getDate(widget.date),
scrollDirection: _scrollDirection,
pageSnapping: _pageSnapping,
reverse: _reverse,
controller: _daysPageController,
pageBuilder: _daysPageBuilder,
),
),
],
),
You don't need other FloatingActionsButtons to do that design. What I understand is that you need the upper part not to scroll with the content hence you thought of FABs. There are multiple ways to achieve that. Here is an example, I'm using colors to show you the different parts of your screen. And of course these are random sizes to show the case.
return new Scaffold(
body: Column(
children: <Widget>[
Container(
height: 150,
color: Colors.red,
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20, left: 20),
child: Text(
"- 2 TASKS MORE",
style: TextStyle(
fontSize: 35
),
),
),
GestureDetector(
onTap: () {
print('left arrow pressed');
},
child: Container(
margin: EdgeInsets.only(top: 20, left: 20),
child: Icon(Icons.arrow_left)
),
),
GestureDetector(
onTap: () {
print('right arrow pressed');
},
child: Container(
margin: EdgeInsets.only(top: 20, left: 20),
child: Icon(Icons.arrow_right)
),
)
],
),
SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Column(
children: <Widget>[
Container(
height: 600,
color: Colors.deepPurpleAccent,
),
],
),
)
],
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
],
),
shape: CircularNotchedRectangle(),
color: Colors.red,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: ()
async {
print('FAB pressed');
},
tooltip: 'Add a task',
child: Icon(Icons.add),
elevation: 0.0,
),
);
And here is the result

Loop Cards Flutter

I have been researching Flutter and a question arose --
I have an array with some information, and I need to add cards based on this array.
Currently, I create a loop and add the cards which follow the structure of my array and my program listed below. Note that when I call statement passing the parameters, the code runs without any problem, but the following code does not work for me:
import "package:acessorias/pages/global.variables.dart";
import "package:flutter/material.dart";
class Comunicados extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: Center(
child: SizedBox(
width: 150,
child: Image.asset("assets/image/logo.png"),
),
),
actions: <Widget>[
Container(
width: 60,
child: FlatButton(
child: Icon(
Icons.search,
color: Color(0xFFBABABA),
),
onPressed: () => {},
),
),
],
),
body: Container(
color: Color(0xFFF2F3F6),
child: ListView(
children: <Widget>[
comunicado(comunicados[0]["LogNome"], comunicados[0]["EmComDTH"],
comunicados[0]["EmComDesc"]),
comunicado(comunicados[1]["LogNome"], comunicados[1]["EmComDTH"],
comunicados[1]["EmComDesc"]),
comunicado(comunicados[2]["LogNome"], comunicados[2]["EmComDTH"],
comunicados[2]["EmComDesc"]),
comunicado(comunicados[3]["LogNome"], comunicados[3]["EmComDTH"],
comunicados[3]["EmComDesc"]),
comunicado(comunicados[4]["LogNome"], comunicados[4]["EmComDTH"],
comunicados[4]["EmComDesc"]),
comunicado(comunicados[5]["LogNome"], comunicados[5]["EmComDTH"],
comunicados[5]["EmComDesc"])
],
),
),
);
}
}
Widget comunicado(user, data, msg) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage("assets/image/foto.png"),
),
title: new Text(user),
subtitle: Text(data),
trailing: Icon(Icons.more_vert),
),
/*Container(
child: Image.asset("assets/image/post.png"),
),*/
Container(
padding: EdgeInsets.all(10),
child: Text(msg),
),
ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Icon(Icons.favorite),
onPressed: () {},
),
FlatButton(
child: Icon(Icons.share),
onPressed: () {},
),
],
),
),
],
),
);
}
Solution
body: ListView.builder(
itemCount: comunicados.length,
itemBuilder: (context, index) {
/*return ListTile(
title: Text('${comunicados[index]}'),
);*/
return comunicado(comunicados[index]['LogNome'],
comunicados[index]["EmComDTH"], comunicados[index]["EmComDesc"]);
},
),
You can use data model in another dart file like Comunicado.dart
class Comunicado{
String user;
String data;
String msg;
Comunicado(
{this.user, this.data, this.msg});
}
after that you can make list of data model with the static data or etc like
List getComunicado(){
return[
Comunicado(
user: comunicados[0]["LogNome"],
data: comunicados[0]["EmComDTH"],
msg: comunicados[0]["EmComDesc"],
),
Comunicado(
user: comunicados[1]["LogNome"],
data: comunicados[1]["EmComDTH"],
msg: comunicados[1]["EmComDesc"],
),
]
}
in my case, i put it into initial state and don't forget to declare comm
#override
void initState() {
super.initState();
comm= getComunicado();
}
for custom card
Card makeCard(Comunicado newComm) => Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage("assets/image/foto.png"),
),
title: new Text("${newComm.user}"),
subtitle: Text("${newComm.data}"),
trailing: Icon(Icons.more_vert),
),
/*Container(
child: Image.asset("assets/image/post.png"),
),*/
Container(
padding: EdgeInsets.all(10),
child: Text("${newComm.msg}"),
),
ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Icon(Icons.favorite),
onPressed: () {},
),
FlatButton(
child: Icon(Icons.share),
onPressed: () {},
),
],
),
),
],
),
);
and for last you can call make card on listview
ListView.builder(
scrollDirection: Axis.vertical,
itemCount: comm.length,
itemBuilder: (BuildContext context, int index) {
return makeCard(comm[index]);
},
),

Expanded() widget not working in listview

I'm new to flutter. I'm trying to render a page whose body contains Listview with multiple widgets.
_buildOrderDetails widget in the listview is widget that is build with listview.builder() , remaining are normal widgets.
The problem is page is not being scrolled .
When the body Listview is changed to column and _buildOrderDetails is given as child to the Expanded, the listview is limited to some extent of the page height and being scrolled. But when input is focused the page is overflowed
Widget build(BuildContext context){
return ScopedModelDescendant<MainModel>(
builder: (BuildContext context, Widget child, MainModel model) {
return Scaffold(
appBar: AppBar(
title: Text('Order Details'),
actions: <Widget>[
IconButton(
onPressed: () {
model.addNewOrder();
},
icon: Icon(Icons.add),
),
BadgeIconButton(
itemCount: model.ordersCount,
badgeColor: Color.fromRGBO(37, 134, 16, 1.0),
badgeTextColor: Colors.white,
icon: Icon(Icons.shopping_cart, size: 30.0,),
onPressed: () {}
),
]
),
body: ListView(
children: [
Column(
children: [
_buildItemsTitle(),
Expanded(child: _buildOrderDetails(context, model)),
]
),
Card(
child: Column(
children:[
TextField(
decoration: InputDecoration(
labelText: 'Offer Code'
),
),
RaisedButton(
onPressed: (){},
child: Text('Apply'),
)
]
),
),
Card(child: _orderAmount(context, model),),
RaisedButton(
color: Theme.of(context).accentColor,
onPressed: (){},
child: Text('Checkout',
style: TextStyle(
fontSize: 20.0,
color: Colors.white
)
),
)
]
),);});}}
Maybe it can help someone in the future, but the trick seems to be: use ListView + LimitedBox(maxHeight) + Column ...
ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
children: [
FocusTraversalGroup(
child: Form(
key: _formKey,
child: LimitedBox(
maxHeight: MediaQuery.of(context).size.height,
child: Column(
// mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Spacer(flex: 30), // Or Expanded
// More Widgets...
Spacer(flex: 70), // Or Expanded
// ....
Try not to use expanded on growing items. If you want to cover a percentage/fractional height wrap the height with a fixed height or the full height with a container that includes box contstains, then proceed to have expanded or fixed height children. also helpful is the FracionalBox
In the example you showed there is no need for expanded, the children inside will give a content height and the SingleChildScrollView will automaticly handle scrolling based on children.
Widget build(BuildContext context) {
return ScopedModelDescendant<MainModel>(
builder: (BuildContext context, Widget child, MainModel model) {
return Scaffold(
appBar: AppBar(title: Text('Order Details'), actions: <Widget>[
IconButton(
onPressed: () {
model.addNewOrder();
},
icon: Icon(Icons.add),
),
BadgeIconButton(
itemCount: model.ordersCount,
badgeColor: Color.fromRGBO(37, 134, 16, 1.0),
badgeTextColor: Colors.white,
icon: Icon(
Icons.shopping_cart,
size: 30.0,
),
onPressed: () {}),
]),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Column(children: [
_buildItemsTitle(),
Container(child: _buildOrderDetails(context, model)),
]),
Card(
child: Column(children: [
TextField(
decoration: InputDecoration(labelText: 'Offer Code'),
),
RaisedButton(
onPressed: () {},
child: Text('Apply'),
)
]),
),
Card(
child: _orderAmount(context, model),
),
RaisedButton(
color: Theme.of(context).accentColor,
onPressed: () {},
child: Text('Checkout',
style: TextStyle(fontSize: 20.0, color: Colors.white)),
),
],
),
),
);
});
}