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,),
],
),
),
),
);
}
),
);
}
}
Related
I have a custom Card widget with ExpansionTile as a child which displays multiple Dropdownbuttons according to data fetched from an API.
But when I use ListView.builder to build N amount of said custom widgets they all behave simultaneously, for example when I collapse the ExpansionTile all open ExpansionTiles collapse simultaneously and reset the data inside Dropdownbuttons (resetting the data expected outcome when ExpansionTile collapsed but only the collapsed ExpansionTile should reset its children Dropdownbuttons, not all open ExpansionTiles children).
Here is my builder.
var items = ["Apartment 1", "Apartment 2", "Apartment 3", "Apartment 4"];
class MapPage extends StatelessWidget {
const MapPage({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
key: ValueKey(items),
scrollDirection: Axis.vertical,
itemCount: items.length,
padding: const EdgeInsets.only(top: 8),
itemBuilder: (context, index) {
return MapCard(
building: items[index],
floor: 4,
key: Key(items[index].toString()),
);
}),
);
}
}
and my CustomCard
class MapCard extends StatefulWidget {
final String building;
final int floor;
const MapCard({super.key, required this.building, required this.floor});
#override
State<MapCard> createState() => _MapCardState();
}
class _MapCardState extends State<MapCard> {
#override
Widget build(BuildContext context) {
PageStorageKey key = PageStorageKey('${widget.key}');
return Center(
child: Consumer<MapCardViewModel>(
builder: (context, mapCardViewModel, child) => Card(
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.9,
child: Padding(
padding: const EdgeInsets.only(bottom: 12),
child: ExpansionTile(
key: key,
onExpansionChanged: (changed) {
if (!changed) {
mapCardViewModel.setAreaVisibility(false);
mapCardViewModel.setButtonVisibility(false);
mapCardViewModel.setIsFloorChosen(false);
mapCardViewModel.setAreaVisibility(false);
mapCardViewModel.area = mapCardViewModel.areas[0];
mapCardViewModel.floorNumber = mapCardViewModel.floors[0];
}
},
title: Row(
children: [
Container(
padding:
const EdgeInsets.only(top: 8, bottom: 8, right: 8),
child: Image.asset(
"assets/images/example.png",
height: 80,
width: 80,
)),
Flexible(
child: Container(
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
child: Column(
children: [
Text("${widget.building} Apartment \n"
"Floor Count ${widget.floor} ")
],
),
),
)
],
),
children: [
const Text("Choose Floor"),
Padding(
padding: const EdgeInsets.only(right: 24, left: 24),
child: DropdownButton(
isExpanded: true,
value: mapCardViewModel.isFloorChosen == false
? mapCardViewModel.floors[0]
: mapCardViewModel.floorNumber,
items: mapCardViewModel.floors
.map<DropdownMenuItem<int>>((int i) {
return DropdownMenuItem<int>(
value: i,
child: Text(i.toString()),
);
}).toList(),
onChanged: (int? value) {
mapCardViewModel.setFloorNumber(value!);
mapCardViewModel.setIsFloorChosen(true);
mapCardViewModel.setAreaVisibility(true);
}),
),
Visibility(
visible: mapCardViewModel.isAreaVisible,
child: Column(
children: [
const Text("Choose an Area to map"),
Padding(
padding: const EdgeInsets.only(right: 24, left: 24),
child: DropdownButton(
isExpanded: true,
value: mapCardViewModel.isAreaChosen == false
? mapCardViewModel.areas[0]
: mapCardViewModel.area,
items: mapCardViewModel.areas
.map<DropdownMenuItem<String>>(
(String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? value) {
mapCardViewModel.setArea(value!);
mapCardViewModel.setIsAreaChosen(true);
mapCardViewModel.setButtonVisibility(true);
}),
),
],
),
),
Visibility(
visible: mapCardViewModel.isButtonsVisible,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return CustomDialog(
title: "Mapping Status",
content:
"This area hasn't been mapped yet",
page: Container(),
buttonColor: MainColors().mainBlue);
});
},
child: const Text("Show Area Map")),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const MappedPage(),
),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: MainColors().mainBlue),
child: const Text(
"Map The Area",
style: TextStyle(color: Colors.white),
))
],
),
)
],
),
)),
),
));
}
}
I tried to assign keys to each ExpansionTile and custom MapCard widgets with StatefulWidget but I couldn't solve my problem.
I remove all 3rd dependency and try to adjust your solution of MapCard widget.
var items = ["Apartment 1", "Apartment 2", "Apartment 3", "Apartment 4"];
final floors = ['Floor 1', 'Floor 2'];
final areas = ['Area 1', 'Area 2'];
class MapCard extends StatefulWidget {
final String building;
final int floor;
const MapCard({Key? key, required this.building, required this.floor}): super(key: key);
#override
State<MapCard> createState() => _MapCardState();
}
class _MapCardState extends State<MapCard> {
#override
Widget build(BuildContext context) {
PageStorageKey key = PageStorageKey('${widget.key}');
return Center(
child: Card(
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.9,
child: Padding(
padding: const EdgeInsets.only(bottom: 12),
child: ExpansionTile(
key: key,
onExpansionChanged: (changed) {
if (!changed) {
print('!changed');
}
},
title: Row(
children: [
Container(
padding:
const EdgeInsets.only(top: 8, bottom: 8, right: 8),
child: Placeholder(
fallbackHeight: 80,
fallbackWidth: 80,
)),
Flexible(
child: Container(
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
child: Column(
children: [
Text("${widget.building} Apartment \n"
"Floor Count ${widget.floor} ")
],
),
),
)
],
),
children: [
const Text("Choose Floor"),
Padding(
padding: const EdgeInsets.only(right: 24, left: 24),
child: DropdownButton(
isExpanded: true,
value: floors.first,
items: floors
.map<DropdownMenuItem<String>>((String i) {
return DropdownMenuItem<String>(
value: i,
child: Text(i.toString()),
);
}).toList(),
onChanged: (String? value) {
// code here
}),
),
Visibility(
visible: true,
child: Column(
children: [
const Text("Choose an Area to map"),
Padding(
padding: const EdgeInsets.only(right: 24, left: 24),
child: DropdownButton(
isExpanded: true,
value: areas.first,
items: areas
.map<DropdownMenuItem<String>>(
(String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? value) {
// code here
}),
),
],
),
),
Visibility(
visible: true,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(content: Text('Alert dialog'),);
});
},
child: const Text("Show Area Map")),
ElevatedButton(
onPressed: () {
print('navigate');
},
child: const Text(
"Map The Area",
style: TextStyle(color: Colors.white),
))
],
),
)
],
),
)),
),
);
}
}
But I suppose your problem in the line
Consumer<MapCardViewModel>
because every time when you change it this will apply to each created card. So you have to put it above your ListView.builder and pass it as a parameter to your cards
https://github.com/flutter-devs/flutter_folding_cell_demo/blob/master/lib/demo_screen.dart
I'm trying to follow the code in the link above.
But in the SimpleFoldingCell part, an error named 'The class 'SimpleFoldingCell' doesn't have a default constructor.' occurs.
Could
Is there a way to resolve this error in Dart?
class Notific extends StatefulWidget{
#override
_State createState() => _State();
}
class _State extends State<Notific>{
late List<TechnologyModel> _technologyList;
#override
void initState() {
super.initState();
_technologyList = [
TechnologyModel(title: "Application Development",),
TechnologyModel(title: "Research & Development",),
TechnologyModel(title: "Big Data & Analytics",),
TechnologyModel(title: "Support Services",),
TechnologyModel(title: "QA & Software Testing",),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.pink[200],
title: Text("Folding Cell Demo",
style: TextStyle(color: Colors.white),),
),
body: Container(
child: ListView.builder(
itemCount: _technologyList.length,
itemBuilder: (context, index) {
return SimpleFoldingCell(
frontWidget: _buildFrontWidget(index),
innerTopWidget: _buildInnerWidget(index),
innerBottomWidget: _buildInnerBottomWidget(),
cellSize: Size(MediaQuery.of(context).size.width, 125),
padding: EdgeInsets.all(15),
animationDuration: Duration(milliseconds: 200),
borderRadius: 10,
onOpen: () => print('$index cell opened'),
onClose: () => print('$index cell closed'),
);
},
),
),
);
}
Widget _buildFrontWidget(int index) {
return Builder(
builder: (BuildContext context) {
return Container(
color: Colors.cyan[100],
alignment: Alignment.bottomCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Aeologic Technology",
style: TextStyle(
fontSize:20.0,
color: Colors.black,
),
),
SizedBox(height: 10,),
FlatButton(
onPressed: () {
final foldingCellState = context
.findAncestorStateOfType<SimpleFoldingCellState>();
foldingCellState?.toggleFold();
},
child: Text(
"OPEN",
),
textColor: Colors.white,
color: Colors.indigoAccent[100],
splashColor: Colors.white.withOpacity(0.5),
),
],
),
);
},
);
}
Widget _buildInnerBottomWidget() {
return Builder(
builder: (context) {
return Container(
color: Colors.blueGrey[50],
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(bottom: 10),
child: FlatButton(
onPressed: () {
final foldingCellState = context
.findAncestorStateOfType<SimpleFoldingCellState>();
foldingCellState?.toggleFold();
},
child: Text(
"Close",
),
textColor: Colors.white,
color: Colors.redAccent[100],
splashColor: Colors.white.withOpacity(0.5),
),
),
);
}
);
}
Widget _buildInnerWidget(int index) {
return Builder(
builder: (context) {
return Container(
color: Colors.pink[100],
padding: EdgeInsets.only(top: 10),
child: Align(
alignment: Alignment.center,
child: Text(
_technologyList[index].title,
style: TextStyle(
fontSize:20.0,
color: Colors.black,
),
),
),
);
},
);
}
}
class TechnologyModel {
String title;
TechnologyModel({
required this.title,
});
}
For some reason they've created only a named constructor.
return SimpleFoldingCell.create(
frontWidget: _buildFrontWidget(index),
innerWidget: _buildInnerWidget(index),
// innerTopWidget: _buildInnerWidget(index),
// innerBottomWidget: _buildInnerBottomWidget(),
cellSize: Size(MediaQuery.of(context).size.width, 125),
padding: EdgeInsets.all(15),
animationDuration: Duration(milliseconds: 200),
borderRadius: 10,
onOpen: () => print('$index cell opened'),
onClose: () => print('$index cell closed'),
);
It looks like the demo you're looking at is a bit outdated, since some of those properties don't exist anymore (see commented code).
I am having a stuck on transferring the value from the second page to the third page using the value pass from the first page. when I am trying to use the usual way that I am used to calling the data in the stateful widget, it returns an error on undefined.
class restaurantLISTVIEW extends StatefulWidget {
restaurantLISTVIEW({this.category});
final String category;
#override
_restaurantLISTVIEWState createState() => _restaurantLISTVIEWState();
}
within extends state:(working)
FloatingActionButton(
onPressed: (){
return showDialog(
context: context,
builder: (context){
return AlertDialog(
content: Text(
'${widget.category}'
),
);
},
);
},),
error on extends stateless widget, return null: (not working)
onTap: ()
{
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context)=> new SarapanPagi(list: list, index: i, category: category)));
}
within extends stateless:(not working)
FloatingActionButton(
onPressed: (){
return showDialog(
context: context,
builder: (context){
return AlertDialog(
content: Text(
'$category hellp'
),
);
},
);
},),
The whole code on the second page:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as HTTP;
import 'breakfast.dart';
// ignore: camel_case_types
class restaurantLISTVIEW extends StatefulWidget {
restaurantLISTVIEW({this.category});
final String category;
#override
_restaurantLISTVIEWState createState() => _restaurantLISTVIEWState();
}
// ignore: camel_case_types
class _restaurantLISTVIEWState extends State<restaurantLISTVIEW> {
Future<List> getData() async{
var url = 'http://10.0.2.2/foodsystem/restaurantlist.php';
var data = {'product_type': 'xde pape ppon saje nk hantar value'};
var response = await http.post(url, body: json.encode(data));
//final response= await http.get("http://10.0.2.2/foodsystem/getdata.php");
return json.decode(response.body);}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.black),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
//Text("Restaurant's Owner Page"),
Text('${widget.category}', textAlign: TextAlign.center, style: TextStyle(fontSize: 25, fontWeight: FontWeight.w700), ),
],
),
centerTitle: false,
//automaticallyImplyLeading: false,
),
body:
Padding(
padding: const EdgeInsets.only(bottom: 20, left: 5, right: 5),
child: Column(
children: [
SizedBox(height: 30,),
Container(
//decoration: BoxDecoration(border: Border.all(color: Colors.black, width: 4), borderRadius: BorderRadius.circular(15)),
height: 600,
child: FutureBuilder<List>(
future: getData(),
builder: (context, snapshot){
if(snapshot.hasError) print(snapshot.error);
return snapshot.hasData ?
ItemList(list: snapshot.data,) :
Center(child: CircularProgressIndicator(),);
},
),
),
FloatingActionButton(
onPressed: (){
return showDialog(
context: context,
builder: (context){
return AlertDialog(
content: Text(
'${widget.category}'
),
);
},
);
},
),
SizedBox(height: 10,),
],
),
),
);
}
}
class ItemList extends StatelessWidget {
final List list;
final String category;
ItemList({this.list, this.category});
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
//color: Colors.red.shade100,
height: 600,
child: ListView.builder(
itemCount: list==null ? 0 : list.length,
itemBuilder: (context, i){
return new Container(
height: 200,
child: new GestureDetector(
onTap: ()
{
if(widget.category == "Breakfast"){
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context)=> new SarapanPagi(list: list, index: i, category: category)));
}
},
child: new Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
constraints: BoxConstraints(minWidth: 180, maxWidth: 180),
child:
Column(
children: [
Text(list[i]["restaurant_name"], style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), textAlign: TextAlign.center,),
Text("Restaurant ID: ${list[i]["restaurant_id"]}", style: TextStyle(fontSize: 20,), textAlign: TextAlign.center,),
],
),
),
Padding(
padding: const EdgeInsets.only(left :20.0),
child: Container(
constraints: BoxConstraints(minWidth: 150, maxWidth: 300),
child:
SizedBox(
width: 50,
child: Column(
children: [
Text("SSM: ${list[i]["restaurant_ssm"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 15),),
Text("Phone: ${list[i]["restaurant_phone"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 15),),
Text("Address: ${list[i]["restaurant_address"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 15),),
],
),
),
),
),
],
),
Row(
children: [
],
),
],
),
),
),
);
},
),
),
);
The whole code on the third page:
import 'dart:convert';
import 'package:http/http.dart' as HTTP;
import 'package:flutter/material.dart';
//import 'globals.dart' as globals;
class SarapanPagi extends StatefulWidget {
final List list;
final int index;
final String category;
SarapanPagi({this.index,this.list,this.category});
#override
_SarapanPagiState createState() => _SarapanPagiState();
}
class _SarapanPagiState extends State<SarapanPagi> {
Future<List> getData() async{
var url = 'http://10.0.2.2/foodsystem/breakfastlist.php';
var data = {
'product_type': 'Breakfast',
'product_owner': widget.list[widget.index]['restaurant_id'],
};
var response = await http.post(url, body: json.encode(data));
//final response= await http.get("http://10.0.2.2/foodsystem/getdata.php");
return json.decode(response.body);}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.black),
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
//Text("Restaurant's Owner Page"),
Text(widget.list[widget.index]['restaurant_name'], textAlign: TextAlign.center, style: TextStyle(fontWeight: FontWeight.w700), ),
],
),
centerTitle: false,
//automaticallyImplyLeading: false,
),
body:
Padding(
padding: const EdgeInsets.only(bottom: 20, left: 5, right: 5),
child: Column(
children: [
SizedBox(height: 30,),
Container(
//decoration: BoxDecoration(border: Border.all(color: Colors.black, width: 4), borderRadius: BorderRadius.circular(15)),
height: 600,
child: FutureBuilder<List>(
future: getData(),
builder: (context, snapshot){
if(snapshot.hasError) print(snapshot.error);
return snapshot.hasData ?
ItemList(list: snapshot.data,) :
Center(child: CircularProgressIndicator(),);
},
),
),
SizedBox(height: 10,),
],
),
),
);
}
}
class ItemList extends StatelessWidget {
final List list;
ItemList({this.list});
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
//color: Colors.red.shade100,
height: 600,
child: ListView.builder(
itemCount: list==null ? 0 : list.length,
itemBuilder: (context, i){
return new Container(
height: 200,
child: new GestureDetector(
onTap: (){},
child: new Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
"images/${list[i]['image']}",
width: 150,
height: 150,
),
),
Padding(
padding: const EdgeInsets.only(left: 20.0, bottom: 0),
child:
Column(
children: [
Text(list[i]["product_name"], textAlign: TextAlign.center, style: TextStyle(fontSize: 30),),
Text("Price RM : ${list[i]["product_price"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 25),),
RaisedButton(
shape: RoundedRectangleBorder(borderRadius: new BorderRadius.circular(40.0)),
color: Colors.red.shade300,
child: Text("Add to Cart", style: TextStyle(fontWeight: FontWeight.bold),),
onPressed: (){},
)
],
),
),
],
),
/*ListTile(
title: Text(list[i]["product_name"], textAlign: TextAlign.center, style: TextStyle(fontSize: 30),),
leading:
Image.asset(
"images/${list[i]['image']}",
width: 100,
height: 100,
),
subtitle: Text("Price RM : ${list[i]["product_price"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 25),),
),*/
],
),
),
),
);
},
),
),
);
The
You are not using widget.category in restaurantLISTVIEW page but in ItemList widget, that's why you are getting that error.
Adjust your ItemList widget like this
class ItemList extends StatelessWidget {
final List list;
final String category;
ItemList({this.list, this.category});
}
So, your navigation line in ItemList must be
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context)=> new SarapanPagi(list: list, index: i, category: category)));
Also, in SarapanPagi page the variable type of category is not int by String
You are not using widget.category in restaurantLISTVIEW page but in ItemList widget,
The solution that I made is:
this code on the stateful widget class for the second page, needs to be improved by adding the value of the category.
ItemList(list: snapshot.data,)
improved code:
this code forwards the value store in the widget category to the second page from the stateful widget into stateless widget.
ItemList(list: snapshot.data,category: widget.category) :
I'm making an app. I'm getting data from the URL and try to show. But I need to hot reload to see.
These are my codes:
import 'package:flutter/material.dart';
import 'widgets/half_category_widget.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
var searchCat;
var baslik="Ana Sayfa";
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.light(),
home: FirstApp(),
));
createCategory();
createProduct();
}
void runCat(id){
searchCat=id+1;
searchProds();
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.light(),
home: CatProds(),
));
}
class FirstApp extends StatefulWidget {
#override
_FirstAppState createState() => _FirstAppState();
}
List<Widget> menu = new List<Widget>();
Future createCategory() async{
var url = 'https://recepabi.com/pc/getCatKafe';
http.Response response = await http.get(url);
var data = (response.body).toString().split('-');
for(var i=0;i<data.length-1;i++){
menu.add(Expanded(
child: Padding(
padding: const EdgeInsets.all(4.0),
child:
InkWell(onTap: () {
print("ID:" + i.toString());
runCat(i);
baslik=data[i];
},
child: Container(
height: 100.0,
width: 100.0,
child: Column(
children: <Widget>[
HalfCategory(Colors.blue, Icons.menu, data[i]),
],
),
),
) ,
),
));
}
}
List<Widget> products = new List<Widget>();
List<Widget> products1 = new List<Widget>();
Future createProduct() async{
var url = 'https://recepabi.com/pc/getProdKafe';
http.Response response = await http.get(url);
var data = (response.body).toString().split('ğ');
for(var i=0;i<data.length-1;i++){
var prod=data[i].split("ı");
var ad=prod[0];
var birim=prod[1];
var kategori=prod[2];
var fiyat=prod[3];
var resim=prod[4];
var myr=Row(children: <Widget>[Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5.0 ),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Image.network(
resim,
fit: BoxFit.cover,
repeat: ImageRepeat.noRepeat,
height: 200.0,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0,bottom: 16.0),
child: Text(
ad.toUpperCase(),
maxLines: 1,
style: TextStyle(fontSize: 25.0),
textAlign: TextAlign.center,
),
)
],
),
),
),],);
products1.add(myr);
}
}
class _FirstAppState extends State<FirstApp> {
int _index = 0;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Kafeex"),
centerTitle: true,
backgroundColor: Colors.red,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _index,
onTap: (int index) {
setState(() {
_index = index;
if(_index==0)
{
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => FirstApp()),
(Route<dynamic> route) => false,
);
}
else if(_index==1)
{
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
(Route<dynamic> route) => false,
);
}
});
},
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.fastfood),
title: new Text('Sipariş'),
),
BottomNavigationBarItem(
icon: new Icon(Icons.shopping_cart),
title: new Text('Sepet'),
),
],
),
body: Padding(
padding: const EdgeInsets.all(2.0),
child: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
Row(
children:menu
),
SizedBox(
height: 8.0,
),
Padding(
padding: const EdgeInsets.all(6.0),
child: Row(
children: <Widget>[Expanded(
child: Text(baslik,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.start,
),
),],
),
),
SizedBox(
height: 10.0,
),
Column(
children: products1
),
],
),
)
);
}
}
class SecondRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
class CatProds extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Kafeex"),
centerTitle: true,
backgroundColor: Colors.red,
),
body: Padding(
padding: const EdgeInsets.all(2.0),
child: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
Row(
children:menu
),
SizedBox(
height: 8.0,
),
Padding(
padding: const EdgeInsets.all(6.0),
child: Row(
children: <Widget>[Expanded(
child: Text(baslik,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.start,
),
),],
),
),
SizedBox(
height: 10.0,
),
Column(
children: searchProd
),
],
),
)
);
}
}
List<Widget> searchProd = new List<Widget>();
Future searchProds() async{
var url = 'https://recepabi.com/pc/searchProdKafe/'+searchCat.toString();
print(url);
http.Response response = await http.get(url);
var data = (response.body).toString().split('ğ');
for(var i=0;i<data.length-1;i++){
var prod=data[i].split("ı");
var ad=prod[0];
var birim=prod[1];
var kategori=prod[2];
var fiyat=prod[3];
var resim=prod[4];
var myr2=Row(children: <Widget>[Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5.0 ),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Image.network(
resim,
fit: BoxFit.cover,
repeat: ImageRepeat.noRepeat,
height: 200.0,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0,bottom: 16.0),
child: Text(
ad.toUpperCase(),
maxLines: 1,
style: TextStyle(fontSize: 25.0),
textAlign: TextAlign.center,
),
)
],
),
),
),],);
searchProd.add(myr2);
searchCat=0;
}
}
For example: I get the data from URL(createCategory()). I put the data to list(menu) and try to show on the widget(_FirstAppState's widget). But first, run nothing appears. On the second run(by hot reloading) it appears.
How do I prevent this?
The problem here is u r calling createCategory(); & createProduct(); functions in main() function if u change some code in those methods u need to call main() method again which is not possible in hot reload which only changes state & some widget
so for calling main() method again u need to perform hot restart
Hi so I'm trying to show alertDialog when you press the close icon on the card but if I tap the "Close" button, it didn't show the alertDialog for delete confirmation, on the other hand when I tap the "check" Icon on, it successfully show a snackbar.
here's my code for the page:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'Schedule.dart';
class HomeView extends StatefulWidget {
HomeViewState createState() => HomeViewState();
}
class HomeViewState extends State<HomeView> {
final List<Schedule> scheduleList = [
Schedule("Hotel 1", DateTime.now(), DateTime.now(), "Germany"),
Schedule("Hotel 2", DateTime.now(), DateTime.now(), "France")
];
final Icon actionIcon = Icon(Icons.plus_one);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Dashboard"),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: actionIcon,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => UnscheduledField()),
);
},
)
],
),
body: Container(
child: ListView.builder(
itemCount: scheduleList.length,
itemBuilder: (context, int index) => buildCard(context, index)),
));
}
}
Widget buildCard(BuildContext context, int index) {
final List<Schedule> scheduleList = [
Schedule("Hotel 1", DateTime.now(), DateTime.now(), "Germany"),
Schedule("Hotel 2", DateTime.now(), DateTime.now(), "France")
];
final schedule = scheduleList[index];
return Container(
child: GestureDetector(
onTap: () {
showBottomSheet(
context: context,
builder: (context) => Container(
height: 550,
color: Colors.lightBlue,
));
},
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8, bottom: 4),
child: Row(
children: <Widget>[
Text(schedule.companyName,
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold)),
Spacer(),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 4, bottom: 4),
child: Row(
children: <Widget>[Text(schedule.location)],
),
),
Padding(
padding: const EdgeInsets.only(top: 4.0, bottom: 4),
child: Row(
children: <Widget>[
Text('check in at:'),
Text(
"${DateFormat('HH:mm').format(schedule.startTime).toString()}"),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 4.0, bottom: 4),
child: Row(children: <Widget>[
Text('check out at:'),
Text(
"${DateFormat('HH:mm').format(schedule.endTime).toString()}"),
]),
),
Row(
children: <Widget>[
Expanded(
child: SizedBox(
height: 40,
child: ListTile(
trailing: IconButton(
onPressed: () {
alert(context);
},
icon: Icon(
Icons.close,
),
color: Colors.red,
),
),
),
),
Expanded(
child: SizedBox(
height: 40,
child: ListTile(
trailing: IconButton(
onPressed: () {
final snackbar = SnackBar(
content: Text('Successfully added'),
duration: Duration(seconds: 2),
);
Scaffold.of(context).showSnackBar(snackbar);
},
icon: Icon(
Icons.check,
),
color: Colors.lightGreen[300],
),
),
),
),
],
),
]))),
));
}
void alert(BuildContext context) {
var alertDialog = AlertDialog(
title: Text("Confirmation"),
content: Text("Are you sure you want to delete this?"),
actions: <Widget>[
FlatButton(
child: Text("No"),
onPressed: () {
Navigator.of(context).pop();
}),
FlatButton(
child: Text("Yes"),
onPressed: () {
Navigator.of(context).pop();
})
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alertDialog;
});
}
Any help would be appreciated! thanks
your code is perfect but you have to define alert dialog before you call it,
So define Alert Dialog before you call it in OnPress method of button and Pass it to alert method
class HomeView extends StatefulWidget {
HomeViewState createState() => HomeViewState();
}
class HomeViewState extends State<HomeView> {
final List<Schedule> scheduleList = [
Schedule("Hotel 1", DateTime.now(), DateTime.now(), "Germany"),
Schedule("Hotel 2", DateTime.now(), DateTime.now(), "France")
];
final Icon actionIcon = Icon(Icons.plus_one);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Dashboard"),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: actionIcon,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => UnscheduledField()),
);
},
)
],
),
body: buildCard(context, 0),
body: Container(
child: ListView.builder(
itemCount: scheduleList.length,
itemBuilder: (context, int index) => buildCard(context, index)),
)
);
}
}
Widget buildCard(BuildContext context, int index) {
final List<Schedule> scheduleList = [
Schedule("Hotel 1", DateTime.now(), DateTime.now(), "Germany"),
Schedule("Hotel 2", DateTime.now(), DateTime.now(), "France")
];
final schedule = scheduleList[index];
return Container(
child: GestureDetector(
onTap: () {
showBottomSheet(
context: context,
builder: (context) => Container(
height: 550,
color: Colors.lightBlue,
));
},
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8, bottom: 4),
child: Row(
children: <Widget>[
Text(schedule.companyName,
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold)),
Spacer(),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 4, bottom: 4),
child: Row(
children: <Widget>[Text(schedule.location)],
),
),
Padding(
padding: const EdgeInsets.only(top: 4.0, bottom: 4),
child: Row(
children: <Widget>[
Text('check in at:'),
Text(
"${DateFormat('HH:mm').format(schedule.startTime).toString()}"),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 4.0, bottom: 4),
child: Row(children: <Widget>[
Text('check out at:'),
Text(
"${DateFormat('HH:mm').format(schedule.endTime).toString()}"),
]),
),
Row(
children: <Widget>[
Expanded(
child: SizedBox(
height: 40,
child: ListTile(
trailing: IconButton(
onPressed: () {
var alertDialog = AlertDialog(
title: Text("Confirmation"),
content:
Text("Are you sure you want to delete this?"),
actions: <Widget>[
FlatButton(
child: Text("No"),
onPressed: () {
Navigator.of(context).pop();
}),
FlatButton(
child: Text("Yes"),
onPressed: () {
Navigator.of(context).pop();
})
],
);
alert(context, alertDialog);
},
icon: Icon(
Icons.close,
),
color: Colors.red,
),
title: Text("hello"),
),
),
),
Expanded(
child: SizedBox(
height: 40,
child: ListTile(
trailing: IconButton(
onPressed: () {
final snackbar = SnackBar(
content: Text('Successfully added'),
duration: Duration(seconds: 2),
);
Scaffold.of(context).showSnackBar(snackbar);
},
icon: Icon(
Icons.check,
),
color: Colors.lightGreen[300],
),
),
),
),
],
),
]))),
));
}
void alert(BuildContext context, AlertDialog alertDialog) {
showDialog(
context: context,
builder: (BuildContext context) {
return alertDialog;
});
}