How to pass data/Images from one page to another in Bottom Navigation Bar - android

I wanted to send Data/images from one page to another. In the Homepage when I tap on the add Icon button image should be passed to the Cart page and if the icon is tapped again image is removed from the Cart page. But, the cart page should be accessed from bottom navigation bar.
but it is showing an error called 1 positional argument(s) expected, but 0 found.
Try adding the missing arguments.. when it calls the cart page.
HomePage.dart file
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blueGrey,
),
home: NavBar(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Dish> _dishes = List<Dish>();
List<Dish> _cartList = List<Dish>();
#override
void initState() {
super.initState();
_populateDishes();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16.0, top: 8.0),
child: GestureDetector(
child: Stack(
alignment: Alignment.topCenter,
children: <Widget>[
Icon(
Icons.shopping_cart,
size: 36.0,
),
if (_cartList.length > 0)
Padding(
padding: const EdgeInsets.only(left: 2.0),
child: CircleAvatar(
radius: 8.0,
backgroundColor: Colors.red,
foregroundColor: Colors.white,
child: Text(
_cartList.length.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12.0,
),
),
),
),
],
),
onTap: () {
if (_cartList.isNotEmpty)
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Cart(_cartList),
),
);
},
),
)
],
),
body: _buildGridView(),
);
}
ListView _buildListView() {
return ListView.builder(
itemCount: _dishes.length,
itemBuilder: (context, index) {
var item = _dishes[index];
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 2.0,
),
child: Card(
elevation: 4.0,
child: ListTile(
leading: Icon(
item.icon,
color: item.color,
),
title: Text(item.name),
trailing: GestureDetector(
child: (!_cartList.contains(item))
? Icon(
Icons.add_circle,
color: Colors.green,
)
: Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
setState(() {
if (!_cartList.contains(item))
_cartList.add(item);
else
_cartList.remove(item);
});
},
),
),
),
);
},
);
}
GridView _buildGridView() {
return GridView.builder(
padding: const EdgeInsets.all(4.0),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: _dishes.length,
itemBuilder: (context, index) {
var item = _dishes[index];
return Card(
elevation: 4.0,
child: Stack(
fit: StackFit.loose,
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
item.icon,
color: (_cartList.contains(item))
? Colors.grey
: item.color,
size: 100.0,
),
Text(
item.name,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subhead,
)
],
),
Padding(
padding: const EdgeInsets.only(
right: 8.0,
bottom: 8.0,
),
child: Align(
alignment: Alignment.bottomRight,
child: GestureDetector(
child: (!_cartList.contains(item))
? Icon(
Icons.add_circle,
color: Colors.green,
)
: Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
setState(() {
if (!_cartList.contains(item))
_cartList.add(item);
else
_cartList.remove(item);
});
},
),
),
),
],
));
});
}
void _populateDishes() {
var list = <Dish>[
Dish(
name: 'Chicken Zinger',
icon: Icons.fastfood,
color: Colors.amber,
),
Dish(
name: 'Chicken Zinger without chicken',
icon: Icons.print,
color: Colors.deepOrange,
),
Dish(
name: 'Rice',
icon: Icons.child_care,
color: Colors.brown,
),
Dish(
name: 'Beef burger without beef',
icon: Icons.whatshot,
color: Colors.green,
),
Dish(
name: 'Laptop without OS',
icon: Icons.laptop,
color: Colors.purple,
),
Dish(
name: 'Mac wihout macOS',
icon: Icons.laptop_mac,
color: Colors.blueGrey,
),
];
setState(() {
_dishes = list;
});
}
}
Cart.dart file
import 'package:flutter/material.dart';
import 'dish_object.dart';
class Cart extends StatefulWidget {
final List<Dish> _cart;
Cart(this._cart);
#override
_CartState createState() => _CartState(this._cart);
}
class _CartState extends State<Cart> {
_CartState(this._cart);
List<Dish> _cart;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Cart'),
),
body: ListView.builder(
itemCount: _cart.length,
itemBuilder: (context, index) {
var item = _cart[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2.0),
child: Card(
elevation: 4.0,
child: ListTile(
leading: Icon(
item.icon,
color: item.color,
),
title: Text(item.name),
trailing: GestureDetector(
child: Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
setState(() {
_cart.remove(item);
});
},
),
),
),
);
},
),
);
}
}
NavBar.dart file
import 'package:flutter/material.dart';
import 'package:sharewallpaper/cart.dart';
import 'package:sharewallpaper/main.dart';
class NavBar extends StatefulWidget {
#override
_NavBarState createState() => _NavBarState();
}
class _NavBarState extends State<NavBar> {
int _currentIndex = 0;
final List<Widget> _children = [
MyHomePage(),
Cart(), ** This line is throwing an error **
];
void onTappedBar(int index) {
setState(() {
_currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTappedBar,
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(
icon: Icon(Icons.bookmark), title: Text('BookMark')),
],
),
);
}
}

Yep, it will throw an error because the constructor of the Cart class is expecting one parameter to be passed in. You could use a named constructor instead like this:
class Cart extends StatefulWidget {
final List<Dish> _cart;
Cart(this._cart);
That way, you can call it like so:
Cart(cart: _cartList),
But if you actually need the cart list, I would recommend that you write a provider to keep track of the cart data across screens.

Related

In Flutter How do you navigate to a different page and click on a button to navigate to a specfic bottomnavigationtab? I am using Gnav

I am trying to understand how to return to a specific bottomtabindex. As of now I used a hacky way of ading an index to the HomePage as you can see. The issue is I cannot pass the Game object to HomePage too because it feels anti pattern. The Game Object should be passed to the Game Widget/screen
class HomePage extends StatefulWidget {
final int? index;
const HomePage({Key? key, this.index}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
_selectedIndex = widget.index?? 0;
}
int _selectedIndex = 0;
void _navigateBottomBar(int index) {
setState(() {
_selectedIndex = index;
});
}
List<Widget> screens = [
GameHistory(),
Game(),
Statistics(),
Help()
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
children: <Widget>[
Image.asset("assets/images/logo.png", width: 50, height:50),
const Text("App")
],
),
backgroundColor: Colors.deepPurple,
elevation: 10.0,
actions: [
IconButton(
icon: const Icon(Icons.add_circle_outline),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const CreateGame()),
);
},
)
],
),
body: screens[_selectedIndex],
bottomNavigationBar: Container(
color: Colors.black,
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20),
child: GNav(
selectedIndex: _selectedIndex,
onTabChange: _navigateBottomBar,
backgroundColor: Colors.black,
color: Colors.white,
activeColor: Colors.white,
tabBackgroundColor: Colors.deepPurple,
gap: 8,
padding: const EdgeInsets.all(16),
tabs: const [
GButton(icon: Icons.home, text: 'Home'),
GButton(icon: Icons.play_arrow_outlined, text: 'Current Game',),
GButton(icon: Icons.leaderboard_outlined, text: 'Statistics'),
GButton(icon: Icons.help_outline_rounded, text: 'Rules'),
],),
),
);
}
}
//create game widget
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepPurple,
elevation: 10.0,
title: const Text('Create Game'),
),
body: Column(
children: [
const Padding(
padding: EdgeInsets.all(12.0),
child: Text("Team names"),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: Row(children: [
Expanded(
child: TextField(
controller: player2,
decoration: const InputDecoration(hintText: "Playername"),
),
)
])
),
const Center(
child: Text("Versus",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(children: [
Expanded(
child: TextField(
controller: player4,
decoration: const InputDecoration(hintText: "Player name"),
),
)
])
),
const Text("Game Type"),
DropdownButton<String>(
value: gameType,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String? newValue) {
setState(() {
gameType = newValue!;
});
},
items: items
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
Center(
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black),
),
onPressed: () {
// Navigate to game screen and pass information
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => const HomePage(index: 1,)),
(route) =>false,
);
},
child: const Text('Start Game!'),
),
),
],
),
);
}
}

How to pass method into another class in flutter

I tried to create a task app using flutter, So I created a text field in DialogBox and my aim is when I add some text into the text field and when I clicked the OK button, I need to show that text in the list. but I have no idea how to call a method in another class, I've added my two classes.
ListTask Class
import 'package:flutter/material.dart';
class ListTask extends StatefulWidget {
const ListTask({Key? key}) : super(key: key);
#override
State<ListTask> createState() => _ListTaskState();
}
class _ListTaskState extends State<ListTask> {
final List<String> tasks = ['masu', 'adasf', 'wfqf', 'santha'];
final TextEditingController _textFieldController = TextEditingController();
void addItemToList() {
setState(() {
tasks.insert(0, _textFieldController.text);
});
}
#override
Widget build(BuildContext context) {
return Container(
height: 320,
width: double.maxFinite,
child: ListView.builder(
padding: EdgeInsets.only(bottom: 10),
itemCount: tasks.length,
itemBuilder: (context, index) {
return Card(
elevation: 1,
color: Colors.grey[200],
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ExpansionTile(title: Text(tasks[index]), children: <Widget>[
ListTile(
title: Text(tasks[index]),
)
]),
],
),
);
},
),
);
}
Future<void> _displayTextInputDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('TextField in Dialog'),
content: TextField(
onChanged: (value) {
setState(() {
// valueText = value;
});
},
controller: _textFieldController,
decoration: InputDecoration(hintText: "Text Field in Dialog"),
),
actions: <Widget>[
FlatButton(
color: Colors.red,
textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
FlatButton(
color: Colors.green,
textColor: Colors.white,
child: Text('OK'),
onPressed: () {
setState(() {
addItemToList();
Navigator.pop(context);
});
},
),
],
);
});
}
}
TaskApp Class
import 'package:flutter/material.dart';
import 'package:task_app/Widgets/listtasks.dart';
import 'package:task_app/Widgets/logo.dart';
import 'package:task_app/Widgets/searchbar.dart';
class TaskApp extends StatefulWidget {
const TaskApp({Key? key}) : super(key: key);
#override
State<TaskApp> createState() => _TaskAppState();
}
class _TaskAppState extends State<TaskApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
Logo(),
SizedBox(height: 0),
SearchBar(),
SizedBox(height: 15),
Column(
children: [
Text(
'All tasks',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15.0),
)
],
),
SizedBox(height: 15),
ListTask(),
],
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
_displayTextInputDialog(context);
},
label: const Text('Add Task'),
icon: const Icon(Icons.add),
backgroundColor: Colors.blue[900],
),
);
}
}
Calling point of that method in TaskApp Class:
Method:
You can give this a try, it will call a method defined in ListTask(StatefulWidget) from TaskApp(StatefulWidget) widget.
TaskApp.dart
import 'package:flutter/material.dart';
import 'package:vcare/Screens/tetxing1.dart';
class TaskApp extends StatefulWidget {
final ListTask listTask;
const TaskApp({Key? key,required this.listTask}) : super(key: key);
#override
State<TaskApp> createState() => _TaskAppState();
}
class _TaskAppState extends State<TaskApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
// Logo(),
SizedBox(height: 0),
//SearchBar(),
SizedBox(height: 15),
Column(
children: [
Text(
'All tasks',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15.0),
)
],
),
SizedBox(height: 15),
ListTask(),
],
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
ListTask().method1(context);
},
label: const Text('Add Task'),
icon: const Icon(Icons.add),
backgroundColor: Colors.blue[900],
),
);
}
}
ListTask.dart
import 'package:flutter/material.dart';
class ListTask extends StatefulWidget {
method1(context) => createState().displayTextInputDialog(context);
#override
_ListTaskState createState() => _ListTaskState();
}
class _ListTaskState extends State<ListTask> {
final List<String> tasks = ['masu', 'adasf', 'wfqf', 'santha'];
final TextEditingController _textFieldController = TextEditingController();
void addItemToList() {
setState(() {
tasks.insert(0, _textFieldController.text);
});
}
#override
Widget build(BuildContext context) {
return Container(
height: 320,
width: double.maxFinite,
child: ListView.builder(
padding: EdgeInsets.only(bottom: 10),
itemCount: tasks.length,
itemBuilder: (context, index) {
return Card(
elevation: 1,
color: Colors.grey[200],
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ExpansionTile(title: Text(tasks[index]), children: <Widget>[
ListTile(
title: Text(tasks[index]),
)
]),
],
),
);
},
),
);
}
Future<void> displayTextInputDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('TextField in Dialog'),
content: TextField(
onChanged: (value) {
setState(() {
// valueText = value;
});
},
controller: _textFieldController,
decoration: InputDecoration(hintText: "Text Field in Dialog"),
),
actions: <Widget>[
FlatButton(
color: Colors.red,
textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
FlatButton(
color: Colors.green,
textColor: Colors.white,
child: Text('OK'),
onPressed: () {
setState(() {
addItemToList();
Navigator.pop(context);
});
},
),
],
);
});
}
}
if you find this solution helpful please mark as accepted answer

Flutter ListView on click navigate to another screen

I'm learning Flutter. I have a ListView and I would like to make the list items clickable. My idea is that when the user clicks on an item, it will be directed to another screen. Each buttom should leads to different screen. I'm having trouble implementing it, I don't know what to use: gesture detector or ontap. What should I do? Should I use ListTile instead of ListView?
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final title = "ListView List";
return MaterialApp(
title: title,
home: Scaffold(appBar: AppBar(
title: Text(title),
),
body: new ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(20.0),
children: List.generate(choices.length, (index) {
return Center(
child: ChoiceCard(choice: choices[index], item: choices[index]),
);
}
)
)
)
);
}
}
class Choice {
const Choice({this.title, this.icon});
final String title;
final IconData icon;
}
const List<Choice> choices = const <Choice>[
const Choice(title: 'This is a Car', icon: Icons.directions_car),
const Choice(title: 'This is a Bicycle', icon: Icons.directions_bike),
const Choice(title: 'This is a Boat', icon: Icons.directions_boat),
const Choice(title: 'This is a Bus', icon: Icons.directions_bus),
const Choice(title: 'This is a Train', icon: Icons.directions_railway),
];
class ChoiceCard extends StatelessWidget {
const ChoiceCard(
{Key key, this.choice, this.onTap, #required this.item, this.selected: false}
) : super(key: key);
final Choice choice;
final VoidCallback onTap;
final Choice item;
final bool selected;
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.display1;
if (selected)
textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
return Card(
color: Colors.white,
child: Row(
children: <Widget>[
new Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.topLeft,
child: Icon(choice.icon, size:80.0, color: textStyle.color,)),
new Expanded(
child: new Container(
padding: const EdgeInsets.all(10.0),
alignment: Alignment.topLeft,
child:
Text(choice.title, style: null, textAlign: TextAlign.left, maxLines: 5,),
)
),
],
crossAxisAlignment: CrossAxisAlignment.start,
)
);
}
}
You can copy paste run full code below
Step 1: To allow Navigator.push work, you can move MaterialApp to upper level
Step 2: In onTap pass Navigator.push
ChoiceCard(
choice: choices[index],
item: choices[index],
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Detail(choice: choices[index])),
);
},
),
Step 3: Wrap Card with InkWell and call onTap()
return InkWell(
onTap: () {
onTap();
},
child: Card(
working demo
full code
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 {
final title = "ListView List";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: new ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(20.0),
children: List.generate(choices.length, (index) {
return Center(
child: ChoiceCard(
choice: choices[index],
item: choices[index],
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Detail(choice: choices[index])),
);
},
),
);
})));
}
}
class Choice {
const Choice({this.title, this.icon});
final String title;
final IconData icon;
}
const List<Choice> choices = const <Choice>[
const Choice(title: 'This is a Car', icon: Icons.directions_car),
const Choice(title: 'This is a Bicycle', icon: Icons.directions_bike),
const Choice(title: 'This is a Boat', icon: Icons.directions_boat),
const Choice(title: 'This is a Bus', icon: Icons.directions_bus),
const Choice(title: 'This is a Train', icon: Icons.directions_railway),
];
class ChoiceCard extends StatelessWidget {
const ChoiceCard(
{Key key,
this.choice,
this.onTap,
#required this.item,
this.selected: false})
: super(key: key);
final Choice choice;
final VoidCallback onTap;
final Choice item;
final bool selected;
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.display1;
if (selected)
textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
return InkWell(
onTap: () {
onTap();
},
child: Card(
color: Colors.white,
child: Row(
children: <Widget>[
new Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.topLeft,
child: Icon(
choice.icon,
size: 80.0,
color: textStyle.color,
)),
new Expanded(
child: new Container(
padding: const EdgeInsets.all(10.0),
alignment: Alignment.topLeft,
child: Text(
choice.title,
style: null,
textAlign: TextAlign.left,
maxLines: 5,
),
)),
],
crossAxisAlignment: CrossAxisAlignment.start,
)),
);
}
}
class Detail extends StatelessWidget {
final Choice choice;
Detail({this.choice});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Column(
children: <Widget>[
Text("${choice.title}"),
Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
],
),
);
}
}
import 'package:easy_buss/screen/client.dart';
import 'package:easy_buss/screen/invoice.dart';
import 'package:easy_buss/screen/invoice_settings.dart';
import 'package:easy_buss/screen/payment_info.dart';
import 'package:easy_buss/widgets/payment_info_form.dart';
import 'package:flutter/material.dart';
class Settings extends StatefulWidget {
#override
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
List<IconData> _icon = [
Icons.accessible,
Icons.analytics,
Icons.question_answer_sharp,
Icons.message,
Icons.share,
Icons.star_half,
Icons.add_business,
Icons.privacy_tip,
];
List<String> _title = [
'Invoice Settings',
'Reports',
'Frequently Ask Questions',
'Write Us',
'Share With A Friends',
'Rate Us',
'Terms & Conditions',
'Privacy Policy',
];
List<Color> _colors = [
Colors.cyan,
Colors.yellow,
Colors.red,
Colors.purple,
Colors.orange,
Colors.grey,
Colors.pink[300],
Colors.green[200],
];
List _items = [
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
InvoiceSettings(),
];
#override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: _title.length,
separatorBuilder: (BuildContext context, int index) => Container(
padding: EdgeInsets.only(
left: 10,
right: 10,
),
child: Divider(
thickness: 1,
),
),
itemBuilder: (BuildContext context, int index) => ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => _items[index],
),
);
},
leading: Container(
padding: const EdgeInsets.all(5.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: _colors[index],
),
child: Icon(
_icon[index],
color: Colors.white,
size: 20,
),
),
title: Text(
_title[index],
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
trailing: Icon(
Icons.chevron_right,
size: 40,
),
),
);
}
}

Flutter highlight current selected nav item

I have created a starter kit in flutter for a personal project.
Everything is working fine but I have an iisue where I'm unable to highlight the current selected item in the drawer.
I'm abit lost on where I chould be put the code that determins the current selected item.
Below is my code!
class _MdDrawerState extends State<MdDrawer>
with SingleTickerProviderStateMixin<MdDrawer> {
final _animationDuration = const Duration(milliseconds: 350);
AnimationController _animationController;
Stream<bool> isDrawerOpenStream;
StreamController<bool> isDrawerOpenStreamController;
StreamSink<bool> isDrawerOpenSink;
.....
#override
void dispose() {
_animationController.dispose();
isDrawerOpenStreamController.close();
isDrawerOpenSink.close();
super.dispose();
}
void onIconPressed() {
final animationStatus = _animationController.status;
final isAnimationCompleted = animationStatus == AnimationStatus.completed;
.....
}
#override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
return StreamBuilder<bool>(
initialData: false,
stream: isDrawerOpenStream,
builder: (context, isLeftDrawerOpenedAsync) {
return AnimatedPositioned(
duration: _animationDuration,
top: 0,
bottom: 0,
left: isLeftDrawerOpenedAsync.data ? 0 : -screenWidth,
right: isLeftDrawerOpenedAsync.data ? 0 : screenWidth - 45,
child: Row(
children: <Widget>[
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
color: Theme.of(context).backgroundColor,
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
SizedBox(
height: 30,
),
ListTile(
title: Text('First - Last',
style: Theme.of(context).textTheme.headline),
subtitle: Text('something#gmail.com',
style: Theme.of(context).textTheme.subhead),
leading: CircleAvatar(
child: Icon(
Icons.perm_identity,
color: Theme.of(context).iconTheme.color,
),
radius: 40,
),
),
Divider(
height: 30,
),
MdNavItem(
icon: Icons.home,
title: 'Home',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.HomeClickedEvent);
},
),
MdNavItem(
icon: Icons.account_box,
title: 'Account',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.AccountClickedEvent);
},
),
MdNavItem(
icon: Icons.shopping_basket,
title: 'Orders',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.OrderClickedEvent);
},
),
MdNavItem(
icon: Icons.card_giftcard,
title: 'Wishlist',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.WishlistClickedEvent);
},
),
Divider(
height: 30,
),
MdNavItem(
icon: Icons.settings,
title: 'Settings',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.SettingsClickedEvent);
},
),
MdNavItem(
icon: Icons.exit_to_app,
title: 'Logout',
),
Divider(
height: 45,
),
],
),
],
),
),
),
......
],
),
);
},
);
}
}
And the MdNavItem class
class MdNavItem extends StatelessWidget {
final IconData icon;
final String title;
final Function onTap;
const MdNavItem({this.icon, this.title, this.onTap});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(16),
child: Container(
color: Theme.of(context).backgroundColor,
child: Row(
children: <Widget>[
Icon(
icon,
size: 25,
color: Theme.of(context).iconTheme.color,
),
SizedBox(
width: 20,
),
Text(
title,
style: Theme.of(context).textTheme.headline,
),
],
),
),
),
);
}
}
Edit:
First Way to do:
Add this code to your Drawer:
class _MdDrawerState extends State<MdDrawer>
with SingleTickerProviderStateMixin<MdDrawer> {
final _animationDuration = const Duration(milliseconds: 350);
AnimationController _animationController;
Stream<bool> isDrawerOpenStream;
StreamController<bool> isDrawerOpenStreamController;
StreamSink<bool> isDrawerOpenSink;
final List<bool> isTaped = [true, false, false, false, false]; // the first is true because when the app
//launch the home needs to be in red(or the
//color you choose)
void changeHighlight(int index){
for(int indexTap = 0; indexTap < isTaped.length; indexTap++) {
if (indexTap == index) {
isTaped[index] = true; //used to change the value of the bool list
} else {
isTaped[indexTap] = false;
}
}
}
.....
#override
void dispose() {
_animationController.dispose();
isDrawerOpenStreamController.close();
isDrawerOpenSink.close();
super.dispose();
}
void onIconPressed() {
final animationStatus = _animationController.status;
final isAnimationCompleted = animationStatus == AnimationStatus.completed;
.....
}
#override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
return StreamBuilder<bool>(
initialData: false,
stream: isDrawerOpenStream,
builder: (context, isLeftDrawerOpenedAsync) {
return AnimatedPositioned(
duration: _animationDuration,
top: 0,
bottom: 0,
left: isLeftDrawerOpenedAsync.data ? 0 : -screenWidth,
right: isLeftDrawerOpenedAsync.data ? 0 : screenWidth - 45,
child: Row(
children: <Widget>[
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
color: Theme.of(context).backgroundColor,
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
SizedBox(
height: 30,
),
ListTile(
title: Text('First - Last',
style: Theme.of(context).textTheme.headline),
subtitle: Text('something#gmail.com',
style: Theme.of(context).textTheme.subhead),
leading: CircleAvatar(
child: Icon(
Icons.perm_identity,
color: Theme.of(context).iconTheme.color,
),
radius: 40,
),
),
Divider(
height: 30,
),
MdNavItem(
wasTaped: isTaped[0],
icon: Icons.home,
title: 'Home',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.HomeClickedEvent);
changeHighlight(0);
},
),
MdNavItem(
wasTaped: isTaped[1],
icon: Icons.account_box,
title: 'Account',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.AccountClickedEvent);
changeHighlight(1);
},
),
MdNavItem(
wasTaped: isTaped[2],
icon: Icons.shopping_basket,
title: 'Orders',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.OrderClickedEvent);
changeHighlight(2);
},
),
MdNavItem(
wasTaped: isTaped[3],
icon: Icons.card_giftcard,
title: 'Wishlist',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.WishlistClickedEvent);
changeHighlight(3);
},
),
Divider(
height: 30,
),
MdNavItem(
wasTaped: isTaped[4],
icon: Icons.settings,
title: 'Settings',
onTap: () {
onIconPressed();
BlocProvider.of<MdNavBloc>(context)
.add(NavigationEvents.SettingsClickedEvent);
changeHighlight(4);
},
),
MdNavItem(
icon: Icons.exit_to_app,
title: 'Logout',
),
Divider(
height: 45,
),
],
),
],
),
),
),
......
],
),
);
},
);
}
}
And this to your MdNavItem:
class MdNavItem extends StatelessWidget {
final IconData icon;
final String title;
final Function onTap;
final bool wasTaped; //receiving the bool value (if was taped or not)
const MdNavItem({this.icon, this.title, this.onTap, this.wasTaped});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(16),
child: Container(
color: Theme.of(context).backgroundColor,
child: Row(
children: <Widget>[
Icon(
icon,
size: 25,
color: wasTaped ? Colors.red : Theme.of(context).iconTheme.color, //the condition to change the color
),
SizedBox(
width: 20,
),
Text(
title,
style: wasTaped ? TextStyle(
color: Colors.red,
) : Theme.of(context).textTheme.headline,
),
],
),
),
),
);
}
}
Old answer, Second way:
First Screen, where PageView is placed:
class FirstScreen extends StatelessWidget {
final PageController pageController = PageController(initialPage: 0);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kit App'),
),
drawer: CustomDrawer(
pageController: pageController,
),
body: PageView(
controller: pageController,
physics: NeverScrollableScrollPhysics(), //to prevent scroll
children: <Widget>[
HomeScreen(),
AccountScreen(), //your pages
OrdersScreen(),
WishListScreen(),
],
),
);
}
}
The CustomDrawer:
class CustomDrawer extends StatelessWidget {
CustomDrawer({#required this.pageController});
final PageController pageController;
#override
Widget build(BuildContext context) {
return Drawer(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 20),
child: Column(
children: <Widget>[
DrawerItem(
onTap: (){
Navigator.pop(context); //to close the drawer
pageController.jumpToPage(0);
},
leading: Icons.home,
title: 'Home',
index: 0,
controller: pageController,
),
DrawerItem(
onTap: (){
Navigator.pop(context);
pageController.jumpToPage(1);
},
leading: Icons.account_box,
title: 'Account',
index: 1,
controller: pageController,
),
DrawerItem(
onTap: (){
Navigator.pop(context);
pageController.jumpToPage(2);
},
leading: Icons.shopping_cart,
title: 'Orders',
index: 2,
controller: pageController,
),
DrawerItem(
onTap: (){
Navigator.pop(context);
pageController.jumpToPage(3);
},
leading: Icons.card_travel,
title: 'Wishlist',
index: 3,
controller: pageController,
),
],
),
),
);
}
}
and the DrawerItem, where the condition to change the color of the items is placed:
class DrawerItem extends StatelessWidget {
DrawerItem({
#required this.onTap,
#required this.leading,
#required this.title,
#required this.index,
#required this.controller,
});
final VoidCallback onTap;
final IconData leading;
final String title;
final int index;
final PageController controller;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: ListTile(
leading: Icon(
leading,
color: controller.page.round() == index ? Colors.red : Colors.grey,
),
title: Text(
title,
style: TextStyle(
color: controller.page.round() == index ? Colors.red : Colors.grey,
),
),
),
);
}
}
Result:
Now you just need to implement this on your code.

Flutter AlertDialog with ListView and bottom TextField

I'm working on a Flutter project and I was trying to achieve an AlertDialog similar to the option's dialog specified on MaterialDesign Guidelines, but with a TextInput at the bottom.
I have managed to get something similar to what I want but I there's a problem I can't solve: when the user taps on TextInput and the keyboard appears, I'd like the TextInput to be on top of the keyboard with the listview getting smaller on the y-axis (that's why I'm just setting maxHeight on ConstrainedBox), so that the user can see what he texts, but I'm getting just the opposite, the listview keeps the same size and the InputText is not visible.
I have tried changing the listview with a column nested on a SingleChildScrollView, or wrapping the entire original Column on a SingleChildScrollView, but none of them seems to work.
This is my current code:
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(widget.title),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20))
),
actions: <Widget>[
FlatButton(
child: const Text('CANCEL'),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).accentColor,
onPressed: () {
widget.onCancel();
},
),
FlatButton(
child: const Text('OK'),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).accentColor,
onPressed: () {
widget.onOk();
},
),
],
content: Container(
width: double.maxFinite,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Divider(),
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height*0.4,
),
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.exercises.length,
itemBuilder: (BuildContext context, int index){
return RadioListTile(
title: Text(widget.exercises[index].name),
value: index,
groupValue: _selected,
onChanged: (value){
setState(() {
_selected = index;
});
}
);
}
),
),
Divider(),
TextField(
autofocus: false,
maxLines: 1,
style: TextStyle(fontSize: 18),
decoration: new InputDecoration(
border: InputBorder.none,
hintText: widget.hintText,
),
),
],
),
),
);
}
Could somebody provide me some help?
Thanks a lot!!
You can copy paste run full code below
You can in content use SingleChildScrollView
code snippet
content: SingleChildScrollView(
child: Container(
width: double.maxFinite,
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class Exercise {
String name;
Exercise({this.name});
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
List<Exercise> exercises = [
Exercise(name: 'A'),
Exercise(name: 'B'),
Exercise(name: 'C'),
Exercise(name: 'D'),
Exercise(name: 'E'),
Exercise(name: 'F'),
Exercise(name: 'G')
];
int _selected;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(widget.title),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20))),
actions: <Widget>[
FlatButton(
child: const Text('CANCEL'),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).accentColor,
onPressed: () {
//widget.onCancel();
},
),
FlatButton(
child: const Text('OK'),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).accentColor,
onPressed: () {
//widget.onOk();
},
),
],
content: SingleChildScrollView(
child: Container(
width: double.maxFinite,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Divider(),
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.4,
),
child: ListView.builder(
shrinkWrap: true,
itemCount: exercises.length,
itemBuilder: (BuildContext context, int index) {
return RadioListTile(
title: Text(exercises[index].name),
value: index,
groupValue: _selected,
onChanged: (value) {
setState(() {
_selected = index;
});
});
}),
),
Divider(),
TextField(
autofocus: false,
maxLines: 1,
style: TextStyle(fontSize: 18),
decoration: new InputDecoration(
border: InputBorder.none,
hintText: "hint",
),
),
],
),
),
),
);
}
}

Categories

Resources