chips to filter the data - flutter

I want to filter the data of people based on the jobs selected in chips
Let's say if the Maid chip is selected I should show some 5-6 maids and a see-all button
Similarly, if the Engineer chip is selected then only 5-6 engineers should be shown
These filtered data should also be horizontally scrollable.
I'm learning flutter so we can use any dummy data to achieve this and also I want it to be like a card so that I can show persons pic, and some related info and their ratings.
And also i would like to keep the chip size constant for all , basically it should take the chip size of the longest word if possible
My code Till now
import 'package:flutter/material.dart';
import 'package:mad_ezee_app/constants.dart';
import 'package:flutter/src/rendering/box.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _selectedIndex = 0;
PageController pageController = PageController();
List array =["Maid","Driver","Engineer","Gardener","Pilot"];
void onTapped(int index){
setState(() {
_selectedIndex = index;
});
pageController.jumpToPage(index);
}
void tappedCategory(int index){
setState(() {
_selectedIndex = index;
});
print(index);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children:[
Container(
child: Container(
margin: EdgeInsets.only(top:45,bottom: 15),
padding: EdgeInsets.only(left: 20,right: 20),
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children:[
Text("Bengaluru"),
Text("R.T Nagar")
]
),
Container(
width: 45,
height:45,
padding: EdgeInsets.only(left: 0,right: 0),
child: Icon(Icons.search,color: Colors.white,),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color:TimePassColor.APP_COLOR
),
),
Container(
width: 45,
height:45,
child: Icon(Icons.notifications,color: Colors.white,),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color:TimePassColor.APP_COLOR
),
),
]
)
)
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List<Widget>.generate(
array.length, // place the length of the array here
(int index) {
return Container(
margin: EdgeInsets.all(2.0),
child: GestureDetector(
onTap: (){
print(index);
},
child: Chip(
label: Text(array[index])
),
),
);
}
).toList(),
),
),
Expanded(
child:ListView(
// This next line does the trick.
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 160.0,
color: Colors.red,
),
Container(
width: 160.0,
color: Colors.blue,
),
Container(
width: 160.0,
color: Colors.green,
),
Container(
width: 160.0,
color: Colors.yellow,
),
Container(
width: 160.0,
color: Colors.orange,
),
],
),
),
Expanded(
child: PageView(
controller: pageController,
children: [
Container(color: Colors.white,),
Container(color: Colors.white,),
Container(color: Colors.white,),
Container(color: Colors.white,),
Container(color: Colors.white,),
Container(color: Colors.white,),
Container(color: Colors.white,),
Container(color: Colors.white,),
],
),
),
]
),
bottomNavigationBar: BottomNavigationBar(items: const <BottomNavigationBarItem> [
BottomNavigationBarItem(icon: Icon(Icons.home),label:'Home'),
BottomNavigationBarItem(icon: Icon(Icons.cleaning_services),label:'House Keeping'),
BottomNavigationBarItem(icon: Icon(Icons.search),label:'Search'),
BottomNavigationBarItem(icon: Icon(Icons.account_balance_wallet),label:'Wallet'),
BottomNavigationBarItem(icon: Icon(Icons.bookmarks),label:'Bookmarked'),
BottomNavigationBarItem(icon: Icon(Icons.local_convenience_store),label:'Store'),
BottomNavigationBarItem(icon: Icon(Icons.notifications),label:'Notifications'),
BottomNavigationBarItem(icon: Icon(Icons.assessment),label:'Notifications'),
BottomNavigationBarItem(icon: Icon(Icons.person),label:'Profile'),
],currentIndex: _selectedIndex,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
onTap: onTapped,
)
);
}
}
Sample Data could be like this:-
data =[
{
"name":"Sachin Rajput",
"profilePic":"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category":["cleaning","Mopping","Engineer"]
"rating":5
},
:
]
Note :- A person can have multiple profession
*Current Output

I guess this works for you.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _selectedIndex = 0;
int _selectedCategoryIndex = -1;
String _selectedUserType = "Maid";
PageController pageController = PageController();
List array = ["Maid", "Driver", "Engineer", "Gardener", "Pilot"];
List data = [
{
"name": "Sachin Rajput",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Maid", "Engineer"],
"rating": 5,
"bg": Colors.red
},
{
"name": "Sachin Tendulkar",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Gardener", "Pilot", "Engineer"],
"rating": 5,
"bg": Colors.amberAccent
}
];
List filteredData = [];
void onTapped(int index) {
setState(() {
_selectedIndex = index;
});
pageController.jumpToPage(index);
}
void tappedCategory(int index) {
_selectedCategoryIndex = index;
_selectedUserType = array[index];
_filterData();
}
#override
void initState() {
super.initState();
_filterData();
}
_filterData() {
filteredData = _selectedCategoryIndex >= 0 ? data.where((element) => element["category"].contains(_selectedUserType)).toList() : data;
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(mainAxisSize: MainAxisSize.min, children: [
Container(
margin: const EdgeInsets.only(top: 45, bottom: 15),
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(children: const [
Text("Bengaluru"),
Text("R.T Nagar")
]),
Container(
width: 45,
height: 45,
padding: const EdgeInsets.only(left: 0, right: 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.red),
child: const Icon(
Icons.search,
color: Colors.white,
),
),
Container(
width: 45,
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.red),
child: const Icon(
Icons.notifications,
color: Colors.white,
),
),
])),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List<Widget>.generate(
array.length, // place the length of the array here
(int index) {
return Container(
margin: const EdgeInsets.all(2.0),
child: GestureDetector(
onTap: () {
tappedCategory(index);
},
child: Chip(label: Text(array[index])),
),
);
}).toList(),
),
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: filteredData.length,
itemBuilder: (context, index) {
var item = filteredData[index];
return Container(
width: 160.0,
color: item['bg'],
child: Center(
child: Text(item["name"].toString()),
),
);
},
// This next line does the trick.
),
),
]),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(
icon: Icon(Icons.cleaning_services), label: 'House Keeping'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet), label: 'Wallet'),
BottomNavigationBarItem(
icon: Icon(Icons.bookmarks), label: 'Bookmarked'),
BottomNavigationBarItem(
icon: Icon(Icons.local_convenience_store), label: 'Store'),
BottomNavigationBarItem(
icon: Icon(Icons.notifications), label: 'Notifications'),
BottomNavigationBarItem(
icon: Icon(Icons.assessment), label: 'Notifications'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
onTap: onTapped,
));
}
}
A suggestion is to reduce the number of items in the bottom nav bar. 4 to 5 is optimum, and 6 is a worst-case scenario. But you have 9 items, which will be difficult to access on smaller devices, and especially fat finger problems will easily frustrate the end-user.

Related

Flutter: A list of generated TextFields deletes item at the final index regardless of the index passed

Assuming I have created 10 fields and use the delete button at index 2, the fields reduce to 9 but the item in index 10 is deleted instead of deleting 2 and moving up the others. I have written some minimal reproduction of the code
Here is the sample code.
import 'package:flutter/material.dart';
void main() {
runApp(const EditFields());
}
class EditFields extends StatefulWidget {
const EditFields({Key? key}) : super(key: key);
#override
State<EditFields> createState() => _EditFieldsState();
}
class _EditFieldsState extends State<EditFields> {
List<String> openRoles = [];
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ShrinkWrap vs Slivers',
home: Scaffold(
appBar: AppBar(
title: const Text("ShrinkWrap"),
),
body: Column(
children: [
...List.generate(
openRoles.length,
(i) {
return Row(
children: [
SizedBox(
width: 300,
child: TextFormField(
maxLines: 1,
key: Key('rolefield$i'),
//..decoration
onChanged: (value) {
setState(() {
openRoles[i] = value!;
});
},
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: InkWell(
onTap: () {
openRoles.removeAt(i);
setState(() {});
},
child: const Icon(
Icons.delete,
color: Colors.red,
size: 24,
),
),
),
],
);
},
),
ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
primary: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
side: const BorderSide(color: Colors.blue))),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Padding(
padding: EdgeInsets.all(4.0),
child: Icon(
Icons.add_rounded,
size: 25,
color: Colors.blue,
),
),
Text('ADD', style: TextStyle(color: Colors.blue)),
],
),
onPressed: () {
openRoles.add("Text");
setState(() {});
}),
],
),
),
);
}
}
The issue is with using key, once a single item remove key changes by from
List.generate(
openRoles.length,
(i) {
If we do use map instead of list, removing n item, Data will for n> items. We can use TextEditingController in this case to work properly
class EditFields extends StatefulWidget {
const EditFields({Key? key}) : super(key: key);
#override
State<EditFields> createState() => _EditFieldsState();
}
class _EditFieldsState extends State<EditFields> {
List<TextEditingController> controllers = [];
int counterX = 0;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ShrinkWrap vs Slivers',
home: Scaffold(
appBar: AppBar(
title: const Text("ShrinkWrap"),
),
body: Column(
children: [
for (final c in controllers) rowB(c),
ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
primary: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
side: const BorderSide(color: Colors.blue))),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Padding(
padding: EdgeInsets.all(4.0),
child: Icon(
Icons.add_rounded,
size: 25,
color: Colors.blue,
),
),
Text('ADD', style: TextStyle(color: Colors.blue)),
],
),
onPressed: () {
controllers.add(TextEditingController());
setState(() {});
}),
],
),
),
);
}
Row rowB(TextEditingController c) {
return Row(
children: [
SizedBox(
width: 300,
child: TextFormField(
maxLines: 1,
controller: c,
//..decoration
onChanged: (value) {
setState(() {});
},
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: InkWell(
onTap: () {
controllers.remove(c);
setState(() {});
},
child: const Icon(
Icons.delete,
color: Colors.red,
size: 24,
),
),
),
],
);
}
}

How to use Gesture control and change color on chip selection in Flutter

context :
I want to click on a particular services person/product and open a page where details can be shown more like a details page
Problem
I think that Gesture control should work but I'm not able to put it the right way in my code
How to change chip color on selection the data is getting filtered but i want to add 2 more things
highlight the chip that is selected
so a text message stating Not Available if there is nothing
available, rather then leaving blank and
My Code
class _HomeScreenState extends State<HomeScreen> {
int _selectedIndex = 0;
int _selectedCategoryIndex = -1;
String _selectedUserType = "Maid";
PageController pageController = PageController();
List array = ["Maid", "Driver", "Engineer", "Gardener", "Pilot","carpainter", "guard", "plumber"];
List data = [
{
"name": "Sachin Rajput",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Maid", "Engineer"],
"rating": 5,
"bg": Colors.red
},
{
"name": "Sachin Tendulkar",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Gardener", "Pilot", "Engineer"],
"rating": 5,
"bg": Colors.amberAccent
},
{
"name": "Sachin Test",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["carpainter", "guard", "plumber"],
"rating": 5,
"bg": Colors.blue
}
];
List product_data = [
{
"name": "P1",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Dusting"],
"rating": 5,
"bg": Colors.red
},
{
"name": "P2",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Mopping"],
"rating": 5,
"bg": Colors.amberAccent
},
{
"name": "P3",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["cleaning"],
"rating": 5,
"bg": Colors.blue
}
];
List filteredData = [];
void onTapped(int index) {
setState(() {
_selectedIndex = index;
});
pageController.jumpToPage(index);
}
void tappedCategory(int index) {
_selectedCategoryIndex = index;
_selectedUserType = array[index];
_filterData();
}
#override
void initState() {
super.initState();
_filterData();
}
_filterData() {
print(_selectedUserType);
filteredData = data.where((element) => element["category"].contains(_selectedUserType)).toList();
print(filteredData);
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: pageController,
children: [
SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 5),
child: Container(
// color: Colors.purple,
// margin: const EdgeInsets.only(top: 45, bottom: 15),
padding: const EdgeInsets.only(left: 10, right: 10),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Bengaluru",
style: TextStyle(
color: APP_COLOR.mainColor,
),
),
Text("R.T Nagar")
]),
),
customContainer(iconData: Icons.search,),
SizedBox(width: 10,),
customContainer(iconData: Icons.notifications,),
])),
),
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 10,horizontal: 10),
child: Align(
alignment: Alignment.centerLeft,
child:
Text(
'Popular Services',
),
),
),
Container(
height: MediaQuery.of(context).size.height / 12,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: List<Widget>.generate(
array.length, // place the length of the array here
(int index) {
return Container(
margin: const EdgeInsets.all(2.0),
child: GestureDetector(
onTap: () {
tappedCategory(index);
},
child: Chip(label: Text(array[index])),
),
);
}).toList(),
),
),
Container(
height: MediaQuery.of(context).size.height / 6,
child: ListView.builder(
scrollDirection: Axis.horizontal,
// physics: NeverScrollableScrollPhysics(),
itemCount: filteredData.length,
itemBuilder: (context, index) {
var item = filteredData[index];
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Container(
color: item['bg'],
child: Center(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Text(item["name"].toString()),
),
),
),
);
},
// This next line does the trick.
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 10,horizontal: 10),
child: Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,
children: [
Text(
'Popular Products',
),
Align(
alignment: Alignment.centerRight,
child:
Text(
'View All',
),
),
],
),
),
Container(
height: MediaQuery.of(context).size.height / 6,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: product_data.length,
itemBuilder: (context, index) {
var item = product_data[index];
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Container(
color: item['bg'],
child: Center(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 60),
child: Text(item["name"].toString()),
),
),
),
);
},
// This next line does the trick.
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 10,horizontal: 10),
child: Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,
children: [
Text(
'Our Products',
),
Align(
alignment: Alignment.centerRight,
child:
Text(
'View All',
),
),
],
),
),
Container(
height: MediaQuery.of(context).size.height / 6,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: product_data.length,
itemBuilder: (context, index) {
var item = product_data[index];
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Container(
color: item['bg'],
child: Center(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 60),
child: Text(item["name"].toString()),
),
),
),
);
},
// This next line does the trick.
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 10,horizontal: 10),
child: Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,
children: [
Text(
'New Products',
),
Align(
alignment: Alignment.centerRight,
child:
Text(
'View All',
),
),
],
),
),
Container(
height: MediaQuery.of(context).size.height / 6,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: product_data.length,
itemBuilder: (context, index) {
var item = product_data[index];
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Container(
color: item['bg'],
child: Center(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 60),
child: Text(item["name"].toString()),
),
),
),
);
},
),
),
],
),
),
)
]),
),
Container(color: Colors.blue,),
Container(color: Colors.white,),
Container(color: Colors.yellow,),
Container(color: Colors.blue,),
Container(color: Colors.white,),
Container(color: Colors.yellow,)
],
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(
icon: Icon(Icons.cleaning_services), label: 'Services'),
BottomNavigationBarItem(
icon: Icon(Icons.local_convenience_store), label: 'Store'),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet), label: 'Wallet'),
BottomNavigationBarItem(
icon: Icon(Icons.bookmarks), label: 'Bookmarked'),
BottomNavigationBarItem(
icon: Icon(Icons.assessment), label: 'Current Orders'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
currentIndex: _selectedIndex,
selectedItemColor: APP_COLOR.mainColor,
unselectedItemColor: Colors.grey,
onTap: onTapped,
));
}
Widget customContainer({required IconData iconData}){
return Container(
width: 45,
height: 45,
padding: const EdgeInsets.only(left: 0, right: 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: APP_COLOR.mainColor,),
child: Icon(
iconData,
color: Colors.white,
),
);
}
}
I've recently started the flutter journey so i might have asked a very basic question so it will be great if you can explain the changes as well taht you made so i can understand it better
Hope this helps
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
PageController pageController = PageController();
int _selectedIndex = 0;
void onTapped(int index) {
setState(() {
_selectedIndex = index;
});
pageController.jumpToPage(index);
}
#override
void dispose() {
pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: pageController,
children: [
const HomePage(),
Container(
color: Colors.blue,
),
Container(
color: Colors.white,
),
Container(
color: Colors.yellow,
),
Container(
color: Colors.blue,
),
Container(
color: Colors.white,
),
Container(
color: Colors.yellow,
)
],
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(
icon: Icon(Icons.cleaning_services), label: 'Services'),
BottomNavigationBarItem(
icon: Icon(Icons.local_convenience_store), label: 'Store'),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet), label: 'Wallet'),
BottomNavigationBarItem(
icon: Icon(Icons.bookmarks), label: 'Bookmarked'),
BottomNavigationBarItem(
icon: Icon(Icons.assessment), label: 'Current Orders'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.red,
unselectedItemColor: Colors.grey,
onTap: onTapped,
));
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _selectedCategoryIndex = 0;
String _selectedUserType = "Maid";
List array = [
"Maid",
"Driver",
"Engineer",
"Gardener",
"Pilot",
"carpainter",
"guard",
"plumber"
];
List data = [
{
"name": "Sachin Rajput",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Maid", "Engineer"],
"rating": 5,
"bg": Colors.red
},
{
"name": "Sachin Tendulkar",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Gardener", "Pilot", "Engineer"],
"rating": 5,
"bg": Colors.amberAccent
},
{
"name": "Sachin Test",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["carpainter", "guard", "plumber"],
"rating": 5,
"bg": Colors.blue
}
];
List product_data = [
{
"name": "P1",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Dusting"],
"rating": 5,
"bg": Colors.red
},
{
"name": "P2",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["Mopping"],
"rating": 5,
"bg": Colors.amberAccent
},
{
"name": "P3",
"profilePic":
"https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
"category": ["cleaning"],
"rating": 5,
"bg": Colors.blue
}
];
List filteredData = [];
void tappedCategory(int index) {
_selectedCategoryIndex = index;
_selectedUserType = array[index];
_filterData();
}
#override
void initState() {
super.initState();
_filterData();
}
#override
void dispose() {
super.dispose();
}
_filterData() {
filteredData = data
.where((element) => element["category"].contains(_selectedUserType))
.toList();
setState(() {});
}
Widget customContainer({required IconData iconData}) {
return Container(
width: 45,
height: 45,
padding: const EdgeInsets.only(left: 0, right: 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.red,
),
child: Icon(
iconData,
color: Colors.white,
),
);
}
Widget customProductsList({required String title, required List dataList}) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title),
const Align(
alignment: Alignment.centerRight,
child: Text(
'View All',
),
),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height / 6,
child: dataList.isNotEmpty
? ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: dataList.length,
itemBuilder: (context, index) {
var item = dataList[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Container(
color: item['bg'],
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 60),
child: Text(item["name"].toString()),
),
),
),
);
},
// This next line does the trick.
)
: const Center(
child: Text('No data found.'),
),
),
],
);
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: Container(
// color: Colors.purple,
// margin: const EdgeInsets.only(top: 45, bottom: 15),
padding: const EdgeInsets.only(left: 10, right: 10),
child: Row(children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Bengaluru",
style: TextStyle(
color: Colors.red,
),
),
const Text("R.T Nagar")
]),
),
customContainer(
iconData: Icons.search,
),
const SizedBox(
width: 10,
),
customContainer(
iconData: Icons.notifications,
),
])),
),
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
const Padding(
padding: EdgeInsets.symmetric(
vertical: 10, horizontal: 10),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
'Popular Services',
),
),
),
SizedBox(
height: MediaQuery.of(context).size.height / 12,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: List<Widget>.generate(
array
.length, // place the length of the array here
(int index) {
return Container(
margin: const EdgeInsets.all(2.0),
child: GestureDetector(
onTap: () {
tappedCategory(index);
},
child: Chip(
label: Text(array[index]),
backgroundColor:
_selectedCategoryIndex == index
? Colors.green
: Colors.grey,
),
),
);
}).toList(),
),
),
SizedBox(
height: MediaQuery.of(context).size.height / 6,
child: filteredData.isNotEmpty
? ListView.builder(
scrollDirection: Axis.horizontal,
// physics: NeverScrollableScrollPhysics(),
itemCount: filteredData.length,
itemBuilder: (context, index) {
var item = filteredData[index];
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10),
child: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
DetailPage(
user: item)));
},
child: Container(
color: item['bg'],
child: Center(
child: Padding(
padding: const EdgeInsets
.symmetric(
horizontal: 20),
child: Text(
item["name"].toString()),
),
),
),
),
);
},
// This next line does the trick.
)
: const Center(
child: Text(
"No records available for the selected category"),
),
),
customProductsList(
title: 'Popular Products',
dataList: product_data),
customProductsList(
title: 'Our Products', dataList: product_data),
customProductsList(
title: 'New Products', dataList: product_data)
],
),
),
)
]),
);
}
}
class DetailPage extends StatelessWidget {
const DetailPage({Key? key, this.user}) : super(key: key);
final dynamic user;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(user["name"]),
),
body: Container(
padding: EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
// mainAxisAlignment: MainAxisAlignment.center,
children: [
CircleAvatar(child: Image.network(user["profilePic"]), minRadius: 60,),
SizedBox(height: 10,),
Text("${user["name"]}"),
],
),
)
);
}
}
You can use: <true/false expressions> ? <if true> : <if false>
highlight the chip that is selected
Add an backgroundColor to Chip. index == _selectedCategoryIndex will check that chip is selected or not by index then set the color you want. In this case, that ex mean If the chip is selected chip, colored it!
- child: Chip(label: Text(array[index])),
+ child: Chip(
+ label: Text(array[index]),
+ backgroundColor: index == _selectedCategoryIndex ? APP_COLOR.mainColor : null),
+ )
so a text message stating Not Available if there is nothing available, rather then leaving blank and
Check filteredData have data then render what you want. In this case, ex mean If the filtered list is EMPTY, then render the Text insteads.
Detailer:
- Container(
- height: MediaQuery.of(context).size.height / 6,
- child: ListView.builder(...),
- ),
+ Container(
+ height: MediaQuery.of(context).size.height / 6,
+ child: filteredData.isNotEmpty
+ ? ListView.builder(...)
+ : Text('YOUR FILTERED LIST IS EMPTY'),
+ ),
Chip(
label: "label",
backgroundColor: _selectedCategoryIndex == index ? Colors.blue : Colors.green,
),
do not forgot to change tappedCategory function
replace your function with this,
void tappedCategory(int index) {
_selectedCategoryIndex = index;
_selectedUserType = array[index];
_filterData();
setState(() {});
}

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:

Is there a way to control the leading element behavior of NavigationRail in Flutter?

Flutter recently launched their v1.17 (latest stable release) and in that they have included a new widget "Navigation Rail".
Though this widget is still in its early stages(and I'm expecting a bit more additional properties like padding for NavigationRailDestination) it gives a whole new perspective to orthodox navigation.
So while Implementing this widget I've encountered a problem to which I'm searching for a workaround maybe a solution(if anybody has one!).
And that problem is when we try to implement the toggle between leading elements and the navigationRailDestinations using setState(){...} , the toggling happens only once and not for the whole lifecycle of the app.
I'm struggling to implement it please help!.
Here's the code snippet:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _selectedIndex = 0, menuColor = 0xFfFCCFA8;
final padding = 8.0;
//bool leadingProfileFlag = false, leadingSettingsFlag = false, contentFlag = true;
String profilePic, contentView = "dash";
getView(String contentView,int selectedIndex,int menuColor) {
switch (contentView) {
case 'MenuRails.selectedIndex':
return MenuRails(selectedIndex: selectedIndex,menuColor: menuColor,);
case '' : return MenuRails(selectedIndex: selectedIndex,menuColor: menuColor,);
case '2' : return MenuRails(selectedIndex: selectedIndex,menuColor: menuColor,);
case 'settings': return Expanded(child: Container());
case 'profile' : return Expanded(child: Container());
default: return MenuRails(selectedIndex: selectedIndex,menuColor: menuColor,);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff28292E),
resizeToAvoidBottomPadding: false,
body: Row(
children: <Widget>[
NavigationRail(
leading: Column(
children: <Widget>[
SizedBox(
height: 38,
),
InkWell(
splashColor: Color(0xffFCCFA8),
onTap: () {
setState(() {
contentView = 'profile';
});
},
child: Center(
child: CircleAvatar(
radius: 16,
backgroundImage: profilePic != null
? NetworkImage(profilePic)
: AssetImage('assets/dummy_profile.png'),
),
),
),
SizedBox(
height: 88,
),
RotatedBox(
quarterTurns: -1,
child: GestureDetector(
onTap: (){
setState(() {
contentView = 'settings';
});
},
child: IconButton(
icon: Icon(Icons.tune),
color: Color(0xffFCCFA8),
onPressed: () {
setState(() {});
},
),
),
)
],
),
backgroundColor: Color(0xff2D3035),
groupAlignment: 1.0,
minWidth: MediaQuery.of(context).size.width * 0.07,
elevation: 8.0,
minExtendedWidth: MediaQuery.of(context).size.width * 0.4,
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
contentView = _selectedIndex.toString();
});
},
selectedLabelTextStyle: TextStyle(
color: Color(0xffFCCFA8),
fontSize: 13,
letterSpacing: 0.8,
decoration: TextDecoration.underline,
decorationThickness: 2.0,
),
unselectedLabelTextStyle: TextStyle(
fontSize: 13,
letterSpacing: 0.8,
),
labelType: NavigationRailLabelType.all,
destinations: [
buildRotatedTextRailDestination("Dashboard", padding),
buildRotatedTextRailDestination("Shop", padding),
buildRotatedTextRailDestination("Service", padding),
],
/*
trailing: Column(
children: <Widget>[
SizedBox(height: 15,),
Icon(
Icons.exit_to_app,//Logout icon
color: Colors.white70,
),
SizedBox(height: 10,)
],
),
*/
),
//VerticalDivider(thickness: 1, width: 1),
// This is the main content.
getView(contentView,_selectedIndex,menuColor),
],
),
);
}
Widget menuRail() {
}
NavigationRailDestination buildRotatedTextRailDestination(
String text, double padding) {
return NavigationRailDestination(
icon: SizedBox.shrink(),
label: Padding(
padding: EdgeInsets.symmetric(vertical: padding),
child: RotatedBox(
quarterTurns: -1,
child: Text(text),
),
),
);
}
}
// ignore: must_be_immutable
class MenuRails extends StatefulWidget {
int menuColor;
final int selectedIndex;
MenuRails({this.menuColor,this.selectedIndex});
#override
_MenuRailsState createState() => _MenuRailsState();
}
class _MenuRailsState extends State<MenuRails> {
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
color: Colors.black54,
child: Column(
children: <Widget>[
SizedBox(height: MediaQuery.of(context).size.height * 0.07),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
IconButton(
icon: Icon(
Icons.clear_all,
color: Color(widget.menuColor),
),
onPressed: () {
setState(() {
if (widget.menuColor == 0xFfFCCFA8)
widget.menuColor = 0xffffffff;
else
widget.menuColor = 0xFfFCCFA8;
});
},
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.07,
)
],
),
SizedBox(height: MediaQuery.of(context).size.height * 0.02),
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.width * 0.08, 0, 0, 0),
child: ClipRRect(
borderRadius: BorderRadius.only(topLeft: Radius.circular(55)),
child: Container(
color: Color(0xfffff9c4),
height: MediaQuery.of(context).size.height,
// Here we have to write code for content.
child: Center(
child: Text(
'selectedIndex: $widget.selectedIndex',
),
),
),
),
),
)
],
),
),
);
}
}
Try using Navigation Rails with PageView inside the Expanded widget
class NavRail extends StatefulWidget {
#override
_NavRailState createState() => _NavRailState();
}
class _NavRailState extends State<NavRail> {
int selectedIndex = 0;
PageController pageController = PageController();
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
NavigationRail(
labelType: NavigationRailLabelType.all,
selectedIconTheme: IconThemeData(color: Colors.green),
unselectedIconTheme: IconThemeData(color: Colors.blueGrey),
selectedLabelTextStyle: TextStyle(color: Colors.green),
unselectedLabelTextStyle: TextStyle(color: Colors.blueGrey),
selectedIndex: selectedIndex,
onDestinationSelected: (index) {
setState(() {
selectedIndex = index;
pageController.animateToPage(index,
duration: Duration(milliseconds: 200),
curve: Curves.easeIn);
});
},
destinations: [
NavigationRailDestination(
icon: Icon(Icons.home),
label: Text('Home'),
),
NavigationRailDestination(
icon: Icon(Icons.info),
label: Text('About'),
),
NavigationRailDestination(
icon: Icon(Icons.message),
label: Text('Feedback'),
),
],
),
Expanded(
child: PageView(
controller: pageController,
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
color: Colors.blue,
),
Container(
color: Colors.green,
),
Container(
color: Colors.indigo,
),
],
))
],
),
);
}
}

How to fix "A RenderFlex overflowed by Infinity pixels on the bottom." error on flutter?

I brought some code from the net for the different appbar design and apply it to my code. And I wanted to use bottomnavigationbar and tabbar for my app. But when I tried to apply them together, the part of bottomenavigationbar overflowed by infinity pixels on the bottom. To make scroll on the tabbarview, I attached expanded and singlechildscrollview too, but nothing changed.
I'm a real beginner of Dart and Flutter.
Please give me a hint to fix this problem.
Home.dart
class Home extends StatelessWidget {
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Column(
children: <Widget>[
Container(
height: 160.0,
child: Stack(
children: <Widget>[
Container(
color: Colors.pinkAccent[400],
width: MediaQuery.of(context).size.width,
height: 100.0,
child: Center(
child: Text(
"여행 앱 로고",
style: TextStyle(color: Colors.white, fontSize: 18.0),
),
),
),
Positioned(
top: 80.0,
left: 0.0,
right: 0.0,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(1.0),
border: Border.all(
color: Colors.grey.withOpacity(0.5), width: 1.0),
color: Colors.white),
child: Row(
children: [
IconButton(
icon: Icon(
Icons.menu,
color: Colors.pinkAccent[400],
),
onPressed: () {
print("your menu action here");
_scaffoldKey.currentState.openDrawer();
},
),
Expanded(
child: TextField(
decoration: InputDecoration.collapsed(
hintText: "검색",
),
),
),
IconButton(
icon: Icon(
Icons.search,
color: Colors.pinkAccent[400],
),
onPressed: () {
print("your menu action here");
},
),
],
),
),
),
)
],
),
),
Container(
child: TabBarHome(),
),
],
),
);
}
}
TabBarHome.dart
class TabBarHome extends StatefulWidget {
#override
_TabBarHomeState createState() => _TabBarHomeState();
}
class _TabBarHomeState extends State<TabBarHome> with
SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
#override
void dispose() {
super.dispose();
_tabController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: TabBarView(
controller: _tabController,
children: <Widget>[
Text('회원가입'),
Text('마이페이지'),
Text('공지'),
],
),
),
),
],
),
bottomNavigationBar: Container(
child: TabBar(
controller: _tabController,
labelColor: Colors.black45,
tabs: <Widget>[
Tab(icon: Icon(Icons.person), text: '회원가입'),
Tab(icon: Icon(Icons.assignment_ind), text: '마이페이지'),
Tab(icon: Icon(Icons.list), text: '공지'),
],
),
color: Colors.cyanAccent[100],
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton.extended(
onPressed: () { },
tooltip: '해외 명소',
icon: Icon(Icons.location_on),
label: Text("해외"),
backgroundColor: Colors.orange[600],
elevation: 10.0,
),
);
}
}
I expect to scroll each tabbarview page and make no errors. Thank you.
Here is my solution to your problem. I have also used just one Scaffold rather than using two. Please check this out and let me know if it works for you.
class Home extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomeState();
}
}
class _HomeState extends State<Home> with TickerProviderStateMixin {
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
TabController _tabController;
int _selectedTabIndex;
#override
void initState() {
super.initState();
_selectedTabIndex = 0;
_tabController = TabController(length: 3, vsync: this);
}
#override
void dispose() {
super.dispose();
_tabController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Column(
children: <Widget>[
Container(
height: 160.0,
child: Stack(
children: <Widget>[
Container(
color: Colors.pinkAccent[400],
width: MediaQuery.of(context).size.width,
height: 100.0,
child: Center(
child: Text(
"여행 앱 로고",
style: TextStyle(color: Colors.white, fontSize: 18.0),
),
),
),
Positioned(
top: 80.0,
left: 0.0,
right: 0.0,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(1.0),
border: Border.all(
color: Colors.grey.withOpacity(0.5), width: 1.0),
color: Colors.white),
child: Row(
children: [
IconButton(
icon: Icon(
Icons.menu,
color: Colors.pinkAccent[400],
),
onPressed: () {
print("your menu action here");
_scaffoldKey.currentState.openDrawer();
},
),
Expanded(
child: TextField(
decoration: InputDecoration.collapsed(
hintText: "검색",
),
),
),
IconButton(
icon: Icon(
Icons.search,
color: Colors.pinkAccent[400],
),
onPressed: () {
print("your menu action here");
},
),
],
),
),
),
)
],
),
),
Expanded(
child: TabBarView(
controller: _tabController,
children: <Widget>[
Text('회원가입'),
Text('마이페이지'),
Text('공지'),
],
),
)
/* Container(
child: TabBarHome(),
),*/
],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedTabIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.person), title: Text('회원가입')),
BottomNavigationBarItem(
icon: Icon(Icons.assignment_ind), title: Text('마이페이지')),
BottomNavigationBarItem(icon: Icon(Icons.list), title: Text('공지')),
],
onTap: (int tappedIndex) {
setState(() {
_selectedTabIndex = tappedIndex;
_tabController.index = tappedIndex;
});
},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton.extended(
onPressed: () {},
tooltip: '해외 명소',
icon: Icon(Icons.location_on),
label: Text("해외"),
backgroundColor: Colors.orange[600],
elevation: 10.0,
),
);
}
}