Related
i'm trying to make a Tabbar that appear in a new page when the search icon in pressed. The code works fine but i don't know how to implement this tabbar. I want to use the tabbar for splitting the search info, each icon has to show only specific info.
I guess each icon has a specific list?
This is my search_tool.dart this appear when the icon button at the main page is pressed
[EDIT] Now the result is shown correctly, but when I press the search box to write the error message contained in buildSuggestion always appears, instead it should only show the list with the relative records and if something not belonging to that category is searched then it must give the error message
import 'package:flutter/material.dart';
import 'package:solaris/lista_data.dart';
import 'constants.dart';
class LinkItemsSearch extends SearchDelegate<LinkItem>{
#override
PreferredSizeWidget buildBottom(BuildContext context) {
return PreferredSize(
child: Container(
alignment: Alignment.center,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ElevatedButton(
onPressed: () {
query = 'Apps';
this.showResults(context);
},
child: Text('Apps'),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ElevatedButton(
onPressed: () {
query = 'Movies';
this.showResults(context);
},
child: Text('Movies'),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ElevatedButton(
onPressed: () {
query = 'Games';
this.showResults(context);
},
child: Text('Games'),
),
),
],
),
),
),
preferredSize: Size.fromHeight(60),
);
}
#override
List<Widget> buildActions(BuildContext context) {
return [IconButton(icon: Icon(Icons.clear),onPressed: () { query=""; },)];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(onPressed: () { Navigator.pop(context); }, icon: Icon(Icons.arrow_back),);
}
#override
Widget buildResults(BuildContext context) {
var mylist = loadLinkItem().where((p) => p.description.contains(query)).toList();
return Container(
color: blue,
child: ListView.builder(
itemCount: mylist.length,
itemBuilder: (context,index){
final LinkItem listitem = mylist[index];
return Container(
color: blue,
child: ListTile(
title:InkWell(
onTap: () { Navigator.pushReplacement(context,MaterialPageRoute(builder: (context) => listitem.link)); },
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget> [
Text(listitem.title, style: TextStyle(color: Colors.white),),
Text(listitem.description, style: TextStyle(color: Colors.white,fontSize: 14),),
Divider(color: white,),
],
),
),
),
);
}
),
);
}
#override
Widget buildSuggestions(BuildContext context) {
final mylist = query.isEmpty? loadLinkItem():loadLinkItem().where((p) => p.description.contains(RegExp(query, caseSensitive: false))).toList();
return mylist.isEmpty?
Container(
color: red,
child: Center(child: Text('No Result Found . . .', style: TextStyle(color: Colors.white,fontSize: 20,))),
):Container(
color: blue,
child: ListView.builder(
itemCount: mylist.length,
itemBuilder: (context,index){
final LinkItem listitem = mylist[index];
return Container(
color: blue,
child: ListTile(onTap: (){ showResults(context);},
title:InkWell(
onTap: () { Navigator.pushReplacement(context,MaterialPageRoute(builder: (context) => listitem.link)); },
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget> [
Text(listitem.title, style: TextStyle(color: Colors.white),),
Text(listitem.description, style: TextStyle(color: Colors.white,fontSize: 14),),
Divider(color: white,),
],
),
),
),
);
}
),
);
}
}
Search icon
IconButton(onPressed:(){
showSearch(context: context, delegate: LinkItemsSearch());
}, icon: Icon(Icons.search),),
List
class LinkItem{
final String title;
final String description;
final link;
LinkItem({
required this.title,
required this.description,
required this.link,
});
}
List<LinkItem> loadLinkItem(){
var link = <LinkItem>[
LinkItem(
title: 'Title1',
description: 'Apps',
link: Title1(),
),LinkItem(
title: 'Title2',
description: 'Movies',
link: Title2(),
),LinkItem(
title: 'Title3',
description: 'Games',
link: Title3(),
),
];
return link;
}
You can override the buildBottom method in your LinkItemsSearch:
#override
PreferredSizeWidget buildBottom(BuildContext context) {
return PreferredSize(
child: Container(
alignment: Alignment.center,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ElevatedButton(
onPressed: () {
query = 'Apps';
mylist = loadLinkItem()
.where((p) => p.description.contains(query))
.toList();
this.showResults(context);
},
child: Text('Apps'),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ElevatedButton(
onPressed: () {
query = 'Movies';
mylist = loadLinkItem()
.where((p) => p.description.contains(query))
.toList();
this.showResults(context);
},
child: Text('Movies'),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ElevatedButton(
onPressed: () {
query = 'Games';
mylist = loadLinkItem()
.where((p) => p.description.contains(query))
.toList();
this.showResults(context);
},
child: Text('Games'),
),
),
],
),
),
),
preferredSize: Size.fromHeight(60),
);
}
For this to work, you have to create myList on the top of your LinkItemsSearch and reuse it when filtering everywhere.
Also, I just updated loadLinkItem method to have some input for filtering:
List<LinkItem> loadLinkItem() {
var link = <LinkItem>[
LinkItem(
title: 'Title1',
description: 'Movies',
link: '',
),
LinkItem(
title: 'Title2',
description: 'Games',
link: '',
),
LinkItem(
title: 'Title3',
description: 'Apps',
link: '',
),
];
return link;
}
Of course, I have not completely matched your style, so I did not style buttons as you need it, you might higher bottom bar than 60 as I used. I also have not attached any on press handlers since I am not sure what should they do, but it looks as it is expected: https://i.stack.imgur.com/osUkt.png
I wrapped them with a Column and SingleChildScrollView in case you have more of those items and they need to be scrollable: https://i.stack.imgur.com/FyWVX.png
You can even add some conditions in cases when you don't need this bottom bar to be displayed and in that case, you can just return null from the buildBottom method.
FIX
import 'package:flutter/material.dart';
import 'package:solaris/lista_data.dart';
import 'constants.dart';
class LinkItemsSearch extends SearchDelegate<LinkItem>{
#override
PreferredSizeWidget buildBottom(BuildContext context) {
return PreferredSize(
child: Container(
alignment: Alignment.center,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ElevatedButton(
onPressed: () {
query = 'Apps';
this.showResults(context);
},
child: Text('Apps'),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ElevatedButton(
onPressed: () {
query = 'Movies';
this.showResults(context);
},
child: Text('Movies'),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: ElevatedButton(
onPressed: () {
query = 'Games';
this.showResults(context);
},
child: Text('Games'),
),
),
],
),
),
),
preferredSize: Size.fromHeight(60),
);
}
#override
List<Widget> buildActions(BuildContext context) {
return [IconButton(icon: Icon(Icons.clear),onPressed: () { query=""; },)];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(onPressed: () { Navigator.pop(context); }, icon: Icon(Icons.arrow_back),);
}
#override
Widget buildResults(BuildContext context) {
var mylist = loadLinkItem().where((p) => p.description.contains(query)).toList();
return Container(
color: blue,
child: ListView.builder(
itemCount: mylist.length,
itemBuilder: (context,index){
final LinkItem listitem = mylist[index];
return Container(
color: blue,
child: ListTile(
title:InkWell(
onTap: () { Navigator.pushReplacement(context,MaterialPageRoute(builder: (context) => listitem.link)); },
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget> [
Text(listitem.title, style: TextStyle(color: Colors.white),),
Text(listitem.description, style: TextStyle(color: Colors.white,fontSize: 14),),
Divider(color: white,),
],
),
),
),
);
}
),
);
}
#override
Widget buildSuggestions(BuildContext context) {
final mylist = query.isEmpty? loadLinkItem():loadLinkItem().where((p) => p.description.contains(RegExp(query, caseSensitive: false))).toList();
return mylist.isEmpty?
Container(
color: red,
child: Center(child: Text('No Result Found . . .', style: TextStyle(color: Colors.white,fontSize: 20,))),
):Container(
color: blue,
child: ListView.builder(
itemCount: mylist.length,
itemBuilder: (context,index){
final LinkItem listitem = mylist[index];
return Container(
color: blue,
child: ListTile(onTap: (){ showResults(context);},
title:InkWell(
onTap: () { Navigator.pushReplacement(context,MaterialPageRoute(builder: (context) => listitem.link)); },
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget> [
Text(listitem.title, style: TextStyle(color: Colors.white),),
Text(listitem.description, style: TextStyle(color: Colors.white,fontSize: 14),),
Divider(color: white,),
],
),
),
),
);
}
),
);
}
}
everyone
I'm encountering a problem while using Flutter.
Basically when i open my CustomDrawer widget, not always but quite frequently, the keyboard pops out in an unwanted way.
I don't get why it does it... maybe because it re-runs the build method or something i don't know. Down below you can find the code.
Every little bit of information is well appreciated.
Thanks everyone.
Here's the Screen.dart
...
build(context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.white),
backgroundColor: Colors.transparent,
elevation: 0,
),
drawer: CustomDrawer(),
...
And the custom_drawer_widget.dart
...
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: [
Stack(
children: [
Container(
padding: EdgeInsets.all(20),
child: Text(
"Hi, $username",
style: TextStyle(
fontSize: 22,
),
),
alignment: Alignment.bottomLeft,
color: Colors.yellow,
height: 300,
),
],
),
Container(
height: 60.0 * 6,
child: Column(
children: [
Container(
height: 60,
child: FlatButton(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 10),
highlightColor: Colors.grey[350],
color: Colors.transparent,
onPressed: () {},
child: Row(
children: [
Icon(
Icons.home,
color: Colors.grey[600],
),
SizedBox(width: 30),
Text("Homepage"),
],
),
),
),
ListTile(
leading: Icon(Icons.book),
title: Text("Diary"),
onTap: () {}),
ListTile(
leading: Icon(Icons.chat),
title: Text("Chat"),
onTap: () {}),
ListTile(
leading: Icon(Icons.credit_card),
title: Text("Credit Card"),
onTap: () {}),
ListTile(
leading: Icon(Icons.exit_to_app),
title: Text("Sign Out"),
onTap: () async {
await FirebaseAuth.instance.signOut();
}),
ListTile(
leading: Icon(Icons.settings),
title: Text("Settings"),
onTap: () {}),
],
),
),
Expanded(
child: Container(
padding: EdgeInsets.all(22),
alignment: Alignment.bottomLeft,
child: Row(
children: [
Text("Version 0.1"),
],
),
),
)
],
),
);
}
...
I don't see exactly where you dismiss the keyboard, but I was having the same issue after dismissing the keyboard after a form submit. This fixed my issue.
See this answer here:
https://github.com/flutter/flutter/issues/54277
Where instead of:
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
},
The code should be:
onTap: () {
final FocusScopeNode currentScope = FocusScope.of(context);
if (!currentScope.hasPrimaryFocus && currentScope.hasFocus) {
FocusManager.instance.primaryFocus.unfocus();
}
},
How can I change the toolbar color for the Navigation drawer.
Just add padding: EdgeInsets.all(0.0), in your listview widget inside Drawer widget
Try this
class HomePage extends StatefulWidget {
#override
_HomePageScreen createState() => _HomePageScreen();
}
class _HomePageScreen extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.all(0.0),
children: <Widget>[
UserAccountsDrawerHeader(
accountName: Text("Nilesh Rathod"),
accountEmail: Text("nilesh#gmail.com"),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,
child: Text("Nilu"),
),
),
ListTile(
title: Text("Home"),
trailing: Icon(Icons.new_releases),
),
Divider(),
ListTile(
title: Text("Profile"),
trailing: Icon(Icons.person),
onTap: () => {},
),
Divider(),
ListTile(
title: Text("Tab Layout"),
trailing: Icon(Icons.person),
onTap: () => {},
),
Divider(),
ListTile(
title: Text("Comman View Demo"),
trailing: Icon(Icons.person),
onTap: () => {},
),
Divider(),
ListTile(
title: Text("Close"),
trailing: Icon(Icons.close),
onTap: () => Navigator.of(context).pop(),
),
],
),
),
body: CachedNetworkImage(
imageUrl: 'https://i.stack.imgur.com/K8FFo.jpg?s=328&g=1',
placeholder: (context, url) => CircularProgressIndicator(), //<= ends here
errorWidget: (context, url, error) => Icon(Icons.error)),
);
}
}
OUTPUT
With padding: EdgeInsets.all(0.0),
Without padding: EdgeInsets.all(0.0),
I have navigation drawer, i select one item from it and after i select second item when i pressed back after selecting second item app got closed i need to go on first item when i pressed back .
#override
Widget build(BuildContext context) {
List<Widget> drawerOptions = [];
for (var i = 0; i < drawerItems.length; i++) {
var d = drawerItems[i];
drawerOptions.add(new ListTile(
leading: new Icon(d.icon),
title: new Text(
d.title,
style: new TextStyle(fontSize: 14.0, fontWeight: FontWeight.w400),
),
selected: i == _selectedIndex,
onTap: () => _onSelectItem(i),
));
}
return new Scaffold(
appBar: SearchBar(
loader: QuerySetLoader<ProductModel>(
querySetCall: _getItemListForQuery,
itemBuilder: _buildItemWidget,
loadOnEachChange: true,
animateChanges: true,
),
defaultBar: AppBar(
title: Text('Home'),
),
),
drawer: new Drawer(
child: SingleChildScrollView(
child: new Column(
children: <Widget>[
DecoratedBox(
position: DecorationPosition.background,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/bac_image.png'),
fit: BoxFit.cover),
),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(20.0),
child: new Image(
image: new AssetImage("assets/blik_mobile.png"),
height: 100,
width: 100,
),
),
Column(children: drawerOptions)
],
),
)
],
),
),
),
body: _getDrawerItemScreen(_selectedIndex),
bottomNavigationBar: BottomNavigationBar(
onTap: (int index) {
setState(() {
this.index = index;
// Navigator.of(context).pop();
});
_navigateToScreens(index);
},
type: BottomNavigationBarType.fixed,
currentIndex: index,
items: [
BottomNavigationBarItem(
title: Text('Home'),
icon: Icon(
Icons.home,
color: Colors.black,
)),
BottomNavigationBarItem(
title: Text('Categories'),
icon: Icon(Icons.dashboard, color: Colors.black)),
BottomNavigationBarItem(
title: Text('Cart'),
icon: Icon(Icons.shopping_cart, color: Colors.black)),
BottomNavigationBarItem(
title: Text('WishList'),
icon: Icon(Icons.favorite, color: Colors.black)),
BottomNavigationBarItem(
title: Text('Profile'),
icon: Icon(Icons.person, color: Colors.black)),
],
),
);
}
on select item of drawer
_onSelectItem(int index) {
setState(() {
_selectedIndex = index;
_getDrawerItemScreen(_selectedIndex);
});
Navigator.of(context).pop();
}
get selected drawer screen method is here
_getDrawerItemScreen(int pos) {
switch (pos) {
case 0:
return new FirstScreen(drawerItem: drawerItems[_selectedIndex]);
case 1:
return new OrderHistory(drawerItem: drawerItems[_selectedIndex]);
case 2:
return new WalletScreen(
drawerItem: drawerItems[_selectedIndex],
);
case 3:
return new AddressList(drawerItem: drawerItems[_selectedIndex]);
case 5:
return new AboutUs(drawerItem: drawerItems[_selectedIndex]);
// return new AddAddress(drawerItem: drawerItems[_selectedIndex],);
default:
return new FirstScreen(drawerItem: drawerItems[_selectedIndex]);
}
}
i want to handle back after selecting any of item from my navigation drawer .
If you need to control screen stack, you can use
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
}
detail reference https://medium.com/flutter-community/flutter-push-pop-push-1bb718b13c31
If you want to handle back button
you can wrap your Scaffold with WillPopScope
return WillPopScope(
onWillPop: () => _exitApp(context),
child: Scaffold(
appBar: AppBar(
title: Text("Navigation Demo"),
and ask user Do you want to exit this application or current screen
Future<bool> _exitApp(BuildContext context) {
return showDialog(
context: context,
child: AlertDialog(
title: Text('Do you want to exit this application?'),
content: Text('We hate to see you leave...'),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text('No'),
),
FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text('Yes'),
),
],
),
) ??
false;
}
detail reference https://codingwithjoe.com/flutter-navigation-how-to-prevent-navigation/
This is a snippet of my widgets.dart file where I defined a widget called see_all_cards and its only purpose is to show an extended list of all cards that I was initially displaying. It should just redirect to Trending.dart. That's my main goal here.
Widget see_all_cards(){
return Container(
child: FlatButton(
child: Text(
"See all (43)",
style: TextStyle(
color: Theme.of(context).accentColor, // error
),
),
onPressed: (){
Navigator.push(
context, // error
MaterialPageRoute(
builder: (BuildContext context){
return trending();
},
),
);
},
)
);
}
The following segment is my main page. I've called SlowlyApp from void main.
class SlowlyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SlowlyApp',
home: Scaffold(
appBar: AppBar(
title: Text('Search',
style: TextStyle(
color: Color.fromRGBO(0,0,0,1),
),
),
backgroundColor: Color.fromRGBO(225,225,0,1),
actions: <Widget>[
IconButton(
icon:
Icon(Icons.search),
onPressed: (){
showSearch(context: context, delegate: data_search());
}
),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
smallgap(),
current_cards_heading(),
current_cards(),
see_all_cards(),
smallgap(),
],
),
),
);
}
}
see_all_cards should expect context as parameter. You only have context in your main widget's build method
Widget see_all_cards(BuildContext context){
return Container(
child: FlatButton(
child: Text(
"See all (43)",
style: TextStyle(
color: Theme.of(context).accentColor, // error
),
),
onPressed: (){
Navigator.push(
context, // error
MaterialPageRoute(
builder: (BuildContext context){
return trending();
},
),
);
},
)
);
}
And then you can call passing the context.
class SlowlyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SlowlyApp',
home: Scaffold(
appBar: AppBar(
title: Text('Search',
style: TextStyle(
color: Color.fromRGBO(0,0,0,1),
),
),
backgroundColor: Color.fromRGBO(225,225,0,1),
actions: <Widget>[
IconButton(
icon:
Icon(Icons.search),
onPressed: (){
showSearch(context: context, delegate: data_search());
}
),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
smallgap(),
current_cards_heading(),
current_cards(),
see_all_cards(context),
smallgap(),
],
),
),
);
}
}
I also get this error to solve this way
it's the main file container called my widgets _buildFoodItem define context with parameters
Container(
height: MediaQuery.of(context).size.height - 185.0,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(75.0),
),
),
child: ListView(
primary: true,
padding: const EdgeInsets.only(left: 25.0, right: 20.0),
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 45.0),
child: Container(
height: MediaQuery.of(context).size.height - 300.0,
child: ListView(children: [
_buildFoodItem(context, 'assets/images/plate1.png',
'Slazmon bowl', '₹ 150:00'),
_buildFoodItem(context, 'assets/images/plate2.png',
'Spring bowl', '₹ 120:00'),
_buildFoodItem(context, 'assets/images/plate3.png',
'Chikz bowl', '₹ 100:00'),
_buildFoodItem(context, 'assets/images/plate4.png',
'Berry Bowl', '₹ 199:00'),
_buildFoodItem(context, 'assets/images/plate5.png',
'Greezy bowl', '₹ 170:00'),
]),
),
)
],
),
),
this is my widget _buildFoodItem check the context
Widget _buildFoodItem(
BuildContext context, String imgPath, String foodName, String price) {
return Padding(padding: const EdgeInsets.only(
top: 10.0, left: 10.0, right: 10.0),
child: InkWell(
onTap: () {
Navigator.push(
context,
(MaterialPageRoute(
builder: (context) => FoodDetailsPage(
heroTag: imgPath,
foodName: foodName,
foodPrice: price,
),
)));
},
))
}
)