I am trying to get data from my api and display it using Card widget .I want to align everything in an even manner without using a table. I have a written a code for it. But still there are a few rows which are not aligned properly.
Please write a detailed answer
Here is my table:
Here is my code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'Posts.dart';
late List<Post> drivers;
class MyApp extends StatefulWidget {
// to set the root of app.
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.green,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
late final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Center(
child: const Text("Driver Table",
style: TextStyle(
fontWeight: FontWeight.w900,
),
),
),
),
body: Container(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:[
Expanded(
child: Container(
height: 70,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: const BorderRadius.all(Radius.circular(20))
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [
Text('Did',
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.w900
),
),
Text('Dname',style: TextStyle(
fontSize: 24,
color: Colors.white,
fontWeight: FontWeight.w900
),),
Text('Age',style: TextStyle(
fontSize: 24,
color: Colors.white,
fontWeight: FontWeight.w900
),),
],
),
),
),
]
),
Expanded(
child: Container(
child:_buildBody(context),
),
)
],
),
color:const Color(0xFF303030),
),
//
);
}
// build list view & manage states
FutureBuilder<List<Post>> _buildBody(BuildContext context) {
final HttpService httpService = HttpService();
return FutureBuilder<List<Post>>(
future: httpService.getPosts(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final List<Post>? posts = snapshot.data; //marked
return _buildPosts(context, posts!);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
);
}
// build list view & its tile
ListView _buildPosts(BuildContext context, List<Post> posts) {
Row(
children: [
Container(
child: const Text('Did',
style: TextStyle(
color: Colors.white,
),
),
),
Container(
child: const Text('Dname',style: TextStyle(
color: Colors.white,
),),
),
Container(
child: const Text('Age',style: TextStyle(
color: Colors.white,
),),
),
],
);
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: posts.length,
padding: const EdgeInsets.all(20),
itemBuilder: (context, index) {
return Container(
height:70,
child: Card(
shadowColor: Colors.white,
color:const Color(0xFF303030),
elevation: 1,
child: IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(posts[index].Did,style: const TextStyle(fontWeight: FontWeight.bold,
color:Colors.white,),),
Text(posts[index].Dname,style: const TextStyle(fontWeight: FontWeight.bold,
color:Colors.white,),),
Text(posts[index].Age,style: const TextStyle(fontWeight: FontWeight.bold,color:Colors.white,),
),
],
),
),
),
);
},
);
}
}
class HttpService {
Future<List<Post>> getPosts() async {
Response res = await get(
Uri.parse('http://localhost/localconnect/driver_change.php'));
print(res.body);
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Post> posts = body.map(
(dynamic item) => Post.fromJson(item),
).toList();
return posts;
} else {
throw "Unable to retrieve posts.";
}
}
}
Posts.dart
import 'dart:convert';
List<Post> userFromJson(String str) => List<Post>.from(json.decode(str).map((x) => Post.fromJson(x)));
String userToJson(List<Post> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Post{
Post({
required this.Did,
required this.Dname,
required this.Age,
});
String Did;
String Dname;
String Age;
factory Post.fromJson(Map<String, dynamic> json) => Post(
Did: json["Did"],
Dname: json["Dname"],
Age: json["Age"],
);
Map<String, dynamic> toJson() => {
"Did": Did,
"Dname": Dname,
"Age": Age,
};
}
For every Text widget use
textAlign: TextAlign.center,
and on every Row Row
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
Main issue is coming from ListView.builder's
padding: const EdgeInsets.all(20), //remove this padding
Remove the padding here and no need to use IntrinsicHeight widget.
Related
I am learning Flutter now and i have a screen that loading many series characters, and i have an icon in the AppBar showing
ModalBottomSheet and it have many choices to filter to update data with the new chosen ones.
I got the choices and stored the in a List of Strings but i dont know how to pass it to a function in my cubit file and i don't know how to update data using cubit , i tried many ways but didn't work with me.
Here's my code
import 'package:breakingbad/data/models/breaking_bad_characters.dart';
import 'package:breakingbad/domain/cubit/rick_and_morty_cubit.dart';
import 'package:breakingbad/presentation/character-detail.dart';
import 'package:conditional_builder_null_safety/conditional_builder_null_safety.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../widgets/character_item.dart';
import '../widgets/chip_choice.dart';
class MyHomePage extends StatefulWidget {
static String id ='home';
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return BlocConsumer<RickAndMortyCubit,RickAndMortyState>(
listener: (context, state){},
builder: (context, state) {
var cubit = RickAndMortyCubit.get(context);
return Scaffold(
appBar: AppBar(
title: const Center(child: Text('Rick And Morty')),
actions: [
IconButton(
padding: const EdgeInsets.only(right: 25),
onPressed: (){
showModalBottomSheet(
context: context,
builder: (context) =>
Column(
children: [
Container(
alignment: Alignment.center,
color: Colors.black,
width: double.infinity,
height: 50,
child: const Text('Filter Characters',style: TextStyle(color:
Colors.white,fontSize: 22),),
),
const ChoiceChipWidget(),
],
)
);
},
icon: const Icon(Icons.filter_list_sharp,size: 40,)),
],
),
body: ConditionalBuilder(
condition: state is RickAndMortyCharsLoaded,
fallback: (context)=> const Center(child: CircularProgressIndicator()),
builder: (context) => GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2 / 3,
crossAxisSpacing: 1,
mainAxisSpacing: 1,
),
itemCount: cubit.allHuman.length,
itemBuilder: (context,index) =>
CharacterItem(
rickAndMortyCharacters: cubit.allHuman[index],
widget:CharacterDetail(rickAndMortyCharacters: cubit.allHuman[index]),
)
),
)
);
}
);
}
}
import 'package:breakingbad/domain/cubit/rick_and_morty_cubit.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ChoiceChipWidget extends StatefulWidget {
const ChoiceChipWidget( {super.key, });
#override
State<ChoiceChipWidget> createState() => _ChoiceChipWidgetState();
}
class _ChoiceChipWidgetState extends State<ChoiceChipWidget> {
String selectedChoice1 = "";
String selectedChoice2 = "";
String selectedChoice3 = "";
List<String> filter=[];
#override
Widget build(BuildContext context) {
return BlocBuilder<RickAndMortyCubit, RickAndMortyState>(
builder: (context, state) {
var cubit = RickAndMortyCubit.get(context);
return Column(
children: [
Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'Gender',
style: TextStyle(fontSize: 20),
), //Text
),
Row(
children: cubit.gender.map((item){
return Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
labelStyle: const TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22.0),
),
backgroundColor: Colors.grey[300],
selectedColor: Colors.blue,
selected: selectedChoice1 == item,
onSelected: (selected) {
setState(() {
selectedChoice1 = item;
filter.add(selectedChoice1);
});
},
),
);
}).toList()
),
Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'Species',
style: TextStyle(fontSize: 20),
), //Text
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children:cubit.species.map((item){
return Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
labelStyle: const TextStyle(
fontSize: 18,
color: Colors.black, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22.0),
),
backgroundColor: Colors.grey[300],
selectedColor: Colors.blue,
selected: selectedChoice2 == item,
onSelected: (selected) {
setState(() {
selectedChoice2 = item;
filter.add(selectedChoice2);
});
},
),
);
}).toList()
),
),
Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'Statue',
style: TextStyle(fontSize: 20),
), //Text
),
Row(
children:cubit.statue.map((item){
return Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
labelStyle: const TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22.0),
),
backgroundColor: Colors.grey[300],
selectedColor: Colors.blue,
selected: selectedChoice3 == item,
onSelected: (selected) {
setState(() {
selectedChoice3 = item;
filter.add(selectedChoice3);
});
},
),
);
}).toList()
),
SizedBox(height: 4,),
InkWell(
onTap: (){
// here i want to apply changes
Navigator.pop(context);
},
child: Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'apply',
style: TextStyle(fontSize: 20),
), //Text
),
),
],
);
},
);
}
}
I have two main functions, the first one get all characters to the home screen:
List<Characters>?
getAllCharacters(){
myRepository.
getAllCharacters().then(
(allCharacters)=>
this.allCharacters =
allCharacters;
);
return allCharacters;
}
and the second function that takes a parameter of List of Strings which i suppose to get them from the filtering in bottomSheet;
List<Characters>?
getFilteredCharacters
(List<String> list){
myRepository
.getFilteredCharacters(list)
.then((filteredCharacters)=>
this.filteredCharacters =
filteredCharacters;
);
return filteredCharacters;
}
Anyone could help me in this issue?
I want to show the fetched love calculator data after button click but how to visible it? Please answer
import 'dart:io';
import 'package:AllInOneCalci/CustomTextField.dart';
import 'package:AllInOneCalci/Post.dart';
import 'package:AllInOneCalci/customAppBar.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
class LoveCalUI extends StatelessWidget {
#override
Widget build(BuildContext context) {
var AppBarHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: customAppBar(
height: (AppBarHeight / 3) * 0.4,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(top: 18.0),
child: Text(
'All In One Cali',
style: TextStyle(
color: Colors.black,
fontSize: 35.0,
fontFamily: 'DancingScript',
fontWeight: FontWeight.bold),
),
),
],
),
),
body: CustomFetchData(),
);
}
}
class CustomFetchData extends StatefulWidget {
#override
_CustomFetchDataState createState() => _CustomFetchDataState();
}
class _CustomFetchDataState extends State<CustomFetchData> {
TextEditingController firstNameController = new TextEditingController();
TextEditingController secondNameController = new TextEditingController();
Future<Post> getData() async {
final response = await http.get(
'https://love-calculator.p.rapidapi.com/getPercentage?fname=aalia&sname=Alice',
headers: {
'x-rapidapi-host': 'love-calculator.p.rapidapi.com',
'x-rapidapi-key':
'84e84770b9msh59a96d8b03cb4aap1615a1jsn1cd0ef******',
});
if (response.statusCode == 200) {
return Post.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load api');
}
}
Widget ErrorDesign() {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
alignment: Alignment.center,
child: Text(
'Error: Kindly Connect to Internet',
style: TextStyle(
color: Colors.redAccent,
fontFamily: 'DancingScript',
fontSize: 40.0,
fontWeight: FontWeight.bold,
),
),
),
);
}
Widget DisplayData(String percentageValue, String result) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
height: 100.0,
color: Colors.black,
child: Column(
children: [
Text('Percentage is $percentageValue',
style: TextStyle(
color: Colors.white,
)),
Text('Result is: $result',
style: TextStyle(
color: Colors.white,
)),
],
),
),
);
}
Widget FetchedCalculationValues() {
return Column(
children: [
Container(
child: FutureBuilder<Post>(
future: getData(),
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: CircularProgressIndicator(),
),
);
} else {
if (snapshot.hasError) {
return Container(
child: ErrorDesign(),
);
} else {
return DisplayData(
snapshot.data.percentage, snapshot.data.result);
}
}
})),
],
);
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 18.0, right: 18.0, top: 15.0),
child: CustomTextField('First Name', "", Colors.cyan,
Colors.cyanAccent, Colors.redAccent, firstNameController),
),
Padding(
padding: const EdgeInsets.only(left: 18.0, right: 18.0),
child: CustomTextField('Second Name', "", Colors.red,
Colors.redAccent, Colors.cyanAccent, secondNameController),
),
Padding(
padding: const EdgeInsets.all(18.0),
child: MaterialButton(
color: Colors.redAccent,
child: Text(
'Result',
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {
FetchedCalculationValues();
print('Fetch Calling');
}),
),
Visibility(
visible: false,
child: FetchedCalculationValues(),
),
],
);
}
#override
// ignore: must_call_super
void initState() {
getData();
}
}
How to make the function for api call visible to the screen after button click.
Also I want to use the text field's values at the place of defalut values
Can you solve my problem? It will be very helpful if you do so. I am a newbie and learning flutter since 15 days. Help me so that I can learn it fast. Also the flutter's community is growing fast so it will be easy for me not to wait for response. Thank You.
I have created simplified, single-screen, app without any extra capabilities to solve exactly your issue. It contains two text fields, two Text widgets to display API results and a floating action button to make request.
Key concepts that you should know to make this code are http requests and asynchronous coding. Those links are good starting points for you to get a sense of what actually happens
To summarize what exactly you need:
You send request asynchronously to the API declaring function with async keyword and await keyword in front of http.get() function. This allows you to wait for the result of the request without freezing the app
When result comes back, the rest of the _getNames() function gets executed, which includes setState(). setState() rebuilds your widget and updates values in Text() widgets
Full code:
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int percentage = 0;
String resultString = "";
Map<String, String> requestHeaders = {
'x-rapidapi-host': 'love-calculator.p.rapidapi.com',
'x-rapidapi-key': 'your API key',
};
final name1Controller = TextEditingController();
final name2Controller = TextEditingController();
void _getNames({String name1, String name2}) async {
final response = await http.get(
'https://love-calculator.p.rapidapi.com/getPercentage?fname=$name1&sname=$name2',
// Send authorization headers to the backend.
headers: requestHeaders,
);
final responseJson = json.decode(response.body);
setState(() {
percentage = int.parse(responseJson['percentage']);
resultString = responseJson['result'];
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: name1Controller,
decoration: InputDecoration(
hintText: "name 1",
),
),
TextField(
controller: name2Controller,
decoration: InputDecoration(
hintText: "name 2",
),
),
SizedBox(
height: 10,
),
Text(
'Your Score is: $percentage',
),
Text(
'$resultString',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_getNames(
name1: name1Controller.text,
name2: name2Controller.text,
);
},
tooltip: 'Increment',
child: Text('Go'),
),
);
}
}
I've gotten a flutter problem.
I wanna try to update my screen after
setState(() => {
widgetScreenBuilder = screenWidgets[currentScreen]
});
in my category selector has been called. I've tried to make it so I have one main screen which has the function for my category selector and then I'd like to have the current screen/widget as a function. Then I could change the screen/widget below my selector just by changing the function. I just can't find a way to refresh the page / the body of the main screen after I've changed the function (widget below category selector)
My main screen:
import 'package:flutter/material.dart';
import 'package:app/widgets/categorySelector.dart';
import 'package:app/data/appData.dart';
class MainScreen extends StatefulWidget {
#override
_MainScreen createState() => _MainScreen();
}
class _MainScreen extends State<MainScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColorDark,
appBar: AppBar(
backgroundColor: Theme.of(context).primaryColorDark,
elevation: 0.0,
title: Center(
child: Text(
"Tournaments",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 26.0,
letterSpacing: 1.1
)
),
),
),
body: Column(
children: <Widget>[
CategorySelector(),
widgetScreenBuilder
],
),
);
}
}
My category selector:
import 'package:app/data/appData.dart';
import 'package:flutter/material.dart';
class CategorySelector extends StatefulWidget {
#override
_CategorySelectorState createState() => _CategorySelectorState();
}
class _CategorySelectorState extends State<CategorySelector> {
final List<String> categories = ['All games', 'New game', "New player", "Top players"];
#override
Widget build(BuildContext context) {
return Container(
height: 75.0,
color: Theme.of(context).primaryColorDark,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
if (currentScreen != index) {
currentScreen = index;
setState(() => {
widgetScreenBuilder = screenWidgets[currentScreen]
});
}
},
child: Center(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 20.0),
child: Text(
categories[index],
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
letterSpacing: 1.2,
color: index == currentScreen ? Colors.white : Colors.white50
)
)
),
),
);
}
)
);
}
}
The appData.dart file where widgetScreenBuilder, screenWidgets and currentScreen is located:
import 'package:app/widgets/allGames.dart';
int currentScreen = 0;
List screenWidgets = [AllGames(), NewGame()];
var widgetScreenBuilder = screenWidgets[currentScreen];
I'm new to app development, dart and flutter so any help would be appreciated!
Thanks <3
I can't understand you question well,
But i think you should try didChangeDependencies
Check it : https://api.flutter.dev/flutter/widgets/State/didChangeDependencies.html
change your MainScreen class to this :
class MainScreen extends StatefulWidget {
#override
_MainScreen createState() => _MainScreen();
}
class _MainScreen extends State<MainScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColorDark,
appBar: AppBar(
backgroundColor: Theme.of(context).primaryColorDark,
elevation: 0.0,
title: Center(
child: Text("Tournaments",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 26.0,
letterSpacing: 1.1)),
),
),
body: CategorySelector(), // delete column and just put CategorySelector()
);
}
}
and change your CategorySelector class to this :
class CategorySelector extends StatefulWidget {
#override
_CategorySelectorState createState() => _CategorySelectorState();
}
class _CategorySelectorState extends State<CategorySelector> {
final List<String> categories = [
'All games',
'New game',
"New player",
"Top players"
];
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
height: 75.0,
color: Theme.of(context).primaryColorDark,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
if (currentScreen != index) {
currentScreen = index;
setState(
() =>
{widgetScreenBuilder = screenWidgets[currentScreen]},
);
}
},
child: Center(
child: Padding(
padding:
EdgeInsets.symmetric(horizontal: 20.0, vertical: 20.0),
child: Text(
categories[index],
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
letterSpacing: 1.2,
color: index == currentScreen
? Colors.white
: Colors.white54),
),
),
),
);
},
),
),
widgetScreenBuilder, // add widgetScreenBuilder here
],
);
}
}
Your code is working properly now :)
setState() can only make changes in its own class.
I wanted to send Data/images from one page to another. In the Homepage when I tap on the add Icon button image should be passed to the Cart page and if the icon is tapped again image is removed from the Cart page. But, the cart page should be accessed from bottom navigation bar.
but it is showing an error called 1 positional argument(s) expected, but 0 found.
Try adding the missing arguments.. when it calls the cart page.
HomePage.dart file
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blueGrey,
),
home: NavBar(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Dish> _dishes = List<Dish>();
List<Dish> _cartList = List<Dish>();
#override
void initState() {
super.initState();
_populateDishes();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16.0, top: 8.0),
child: GestureDetector(
child: Stack(
alignment: Alignment.topCenter,
children: <Widget>[
Icon(
Icons.shopping_cart,
size: 36.0,
),
if (_cartList.length > 0)
Padding(
padding: const EdgeInsets.only(left: 2.0),
child: CircleAvatar(
radius: 8.0,
backgroundColor: Colors.red,
foregroundColor: Colors.white,
child: Text(
_cartList.length.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12.0,
),
),
),
),
],
),
onTap: () {
if (_cartList.isNotEmpty)
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Cart(_cartList),
),
);
},
),
)
],
),
body: _buildGridView(),
);
}
ListView _buildListView() {
return ListView.builder(
itemCount: _dishes.length,
itemBuilder: (context, index) {
var item = _dishes[index];
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 2.0,
),
child: Card(
elevation: 4.0,
child: ListTile(
leading: Icon(
item.icon,
color: item.color,
),
title: Text(item.name),
trailing: GestureDetector(
child: (!_cartList.contains(item))
? Icon(
Icons.add_circle,
color: Colors.green,
)
: Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
setState(() {
if (!_cartList.contains(item))
_cartList.add(item);
else
_cartList.remove(item);
});
},
),
),
),
);
},
);
}
GridView _buildGridView() {
return GridView.builder(
padding: const EdgeInsets.all(4.0),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: _dishes.length,
itemBuilder: (context, index) {
var item = _dishes[index];
return Card(
elevation: 4.0,
child: Stack(
fit: StackFit.loose,
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
item.icon,
color: (_cartList.contains(item))
? Colors.grey
: item.color,
size: 100.0,
),
Text(
item.name,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subhead,
)
],
),
Padding(
padding: const EdgeInsets.only(
right: 8.0,
bottom: 8.0,
),
child: Align(
alignment: Alignment.bottomRight,
child: GestureDetector(
child: (!_cartList.contains(item))
? Icon(
Icons.add_circle,
color: Colors.green,
)
: Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
setState(() {
if (!_cartList.contains(item))
_cartList.add(item);
else
_cartList.remove(item);
});
},
),
),
),
],
));
});
}
void _populateDishes() {
var list = <Dish>[
Dish(
name: 'Chicken Zinger',
icon: Icons.fastfood,
color: Colors.amber,
),
Dish(
name: 'Chicken Zinger without chicken',
icon: Icons.print,
color: Colors.deepOrange,
),
Dish(
name: 'Rice',
icon: Icons.child_care,
color: Colors.brown,
),
Dish(
name: 'Beef burger without beef',
icon: Icons.whatshot,
color: Colors.green,
),
Dish(
name: 'Laptop without OS',
icon: Icons.laptop,
color: Colors.purple,
),
Dish(
name: 'Mac wihout macOS',
icon: Icons.laptop_mac,
color: Colors.blueGrey,
),
];
setState(() {
_dishes = list;
});
}
}
Cart.dart file
import 'package:flutter/material.dart';
import 'dish_object.dart';
class Cart extends StatefulWidget {
final List<Dish> _cart;
Cart(this._cart);
#override
_CartState createState() => _CartState(this._cart);
}
class _CartState extends State<Cart> {
_CartState(this._cart);
List<Dish> _cart;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Cart'),
),
body: ListView.builder(
itemCount: _cart.length,
itemBuilder: (context, index) {
var item = _cart[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2.0),
child: Card(
elevation: 4.0,
child: ListTile(
leading: Icon(
item.icon,
color: item.color,
),
title: Text(item.name),
trailing: GestureDetector(
child: Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
setState(() {
_cart.remove(item);
});
},
),
),
),
);
},
),
);
}
}
NavBar.dart file
import 'package:flutter/material.dart';
import 'package:sharewallpaper/cart.dart';
import 'package:sharewallpaper/main.dart';
class NavBar extends StatefulWidget {
#override
_NavBarState createState() => _NavBarState();
}
class _NavBarState extends State<NavBar> {
int _currentIndex = 0;
final List<Widget> _children = [
MyHomePage(),
Cart(), ** This line is throwing an error **
];
void onTappedBar(int index) {
setState(() {
_currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTappedBar,
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(
icon: Icon(Icons.bookmark), title: Text('BookMark')),
],
),
);
}
}
Yep, it will throw an error because the constructor of the Cart class is expecting one parameter to be passed in. You could use a named constructor instead like this:
class Cart extends StatefulWidget {
final List<Dish> _cart;
Cart(this._cart);
That way, you can call it like so:
Cart(cart: _cartList),
But if you actually need the cart list, I would recommend that you write a provider to keep track of the cart data across screens.
Can we have a selectable ListTile() just like ChoiceChip() ?
I want my Card() which contains ListTile to be selectable.
Here is the Image of the Cards:
Here is the code of a Card:
Container(
width: 98.0,
child: Card(
child: ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Flat No',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
],
),
subtitle: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'102',
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
),
Just use ChoiceChip with Column.
Demo here: DartPad
Try this,
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final flatRoomList = List.generate(50, (i) => i + 1);
final selectedFlatRooms = <int>{};
final alreadyReservedRooms = <int>{2, 4, 23, 7, 13, 39};
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
),
itemCount: flatRoomList.length,
itemBuilder: (context, index) {
final roomNo = flatRoomList[index];
return MyChoiceChip(
flatNo: roomNo.toString(),
selected: selectedFlatRooms.contains(roomNo),
onSelected: alreadyReservedRooms.contains(roomNo)
? null
: (isSelected) {
setState(() {
if (isSelected)
selectedFlatRooms.add(roomNo);
else
selectedFlatRooms.remove(roomNo);
});
},
);
},
),
),
);
}
}
class MyChoiceChip extends StatelessWidget {
final String flatNo;
final bool selected;
final ValueChanged<bool> onSelected;
const MyChoiceChip({
Key key,
#required this.flatNo,
#required this.selected,
this.onSelected,
}) : assert(flatNo != null),
assert(selected != null),
super(key: key);
#override
Widget build(BuildContext context) {
return ChoiceChip(
elevation: 5.0,
backgroundColor: Colors.green[50],
disabledColor: Colors.red[300],
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
label: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"Flat No",
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
Text(
flatNo,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24.0,
),
),
],
),
),
selected: selected,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
onSelected: onSelected,
);
}
}
If you want to make your Card clickable, you just need to wrap your Card Widget with GestureDetector, InkWell, or ... .
child: GestureDetector(
oneTap: (){...}
child: Card(..),
);