Padding and text on Icon Button - flutter - flutter

I am creating a menu with IconButton, but I want to decrease the space between the buttons.
Currently It looks like this:
But I want this:
Also, I would like to know how to put the text below each button, just like the image. I have tried to use other types of button but didn't worked.
This is Menu.dart code:
import 'package:flutter/material.dart';
void main() => runApp(Menu());
class Menu extends StatefulWidget {
const Menu({super.key});
#override
State<Menu> createState() => _MenuState();
}
class _MenuState extends State<Menu> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color.fromARGB(255, 160, 244, 230),
elevation: 0,
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 90),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color.fromARGB(255, 160, 244, 230), Color.fromARGB(255, 92, 172, 178)]
)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Image.asset("assets/entrada.png"),
iconSize: 190,
onPressed: () {},
),
IconButton(
icon: Image.asset("assets/saida.png"),
iconSize: 190,
onPressed: () {},
),
IconButton(
icon: Image.asset("assets/categorias.png"),
iconSize: 190,
onPressed: () {},
)
]
)
)
);
}
}

First you need to build your custom button like this:
Widget customButton(
{required String image,
required String title,
required Function() onTap,
required Size size}) {
return GestureDetector(
onTap: onTap,
child: Container(
color: Colors.transparent,
child: Column(
children: [
Container(
height: size.height,
width: size.width,
constraints: BoxConstraints(maxHeight: 130, maxWidth: 130),
child: Image.asset(image),
),
Text(title),
],
),
),
);
}
then use it like this:
Padding(
padding: const EdgeInsets.symmetric(vertical: 32.0),
child: LayoutBuilder(builder: (context, constraints) {
var buttonMargin = 32.0;
var buttonSize = constraints.maxHeight / 3 - buttonMargin;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
customButton(
image: "assets/entrada.png",
title: 'some text',
onTap: () {},
size: Size(buttonSize, buttonSize),
),
Padding(
padding: EdgeInsets.symmetric(vertical: buttonMargin),
child: customButton(
image: "assets/saida.png",
title: 'some text 2',
onTap: () {},
size: Size(buttonSize, buttonSize),
),
),
customButton(
image: "assets/categorias.png",
title: 'some text 3',
onTap: () {},
size: Size(buttonSize, buttonSize),
),
],
);
}),
)

Related

Flutter how to add a dialog screen over main screen like this

Hi all,
I would like to add a screen that slowly appears form the bottom or the screen and partially covers the main screen below. So you can still see the top part of the main screen. Does anyone know how to do this?
Thank you very much
for this you can use showModalBottomSheet method the simple example is
import 'package:flutter/material.dart';
void main() => runApp(const BottomSheetApp());
class BottomSheetApp extends StatelessWidget {
const BottomSheetApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Bottom Sheet Sample')),
body: const BottomSheetExample(),
),
);
}
}
class BottomSheetExample extends StatelessWidget {
const BottomSheetExample({super.key});
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Modal BottomSheet'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () => Navigator.pop(context),
),
],
),
),
);
},
);
},
),
);
}
}
you can read more about this method here
You can use showModalBottomSheet() same as below...
showModalBottomSheet<void>(
// context and builder are
// required properties in this widget
context: context,
builder: (BuildContext context) {
// we set up a container inside which
// we create center column and display text
// Returning SizedBox instead of a Container
return SizedBox(
height: MediaQuery.of(context).size.height * 0.6,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text('HERE You'll add all your content'),
],
),
),
);
},
);
You can call above method in
initState() of screen or buttons onPressed or onTap.
As per your shared Image I have try something like that Using ModalBottomSheet
Your Button Widget
ElevatedButton(
child: const Text('Show Modal BottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0)),
),
context: context,
builder: (BuildContext context) {
return modelSheet(context);
},
);
},
)
bottomSheet Widget:
modelSheet(BuildContext context) {
return Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0)),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Icon(
Icons.hourglass_empty_outlined,
color: Colors.red,
size: 40,
),
const SizedBox(
height: 10,
),
const Text(
'Beta version',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(
Icons.check,
color: Colors.red,
),
Text('better price')
],
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(
Icons.check,
color: Colors.red,
),
Text('early access')
],
),
const SizedBox(
height: 20,
),
RichText(
text: const TextSpan(
text:
'Please mind that this is a beta version of the app. As a founding member you can get',
style: TextStyle(fontSize: 20, color: Colors.black),
children: <TextSpan>[
TextSpan(
text: '50% off',
style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: ' the price & early access. !'),
],
),
),
const SizedBox(
height: 20,
),
const Text(
'You can look forward to more teachers and practices very soon.'),
const SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
fixedSize: const Size(double.maxFinite, 50)),
child: const Text('Got it'),
),
],
),
),
);
}
Result Screen->

how print the call log when onpressed in flutter?

1.I'm try to making a flutter Dialer like calling app
2.How to show the call log in Listview
3.But i tried several ways i known an via the online tutorials it doesn't work
4.How to make call logs flutter
5.It print in Debug Console
6.I want to shows the call log numbers only
7.I also tried call log package but it also doesn't work for me
import 'package:callapp/models/logss.dart';
import 'package:flutter/material.dart';
import 'package:flutter_phone_direct_caller/flutter_phone_direct_caller.dart';
class MyHomePage extends StatefulWidget {
late final List<Phone> phone;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'];
List icon = [IconButton(onPressed: () {}, icon: Icon(Icons.one_k))];
String display = '';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Center(
child: Text(
display,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w300),
)),
Center(
child: Container(
height: 310,
width: 250,
child: GridView.builder(
itemCount: 12,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 10 / 8,
mainAxisSpacing: 2),
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.grey),
child: InkWell(
onTap: () {
setState(() {
display = display + numbers[index];
});
},
child: Center(child: Text(numbers[index]))));
}),
),
),
Container(
width: 220,
child: Stack(
children: [
Align(
alignment: Alignment.centerLeft,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.blue),
child: IconButton(
iconSize: 30,
icon: Icon(Icons.person),
onPressed: () {
setState(() {
FlutterPhoneDirectCaller.callNumber(display);
});
},
),
),
),
Align(
alignment: Alignment.center,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.green),
child: IconButton(
iconSize: 30,
icon: Icon(Icons.phone),
onPressed: () {
setState(() {
FlutterPhoneDirectCaller.callNumber(display);
Text(display);
print(display);
});
},
),
),
),
Align(
alignment: Alignment.centerRight,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.red),
child: IconButton(
icon: Icon(Icons.backspace),
onPressed: () {
if (display.length != 0) {
setState(() {
display = display.substring(0, display.length - 1);
});
}
},
),
),
)
],
),
),
],
),
);
}
}

How to change positions of icons in AppBar in flutter?

I am trying to reposition my "compass" icon near the "search" icon from the App bar. Everytime i try to make a change in the container with higher value 55 for example "padding: const EdgeInsets.symmetric(horizontal: 50)," i get error stack over flow. Also when i try to change the logo(png) the allingment, nothing happens. Help please!
Image
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[Colors.pink[400], Colors.blue[400]]
),
),
),
title: Row(
children: [
Container(
alignment: Alignment.center,
height: 40,
child: SizedBox(
child: Image.asset(
'assets/images/logox.png',
)
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 50),
child: SizedBox(
child: Icon(
Icons.explore_rounded,
))),
// Container(child: Icon(Icons.explore_rounded)),
],
),
actions: [
GestureDetector(
onTap: () {
// authMethods.signOut();
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => SearchScreen(),
));
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Icon(Icons.search)),
)
],
),
drawer: MainDrawer(),
//body: Body(),
bottomNavigationBar: GradientBottomNavigationBar(
fixedColor: Colors.white,
backgroundColorStart: Colors.pink[400],
backgroundColorEnd: Colors.blue[400],
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(
icon: Icon(Icons.wallet_membership), title: Text('QUA')),
BottomNavigationBarItem(
icon: Icon(Icons.help), title: Text('Help')),
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.pink,
elevation: 50,
hoverColor: Colors.red,
autofocus: true,
onPressed: () {
print('hi');
},
child: Icon(
Icons.comment,
),
tooltip: 'Pick Image',
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat);
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
}
There is actions property in AppBar widget which is mainly used to put icons in AppBar. And in your case centerTitle is used to align your image to center
Output
Full code
class MyHomePage extends StatefulWidget {
final Function onItemPressed;
MyHomePage({
Key key,
this.onItemPressed,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[Colors.pink[400], Colors.blue[400]]),
),
),
centerTitle: true,
title: Container(
alignment: Alignment.center,
height: 40,
child: SizedBox(
child: Image.asset(
'assets/logo.png',
)),
),
actions: [
IconButton(
onPressed: () {},
icon: Icon(Icons.explore_rounded),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.search),
)
],
),
);
}
}
Material appbar has an actions property, you can use that to put search and compass icon together. In order to achieve the same remove
Container(
padding: const EdgeInsets.symmetric(horizontal: 50),
child: SizedBox(
child: Icon(
Icons.explore_rounded,
))),
from its current position and add it into the actions property just above the search button.

How to make bottom bar same like in image

how can I make bottom bar to look same like in image, top corners to be rounded and to icons have the space same like in image.
here is code of bottomMenu bar how is right now.. so basically to have rounded corner and to icon have padding from left and right. but if I add whole BottomNavigationBar in padding then it not move just icons.. hope that somebody can help me to fix this..
Scaffold(
body: _handlePages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
items: <BottomNavigationBarItem>[
_currentIndex == 0
? BottomNavigationBarItem(
icon: Image.asset(
"assets/images/cam.png",
height: 25,
color: appColorBlue,
),
label: "",
)
: BottomNavigationBarItem(
icon: Image.asset(
"assets/images/cam.png",
height: 25,
color: appColorGrey,
),
label: "",
),
_currentIndex == 1
? BottomNavigationBarItem(
icon: Image.asset(
"assets/images/call_blue.png",
height: 27,
color: appColorBlue,
),
label: "",
)
: BottomNavigationBarItem(
icon: Image.asset(
"assets/images/call_blue.png",
height: 27,
color: appColorGrey,
),
label: "",
),
_currentIndex == 2
? BottomNavigationBarItem(
icon: Image.asset(
"assets/images/chat.png",
height: 27,
color: appColorBlue,
),
label: "",
)
: BottomNavigationBarItem(
icon: Image.asset(
"assets/images/chat.png",
height: 27,
color: appColorGrey,
),
label: "",
),
_currentIndex == 3
? BottomNavigationBarItem(
icon: Container(
height: 30,
width: 30,
child: new Stack(
children: <Widget>[
globalImage.length > 0
? CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(globalImage),
)
: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: Colors.grey[400],
shape: BoxShape.circle),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
"assets/images/user.png",
height: 10,
color: Colors.white,
),
)),
],
),
),
// Image.asset(
// "assets/images/settings.png",
// height: 25,
// color: appColorBlue,
// ),
label: "",
)
: BottomNavigationBarItem(
icon: Container(
height: 30,
width: 30,
child: new Stack(
children: <Widget>[
globalImage.length > 0
? CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(globalImage),
)
: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: Colors.grey[400],
shape: BoxShape.circle),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
"assets/images/user.png",
height: 10,
color: Colors.white,
),
)),
],
),
),
// Image.asset(
// "assets/images/settings.png",
// height: 25,
// color: appColorGrey,
// ),
label: "",
),
],
),
),
You can create your own bottom nav bar so that you can design it freely.
Sample...
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: List.generate(
100,
(index) => ListTile(
title: Text('TEST $index'),
),
),
),
bottomNavigationBar: const RoundedBottomNavBar(
onTap: print,
children: const <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.camera_alt)),
BottomNavigationBarItem(icon: Icon(Icons.phone)),
BottomNavigationBarItem(icon: Icon(Icons.send)),
BottomNavigationBarItem(icon: Icon(Icons.circle)),
],
childrenPadding: const EdgeInsets.symmetric(horizontal: 10),
),
);
}
}
class RoundedBottomNavBar extends StatefulWidget {
const RoundedBottomNavBar({
required this.onTap,
required this.children,
this.background = Colors.white,
this.topCornerRadius = 20,
this.childrenPadding = const EdgeInsets.all(0),
});
final ValueChanged<int> onTap;
final List<BottomNavigationBarItem> children;
final Color background;
final double topCornerRadius;
final EdgeInsetsGeometry childrenPadding;
#override
_RoundedBottomNavBarState createState() => _RoundedBottomNavBarState();
}
class _RoundedBottomNavBarState extends State<RoundedBottomNavBar> {
late Radius _topCornerRadius;
int _selectedIndex = 0;
#override
void initState() {
super.initState();
_topCornerRadius = Radius.circular(widget.topCornerRadius);
}
#override
Widget build(BuildContext context) {
int tmpCount = 0;
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
color: widget.background,
borderRadius: BorderRadius.only(
topLeft: _topCornerRadius,
topRight: _topCornerRadius,
),
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: widget.children.map((BottomNavigationBarItem item) {
final int index = tmpCount++;
return GestureDetector(
onTap: () {
setState(() => _selectedIndex = index);
widget.onTap(index);
},
child: Opacity(
opacity: _selectedIndex == index ? 1 : 0.3,
child: Padding(
padding: widget.childrenPadding,
child: item.icon,
),
),
);
}).toList(),
),
),
);
}
}
a solution can be adding your custom bottomNvigationBar, playing with the colors and the shadow, also de radius, something like this:
this is the body
Scaffold(
bottomNavigationBar: bottom(),
appBar: AppBar(
title: Center(child: Text("test")),
),
body: Container(),
);
and here is the bottom widget:
Widget bottom() {
return Container(
height: 60, //you can do it with mediaQuery
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 5.0,
spreadRadius: 2.0,
),
],
color: Colors.blue,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25),
topRight: Radius.circular(25),
)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
GestureDetector(
onTap: () {
print("hello, i press ");
},
child: Icon(
Icons.camera_alt,
size: 35,
),
),
GestureDetector(
onTap: () {
print("hello, i press ");
},
child: Icon(
Icons.phone,
size: 35,
),
),
GestureDetector(
onTap: () {
print("hello, i press ");
},
child: Icon(
Icons.near_me,
size: 35,
)),
],
));
}
here a screenshot of the result:

confused about setState inside onTap Flutter

I've been trying to learn Flutter and this part got me really confused. Thanks a million for your help.
I wanted to return data (an object) to the first screen from the second screen. I did successfully thanks to posts I read from the internet but haven't managed to fully understand. Specifically: Why do I need to assign categoryData to the returned object then again assign it to categoryCard? Why can't I do it directly by assigning categoryCard to the returned Object? This is code that works:
First screen:
SizedBox(
height: 95,
child: GestureDetector(
onTap: () async {
final categoryData =
await Navigator.pushNamed(context, '/EditCategory');
setState(() => categoryCard = categoryData);
},
child: categoryCard),
),
Second screen:
return Card(
child: ListTile(
title: Text('${myText[index]}'),
leading: myIcon[index],
trailing: Icon(Icons.arrow_forward_ios),
onTap: () {
Navigator.pop(
context,
CategoryCard(
categoryIcon: myIcon[index],
categoryText: Text(
'${myText[index]}',
style: TextStyle(fontSize: 20),
)));
},
),
);
Code I think should work but doesn't
First screen:
SizedBox(
height: 95,
child: GestureDetector(
onTap: () {
setState(() async {
CategoryCard categoryCard =
await Navigator.pushNamed(context, '/EditCategory');
});
},
child: categoryCard),
),
Second screen is the same
This is the entire code of the first and second screen in case you'd like to know:
First:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'MyApp.dart';
class Input extends StatefulWidget {
#override
_InputState createState() => _InputState();
}
class _InputState extends State<Input> {
CategoryCard categoryCard = CategoryCard();
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(210, 234, 251, 1),
appBar: appBarInEx(),
body: TabBarView(
children: [
ListView(
children: [
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter the value';
}
return null;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState.validate()) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Processing Data')));
}
},
child: Text('Submit'),
),
),
],
),
),
SizedBox(
height: 150,
child: Card(
color: Color.fromRGBO(254, 228, 194, 1),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(
height: 20,
),
Text(
'Amount',
style: TextStyle(fontSize: 30),
),
SizedBox(
height: 15,
),
Text(r'0$',
style: TextStyle(
fontSize: 30,
)),
Text('_____________________________________',
style: TextStyle(
fontSize: 15,
))
],
),
),
),
),
SizedBox(
height: 95,
child: GestureDetector(
onTap: () async {
final categoryData =
await Navigator.pushNamed(context, '/EditCategory');
setState(() => categoryCard = categoryData);
},
child: categoryCard),
),
SizedBox(
height: 95,
child: Card(
color: Color.fromRGBO(254, 228, 194, 1),
child: ListTile(
contentPadding:
EdgeInsets.symmetric(vertical: 18, horizontal: 16),
title: Text(
'Note',
style: TextStyle(fontSize: 20),
),
leading: Icon(Icons.description_outlined, size: 40),
trailing: Icon(
Icons.arrow_forward_ios_outlined,
size: 30,
),
),
),
),
SizedBox(
height: 95,
child: Card(
color: Color.fromRGBO(254, 228, 194, 1),
child: ListTile(
contentPadding:
EdgeInsets.symmetric(vertical: 18, horizontal: 16),
title: Text(
'Date',
style: TextStyle(fontSize: 20),
),
leading: Icon(Icons.event, size: 40),
trailing: Icon(
Icons.arrow_forward_ios_outlined,
size: 30,
),
),
),
),
Container(
margin: EdgeInsets.fromLTRB(30, 70, 30, 0),
child: Padding(
padding: const EdgeInsets.all(18.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.red)),
elevation: 10,
color: Colors.lime,
onPressed: () {
Navigator.pushNamed(context, '/');
},
textColor: Colors.white,
child: Text(
'Save',
style: TextStyle(fontSize: 40),
),
),
),
)
],
),
Container()
],
),
);
}
}
class CategoryCard extends StatelessWidget {
final Text categoryText;
final Icon categoryIcon;
CategoryCard(
{Key key,
this.categoryText = const Text(
'Category',
style: TextStyle(fontSize: 20),
),
this.categoryIcon = const Icon(
Icons.category_outlined,
size: 40,
)})
: super(key: key);
#override
Widget build(BuildContext context) {
return Card(
color: Color.fromRGBO(254, 228, 194, 1),
child: ListTile(
contentPadding: EdgeInsets.symmetric(vertical: 18, horizontal: 16),
title: categoryText,
leading: categoryIcon,
trailing: Icon(
Icons.arrow_forward_ios_outlined,
size: 30,
),
),
);
}
}
Second:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:material_floating_search_bar/material_floating_search_bar.dart';
import 'Input.dart';
import 'MyApp.dart';
class EditCategory extends StatefulWidget {
#override
_EditCategoryState createState() => _EditCategoryState();
}
class _EditCategoryState extends State<EditCategory> {
List<String> myText = [
'Add Category',
'Cosmetic',
'Education',
'Clothes',
'Food',
'Cosmetic',
'Education',
'Clothes',
'Food'
];
List<Widget> myIcon = [
Icon(Icons.add_circle_outline),
Icon(Icons.no_food_outlined),
Icon(Icons.face),
Icon(Icons.book_outlined),
Icon(Icons.g_translate),
Icon(Icons.no_food_outlined),
Icon(Icons.face),
Icon(Icons.book_outlined),
Icon(Icons.g_translate),
];
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
backgroundColor: Color.fromRGBO(210, 234, 251, 1),
appBar: appBarInEx(),
body: TabBarView(
children: [
Column(
children: [
FloatingSearchAppBar(
title: const Text('Enter Category Name'),
transitionDuration: const Duration(milliseconds: 800),
color: Colors.orangeAccent.shade100,
colorOnScroll: Colors.greenAccent.shade200,
height: 55,
),
Expanded(
child: ListView.builder(
itemCount: myText.length,
itemBuilder: (context, index) {
if (index == 0) {
return SizedBox(
height: 90,
child: Card(
child: ListTile(
title: Text('${myText[index]}'),
leading: myIcon[index],
trailing: Icon(Icons.arrow_forward_ios),
),
));
}
return Card(
child: ListTile(
title: Text('${myText[index]}'),
leading: myIcon[index],
trailing: Icon(Icons.arrow_forward_ios),
onTap: () {
Navigator.pop(
context,
CategoryCard(
categoryIcon: myIcon[index],
categoryText: Text(
'${myText[index]}',
style: TextStyle(fontSize: 20),
)));
},
),
);
},
)),
],
),
Container()
],
),
),
);
}
}
The good code waits for the onTap and assign the result into a local variable. Then it uses setState to assign the local variable into the instance field.
Why do I need to assign categoryData to the returned object then again assign it to categoryCard? Why can't I do it directly by assigning categoryCard to the returned Object?
You can do that actually, this will work:
GestureDetector(
onTap: () async {
categoryData = await Navigator.push(...);
setState(() {});
},
),
Basically setState tells Flutter to rebuild your widget, it's not strictly required to perform state setting within the callback.
Regarding bad code: you use setState with an async callback so Flutter will just rebuild your widget immediately at that moment, it doesn't wait for your async operation to complete. At the time of rebuild, categoryData has the old value so nothing changes on the screen. When user triggers onTap on the second screen and pops back to the first, categoryData is updated with the new value but your widget is not rebuilt so it still shows outdated data.