Related
I am trying to display a list using a list title but would like to add a text with a click event to the top of the list.
How could I do it?
I would be very grateful for the help.
I am trying to display a list using a list title but would like to add a text with a click event to the top of the list.
How could I do it?
I would be very grateful for the help.
Code and image::
Widget StatefulBuilderSuggestions(BuildContext context ,List <SearchDelegateModel> historialMenuPrincipal){
return Container(
child:StatefulBuilder(
builder:(context,setState)
{
return Container(
child: ListView.builder(
itemCount: historialMenuPrincipal.length,
itemBuilder: (context,i)
{
contentPadding: EdgeInsets.symmetric(vertical: 12,horizontal: 16);
return
ListTile(
subtitle: Text(historialMenuPrincipal[i] == null ? "no data" :historialMenuPrincipal[i].email,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 20,
fontWeight: FontWeight.bold,
),
),
title: Text(historialMenuPrincipal[i] == null ? "no data" :historialMenuPrincipal[i].contrasena,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 20,
fontWeight: FontWeight.bold,
),
),
trailing: historialMenuPrincipal[i] != null || historialMenuPrincipal.isEmpty
? IconButton(
icon: Icon(Icons.cancel,color: Colors.black,),
onPressed: () {
setState(() {
historialMenuPrincipal.remove(historialMenuPrincipal[i]);
});
},): null
);
}
),
);
}
)
);
}
use a column with 2 parts, title as a textbutton and above the list
Container(
child: Column(
children: [
TextButton(
onPressed: () {
hideList = !hideList;
},
child: Text("Title"),
),
hideList ? ListView() : Container(),
],
))
something like this
In order to add a Text widget above a list, both widgets should be inside a column and important thing to note is that ListView widget must be inside a Expanded widget and for the text widget to be clickable, use GestureDetector.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
children: [
GestureDetector(
onTap: () {}, child: const Text("Some text above the list")),
Expanded(
child: ListView.builder(
itemCount: 50,
itemBuilder: (context, i) {
return Container(
margin: const EdgeInsets.all(16),
color: Colors.pinkAccent,
child: Text("$i"));
},
),
),
],
),
),
);
}
Here I have a list of id and title,
I would like to create pages. each page contains one sentences of title. Once click ok button it will navigate to next page of the list.
How can I do that within a single page?
I am a newbie but I would like to minimize my code,
it is a bit confusing.
Here are the images of my code.
import 'package:flutter/material.dart';
import 'package:starbucks/appLayout.dart';
import 'package:starbucks/appTheme.dart';
import 'package:starbucks/components/customAppBar.dart';
import 'package:provider/provider.dart';
import 'package:starbucks/pages/payment.dart';
import 'package:starbucks/providers/cartProvider.dart';
import 'package:starbucks/utils/data.dart';
class CartConfirm extends StatelessWidget {
const CartConfirm({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final totalPrice = context.read<CartProvider>().totalPrice;
return Scaffold(
appBar: CustomAppbar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
alignment: Alignment.center,
width: 1024,
decoration: BoxDecoration(
border: Border.all(color: AppTheme.green),
borderRadius: BorderRadius.circular(5),
),
padding: const EdgeInsets.all(50),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"ราคารวม: " ,
style: TextStyle(color: Colors.white),
),
AppLayout.staticField(content: " $totalPrice "),
Text(
" บาท",
style: TextStyle(color: Colors.white),
),
],
),
),
Container(
width: 1024,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AppLayout.button(title: "จ่ายด้วยบัตร", onPressed: () {}),
AppLayout.button(title: "จ่ายด้วยเงินสด", onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
Payment(id: id, title: title,),
));},),
],
),
),
],
),
),
);
}
}
static List<Payment> payment = [
Payment(
id: 1,
title: "กรุณาใส่เงิน",
),
Payment(
id: 2,
title: "ระบบกำลังตรวจนับเงิน",
),
Payment(
id: 3,
title: "กรุณารับบัตรคิวและเงินทอน",
),
Payment(
id: 4,
title: "ขอบคุณที่ใช้บริการ",
),
];
I have made the categories page for my project by making categories page and the data which I am going to display in the category page is imported from data.dart file and I have to use the visible widget but I am facing an error using the code.
The code of data.dart is below:
List<Category> categories = [
Category(
name: 'Accessories',
icon: FontAwesomeIcons.tshirt,
),
Category(
name: 'AutoMobiles',
icon: FontAwesomeIcons.car,
),
Category(
name: 'Beauty and Health',
icon: FontAwesomeIcons.hatCowboy,
),
Category(
name: 'Business & Industrial',
icon: FontAwesomeIcons.cashRegister,
),
Category(
name: 'Book and Learning',
icon: FontAwesomeIcons.book,
),
Category(
name: 'Computer and Peripherals ',
icon: FontAwesomeIcons.laptop,
),
Category(
name: 'Electronics ',
icon: FontAwesomeIcons.tv,
),
and the code for making the categories page is given below:
class CategoryPage extends StatefulWidget {
static String id = 'categoryPage';
#override
_CategoryPageState createState() => _CategoryPageState();
}
class _CategoryPageState extends State<CategoryPage> {
bool isClicked = false;
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: [
Text(
'All Categories',
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: categories.length,
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Expanded(
child: ListTile(
leading: GestureDetector(
onTap: () {
setState(() {
isClicked = !isClicked;
});
},
child: Icon(
categories[index].icon,
),
),
title: Visibility(
visible: isClicked,
child: Text(
categories[index].name,
),
),
),
),
Expanded(
child: ListView.builder(
itemCount: 1,
itemBuilder: (context, index) {
return ListTile(
leading: Text('Hello!'),
);
}),
)
],
);
},
),
),
],
),
// bottomNavigationBar: NavBar(),
),
);
}
}
I have researched well but am unable to solve the problem. How can I get the desirable output and the image file which I was trying to make in the categories page like the image attached below?
A Column will always try to shrinkWrap it's children, using Expanded means the child is supposed to occupy the entire height, these two are mutually exclusive.
A better way to use a Single Scroll View without all those Expanded widgets would be this.
class CategoryPage extends StatefulWidget {
static String id = 'categoryPage';
#override
_CategoryPageState createState() => _CategoryPageState();
}
class _CategoryPageState extends State<CategoryPage> {
bool isClicked = false;
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Text(
'All Categories',
),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: categories.length,
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Expanded(
child: ListTile(
leading: GestureDetector(
onTap: () {
setState(() {
isClicked = !isClicked;
});
},
child: Icon(
categories[index].icon,
),
),
title: Visibility(
visible: isClicked,
child: Text(
categories[index].name,
),
),
),
),
Expanded(
child: ListView.builder(
itemCount: 1,
itemBuilder: (context, index) {
return ListTile(
leading: Text('Hello!'),
);
}),
),
],
);
},
),
],
),
),
// bottomNavigationBar: NavBar(),
),
);
}
}
If the Error is caused by the Inner ListView, you can apply the same logic of SingleChildScrollView()
I have a class ViewTotalItemProvider which extends the ChangeNotifier. Inside the class, there is a list like this.
class ViewTotalItemProvider extends ChangeNotifier{
List<CartPlantLists> cartPlantList3 = [];
}
Additionally, there are 3 screens including class like, PlantFeatureScreen1, ParticularPlant2, CartDetais3. All are stateful widget and I am adding some items in second screen i.e. ParticularPlant2 class.
When I try to show the items from list in the second screen and the third screen it works.
But the value is not updated in the firstScreen i.e. PlantFeatureScreen1. However, when I reload the app, it shows the updated value.
why is this happening? How can I solve it?
Code
ViewTotalItemProvider
List<CartPlantLists> cartPlantList3 = [];
class ViewTotalItemProvider extends ChangeNotifier{
addQuantity(index){
cartPlantList3[index].qu++;
notifyListeners();
}
subtrachQuantity(index){
cartPlantList3[index].qu--;
notifyListeners();
}
}
firstScreen PlantFeatureScreen1 (Here I want to update the value in the very last widget)
class PlantFeatureScreen1 extends StatefulWidget {
#override
_PlantFeatureScreen1State createState() => _PlantFeatureScreen1State();
}
class _PlantFeatureScreen1State extends State<PlantFeatureScreen1> {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ViewTotalItemProvider>(
create: (context) => ViewTotalItemProvider(),
child:Builder(builder: (context) {
return Column(
children: <Widget>[
TopAppBar(),
Expanded(
flex: 1,
child: Align(
alignment: Alignment(-1, 0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
),
child: Text(
"Plants",
style: TextStyle(fontSize: 30, fontWeight: FontWeight.w700),
),
),
),
),
Expanded(
flex: 5,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.blue,
),
child: DefaultTabController(
length: 5,
child: Column(
children: [
Container(
height: 50,
width: double.infinity,
child: TabBar(
isScrollable: true,
tabs: ourAllLists.tabMaker(),
),
),
Container(
height: 317,
width: double.infinity,
decoration: BoxDecoration(color: Colors.white),
child: TabBarView(
children: ourAllLists.tabViewerMaker(context),),),
],
),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: Container(
alignment: Alignment.bottomRight,
height: 120,
width: double.infinity,
child: Stack(
overflow: Overflow.visible,
children: [
Container(
height: 70,
width: 105,
decoration: BoxDecoration(
color: Color(0xFF96CA2D),
borderRadius: BorderRadiusDirectional.horizontal(
end: Radius.circular(32),
start: Radius.circular(32))),
child: Icon(FontAwesomeIcons.shoppingBag,color:Colors.white,size:30),
),
Positioned(
// top: 0,
bottom: 50,
right: 0,
child: Consumer<ViewTotalItemProvider>(
builder: (context, value, child){
return Container(
height: 35,
width: 35,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(50),
border: Border.all(color: Color(0xFF96CA2D),width: 4)
),
child: Center(child: Text(ourAllLists.totalquantity().toString(),style:TextStyle(fontSize: 20,color: Color(0xFF96CA2D)))),
);
}),
),
],
),
),
)
],
);
})
);
}
}
secondScreen ParticularPlant2
class ParticularPlant2 extends StatefulWidget {
final indexNumber;
ParticularPlant2({#required this.indexNumber});
#override
_ParticularPlant2State createState() => _ParticularPlant2State();
}
class _ParticularPlant2State extends State<ParticularPlant2> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TopAppBar(),
Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadiusDirectional.only(
bottomStart: Radius.circular(50),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
ourAllLists
.mainListAllPlantDetailsList1[widget.indexNumber].pN,
style: kPlantNameStyle,
),
Text(
ourAllLists
.mainListAllPlantDetailsList1[widget.indexNumber].ca
.toUpperCase(),
style: TextStyle(
fontSize: 15,
),
),
Text(
"\$" +
ourAllLists
.mainListAllPlantDetailsList1[widget.indexNumber]
.pr
.toString(),
style: kItemPrice,
),
SizedBox(height: 100),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
height: 80,
width: 80,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(50)),
child: Icon(
FontAwesomeIcons.flag,
color: Color(0xFF9DCD3C),
),
),
SizedBox(
height: 50,
),
FlatButton(
onPressed: () {
final tile = cartPlantList3.firstWhere(
(item) =>
item.pN ==
ourAllLists
.mainListAllPlantDetailsList1[
widget.indexNumber]
.pN,
orElse: () => null);
if (tile != null) {
} else {
cartPlantList3.add(
CartPlantLists(
quantity: 1,
plantName: ourAllLists
.mainListAllPlantDetailsList1[
widget.indexNumber]
.pN,
category: ourAllLists
.mainListAllPlantDetailsList1[
widget.indexNumber]
.ca,
price: ourAllLists
.mainListAllPlantDetailsList1[
widget.indexNumber]
.pr,
),
);
}
print(cartPlantList3.length);
},
child: Container(
height: 80,
width: 80,
decoration: BoxDecoration(
color: Color(0xFF9DCD3C),
borderRadius: BorderRadius.circular(50)),
child: Icon(FontAwesomeIcons.shoppingBag,
color: Colors.white),
),
)
],
),
Container(
height: 250,
child: Image(image: AssetImage("assets/tulip.png")),
)
],
)
],
),
)
],
),
),
),
);
}
}
It seems like you are using Provider the wrong way. The best way to do this in your scenario is to wrap MaterialApp inside MyApp() in your main.dart file with MultiProvider. Try something like this: https://pub.dev/packages/provider#multiprovider You can place a ChangeNotifierProvider inside it.
return MultiProvider(
providers: [
ChangeNotifierProvider<ViewTotalItemProvider>(
create: (context) => ViewTotalItemProvider()),
],
child: MaterialApp(...)
);
Also, you have to place a getter and setter in your Model. Here is an example:
class ImageModel extends ChangeNotifier {
String _base64Image;
get base64Image => _base64Image;
set base64Image(String base64Image) {
_base64Image = base64Image;
notifyListeners();
}
}
I would also recommend using Selector instead of Consumer (Ideally, you should use Selector instead of Consumer so that the widget only rebuilds if the value its listening to changes) Here is an example based on the model above:
#override
Widget build(BuildContext context) {
//other widgets
Selector<ImageModel, String>(
selector: (_, model) => model.base64Image,
builder: (_, image, __) {
return Text(image);
},
);
}
)
}
Here is how you can get and set it using a RaisedButton:
class _PlantFeatureScreen1State extends State<PlantFeatureScreen1> {
final itemModel;
List<CartPlantLists> myList=[];
#override
Widget build(BuildContext context) {
itemModel = Provider.of<ViewTotalItemProvider>(context,listen:false);
print(itemModel.yourVariable); //getting the value
return Container(
child: RaisedButton(
child:Text("Set Item");
onPressed:(){
itemModel.yourVariable=myList; //setting the value
},
),
);
}
}
Hope this helps! Good Luck!
Step 1:
add the dependency for the provider pattern in the pubspec.yaml file
dependencies:
flutter:
sdk: flutter
provider: ^4.1.2
Step 2:
create provider in seperate file :
class ViewTotalItemProvider with ChangeNotifier{
List<CartPlantLists> _cartPlantList1 = [];
get cartPlantList1 => _cartPlantList1 ;
set cartPlantList1 (List<CartPlantLists> selected){
_cartPlantList1 = selected;
notifyListeners();
}
}
step 3:
Use MultiProvider to wrap the MaterialApp widget in main.dart.
void main() => runApp(
MultiProvider (providers: [
ChangeNotifierProvider<ViewTotalItemProvider>.value(value:
ViewTotalItemProvider()),
],
child: MyApp()
)
);
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
Step 4:
use provider in your screen PlantFeatureScreen1 :
class PlantFeatureScreen1 extends StatefulWidget {
#override
_PlantFeatureScreen1State createState() => _PlantFeatureScreen1State();
}
class _PlantFeatureScreen1State extends State<PlantFeatureScreen1> {
var viewTotalItemProvider;
#override
Widget build(BuildContext context) {
viewTotalItemProvider = Provider.of<ViewTotalItemProvider>(context);
return Scaffold(
.......
);
}
}
step 5:
get cartPlantList1.
List<CartPlantLists> list = viewTotalItemProvider.cartPlantList1;
step 6 : set cartPlantList1.
List<CartPlantLists> list = [];
...
viewTotalItemProvider.cartPlantList1 = list;
similarly u can use for other two classes.
I have previously asked a question regarding lists in Flutter. I got good help but new problems arose within the same list. Since this new probelm is of other character then the initial question I made this new question.
I have a list (the code below is simplified from my working-code to make my problem clearer) of blue colored containers.
When the user types in 5 and press the 'submit'-button the color of the first container should change to green (if not 5 the button should turn red).
The second time the user press the 'submit'-button the second container should change color. And so on...
The problem I'm facing is that I can't get my increment to the list to work.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'listing 4',
theme: ThemeData(primarySwatch: Colors.blue),
home: FirstScreen(),
);
}
}
class FirstScreen extends StatefulWidget {
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
int sum = 5;
String userAnswer;
String correction = "";
var _controller = new TextEditingController();
int _counter = 1;
List<Color> colors = [Colors.blue, Colors.blue, Colors.blue];
submitPressed(int index) {
if (userAnswer == sum.toString()) {
setState(() {
correction = sum.toString();
colors[index] = Colors.green;
});
} else {
setState(() {
correction = sum.toString();
colors[index] = Colors.red;
});
}
}
Widget myTextField() {
return Container(
width: 50.0,
child: TextField(
controller: _controller,
textAlign: TextAlign.center,
autofocus: true,
keyboardType: TextInputType.number,
onChanged: (val) {
userAnswer = val;
},
),
);
}
Widget myListBuilder() {
return Container(
height: 50.0,
width: 300.0,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: buildContainer,
),
),
);
}
Widget buildContainer(BuildContext context, int index) {
return Container(
child: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Container(
height: 20.0,
width: 15.0,
decoration: BoxDecoration(
color: colors[index], //this is the important line
borderRadius: BorderRadius.all(Radius.circular(8.0))),
),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Listing 4'),
),
body: Container(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10.0),
child: Text('Correct answer is 5',
style: TextStyle(fontSize: 20.0)),
),
myTextField(),
RaisedButton(
child: Text('Submit'),
onPressed: () {
setState(() {
submitPressed(0); //This will naturally only give index 0
});
},
),
myListBuilder(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
buildContainer(context, 0),
buildContainer(context, 1),
buildContainer(context, 2)
],
),
RaisedButton(
child: Text('Next'),
onPressed: () {
_counter++;
_controller.clear();
myTextField();
},
),
Text('This should be container no: $_counter'),
],
),
),
),
);
}
}
I can't figure out why you have this
submitPressed(0);
This code works:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'listing 4',
theme: ThemeData(primarySwatch: Colors.blue),
home: FirstScreen(),
);
}
}
class FirstScreen extends StatefulWidget {
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
int sum = 5;
String userAnswer;
String correction = "";
var _controller = new TextEditingController();
int _counter = 0;
List<Color> colors = [Colors.blue, Colors.blue, Colors.blue];
submitPressed(int index) {
if (userAnswer == sum.toString()) {
setState(() {
correction = sum.toString();
colors[index] = Colors.green;
});
} else {
setState(() {
correction = sum.toString();
colors[index] = Colors.red;
});
}
}
Widget myTextField() {
return Container(
width: 50.0,
child: TextField(
controller: _controller,
textAlign: TextAlign.center,
autofocus: true,
keyboardType: TextInputType.number,
onChanged: (val) {
userAnswer = val;
},
),
);
}
Widget myListBuilder() {
return Container(
height: 50.0,
width: 300.0,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: buildContainer,
),
),
);
}
Widget buildContainer(BuildContext context, int index) {
return Container(
child: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Container(
height: 20.0,
width: 15.0,
decoration: BoxDecoration(
color: colors[index], //this is the important line
borderRadius: BorderRadius.all(Radius.circular(8.0))),
),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Listing 4'),
),
body: Container(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10.0),
child: Text('Correct answer is 5',
style: TextStyle(fontSize: 20.0)),
),
myTextField(),
RaisedButton(
child: Text('Submit'),
onPressed: () {
setState(() {
submitPressed(_counter);
});
},
),
myListBuilder(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
buildContainer(context, 0),
buildContainer(context, 1),
buildContainer(context, 2)
],
),
RaisedButton(
child: Text('Next'),
onPressed: () {
setState(() {
_counter++;
});
_controller.clear();
myTextField();
},
),
Text('This should be container no: ${_counter +1}'),
],
),
),
),
);
}
}
I changed the _counter to act like an index and use it as the parameter of the method submitPressed.
I also put the increment in a setState, or you saw the new number only after hitting the Submit button.