I am having a tough time shortening the code below to a function. I am looking to duplicate the elevated button below to hundreds of buttons in my screen hence believe function is the best way to do so, then I can just call the function in my page.
ElevatedButton(
style:
TextButton.styleFrom(backgroundColor: Colors.grey.shade200),
child: Align(
alignment: Alignment.centerLeft,
child: RichText(
textAlign: TextAlign.justify,
text: TextSpan(
children: <TextSpan>[
TextSpan(
text: "Diploma in Business | ",
style: TextStyle(color: Colors.black),
),
TextSpan(
text: "Taylor\u0027s",
style: TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
),
],
),
),
),
onPressed: () {
sendAnalyticsEvent(
eventName: "diplomainbusiness_taylors",
clickevent: "User clicked dipt");
showModalBottomSheet(
isScrollControlled: true,
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
)),
builder: (context) => Container(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
'https://i.imgur.com/bcAC3cA.jpg',
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return const CircularProgressIndicator();
},
errorBuilder: (context, error, stackTrace) =>
const Text('Some errors occurred!'),
),
ListTile(
title: Text(
'\nThis programme is specifically designed to equip students with solid business knowledge and skills, with a central focus on instilling a global mindset as well as creative and critical thinking, set in an experimental learning environment. Upon successful completion of the programme, students will be able to seamlessly transition into our degree and have the competitive advantage required to seek global employment opportunities.\n',
textAlign: TextAlign.justify,
),
),
ListTile(
title: Text(
'• April and August Intake \n• 2 years programme\n• Scholarships available',
textAlign: TextAlign.justify,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
width: double.infinity,
child: CupertinoButton.filled(
child: Text("Interested? Get more info!"),
onPressed: () => openBrowserTab(),
),
),
),
],
),
),
);
},
),
Basically, the elevated button will trigger a bottom sheet and inside the bottom sheet, there is an image, a few texts (List tile) and so. Is it possible to make this into a function or nah this is the shortest code possible? Kindly need some guidance on this.
Thank you so much!
Declare it like this
import 'package:flutter/material.dart';
class CustomElevatedButton extends StatelessWidget {
final String name;
final String education;
final String eventName;
final String clickEvent;
final String imageURl;
final String errorMessage;
final String information1;
final String information2;
final String information3;
const CustomElevatedButton(
{Key? key,
required this.name,
required this.education,
required this.eventName,
required this.clickEvent,
required this.imageURl,
required this.errorMessage,
required this.information1,
required this.information2,
required this.information3})
: super(key: key);
#override
Widget build(BuildContext context) {
return ElevatedButton(
style: TextButton.styleFrom(backgroundColor: Colors.grey.shade200),
child: Align(
alignment: Alignment.centerLeft,
child: RichText(
textAlign: TextAlign.justify,
text: TextSpan(
children: <TextSpan>[
TextSpan(
text: education,
style: const TextStyle(color: Colors.black),
),
TextSpan(
text: name,
style:
const TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
],
),
),
),
onPressed: () {
sendAnalyticsEvent(
eventName: eventName,
clickevent: clickEvent);
showModalBottomSheet(
isScrollControlled: true,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(20),
)),
builder: (context) => Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
imageURl,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return const CircularProgressIndicator();
},
errorBuilder: (context, error, stackTrace) =>
Text(errorMessage),
),
ListTile(
title: Text(
information1,
textAlign: TextAlign.justify,
),
),
ListTile(
title: Text(
information2,
textAlign: TextAlign.justify,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
width: double.infinity,
child: CupertinoButton.filled(
child: Text(information3),
onPressed: () => openBrowserTab(),
),
),
),
],
),
),
);
},
);
}
}
use it like this
const CustomElevatedButton(
clickEvent: 'User clicked dipt',
education: 'Diploma in Business | ',
errorMessage: 'Some errors occurred!',
eventName: 'diplomainbusiness_taylors',
imageURl: 'https://i.imgur.com/bcAC3cA.jpg',
information1: '\nThis programme is specifically designed to equip students with solid business knowledge and skills, with a central focus on instilling a global mindset as well as creative and critical thinking, set in an experimental learning environment. Upon successful completion of the programme, students will be able to seamlessly transition into our degree and have the competitive advantage required to seek global employment opportunities.\n',
information2: '• April and August Intake \n• 2 years programme\n• Scholarships available',
information3: 'Interested? Get more info!',
name: 'Taylor\u0027s',
),
You can extract anything you want including the styles and onpressed callbacks.
If you have any doubts feel free to ask.
Related
I got this error while running the app. I not so advanced in flutter yet. Trying to find solutions. Can u guys help me please?
Error: Could not find the correct Provider above this Consumer Widget
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that Consumer is under your MultiProvider/Provider.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>().toString()),
);
}
consider using builder like so:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context, child) {
// No longer throws
return Text(context.watch<Example>().toString());
}
);
}
My code here below
import 'package:flutter/material.dart';
class CartModel extends ChangeNotifier {
// list of items on sale
final List _shopItems = const [
// [ itemName, itemPrice, imagePath, color ]
["Avocado", "4.00", "lib/images/avocado.png", Colors.green],
["Banana", "2.50", "lib/images/banana.png", Colors.yellow],
["Chicken", "12.80", "lib/images/chicken.png", Colors.brown],
["Water", "1.00", "lib/images/water.png", Colors.blue],
];
// list of cart items
final List _cartItems = [];
get cartItems => _cartItems;
get shopItems => _shopItems;
// add item to cart
void addItemToCart(int index) {
_cartItems.add(_shopItems[index]);
notifyListeners();
}
// remove item from cart
void removeItemFromCart(int index) {
_cartItems.removeAt(index);
notifyListeners();
}
// calculate total price
String calculateTotal() {
double totalPrice = 0;
for (int i = 0; i < cartItems.length; i++) {
totalPrice += double.parse(cartItems[i][1]);
}
return totalPrice.toStringAsFixed(2);
}
}
//another page
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'cart_model.dart';
class CartPage extends StatelessWidget {
const CartPage({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle:true,
title: const Text("My Cart",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
backgroundColor: Colors.green[600],
elevation: 0,
iconTheme: IconThemeData(
color: Colors.grey[800],
),
),
body: Consumer<CartModel>(
builder: (context, value, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Let's order fresh items for you
// list view of cart
Expanded(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: ListView.builder(
itemCount: value.cartItems.length,
padding: const EdgeInsets.all(12),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(12.0),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8)),
child: ListTile(
leading: Image.asset(
value.cartItems[index][2],
height: 36,
),
title: Text(
value.cartItems[index][0],
style: const TextStyle(fontSize: 18),
),
subtitle: Text(
"\$" + value.cartItems[index][1],
style: const TextStyle(fontSize: 12),
),
trailing: IconButton(
icon: const Icon(Icons.cancel),
onPressed: () =>
Provider.of<CartModel>(context, listen: false)
.removeItemFromCart(index),
),
),
),
);
},
),
),
),
// total amount + pay now
Padding(
padding: const EdgeInsets.all(36.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.green,
),
padding: const EdgeInsets.all(24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Total Price',
style: TextStyle(color: Colors.green[200]),
),
const SizedBox(height: 8),
// total price
Text(
'\$${value.calculateTotal()}',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
// pay now
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.green.shade200),
borderRadius: BorderRadius.circular(28),
),
padding: const EdgeInsets.all(12),
child: Row(
children: const [
Text(
'Pay Now',
style: TextStyle(color: Colors.white),
),
Icon(
Icons.arrow_forward_ios,
size: 16,
color: Colors.white,
),
],
),
),
],
),
),
)
],
);
},
),
);
}
}
How can I make individual buttons turn grey when I click on approve?
The screenshot is below
Below is the List Tile widget code
Widget pendingList({
required String title,
required String subtitle,
required String leading,
onTap,
}) {
return Row(
children: [
Expanded(
flex: 6,
child: Card(
child: ListTile(
leading: Container(
padding: const EdgeInsets.only(left: 15.0),
alignment: Alignment.center,
height: 50,
width: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.0),
image: DecorationImage(
image: NetworkImage(
'therul'),
fit: BoxFit.cover,
),
),
),
title: Text(
title,
style: TextStyle(
fontSize: BtnFnt2,
fontWeight: FontWeight.w600,
),
),
subtitle: Text(
subtitle,
style: TextStyle(
fontSize: littleTexts,
),
),
),
),
),
Expanded(
flex: 2,
child: Bounce(
duration: const Duration(milliseconds: 100),
onPressed: onTap,
child: Container(
padding: const EdgeInsets.all(15.0),
color: appOrange,
child: Text(
'Approve',
style: TextStyle(
color: white,
fontWeight: FontWeight.w500,
),
),
),
),
),
],
);
}
How can I make individual buttons turn grey when I click on approve?
Any idea will be appreciated. Kindly refer to the screenshot and assist if you can.
One way, is to make the card into a stateful widget, like (simplified)
class ColorCard extends StatefulWidget {
const ColorCard({
Key? key,
}) : super(key: key);
#override
State<ColorCard> createState() => _ColorCardState();
}
class _ColorCardState extends State<ColorCard> {
Color col = Colors.white;
#override
Widget build(BuildContext context) {
return Card(
color: col,
child: ListTile(
title: const Text('title'),
subtitle: const Text('subtitle'),
trailing: ElevatedButton(
onPressed: () {
setState(() => col = Colors.grey);
},
child: const Text('click'),
),
),
);
}
}
Alternatively the color could be based on a value stored in an object that extends or 'mixin'-s ChangeNotifier if you want more comprehensive integration.
The application has the function of adding news to favorites. But when I go to the Favorites page, I get the error "Late Initialization Error: Field "article" has not been initialized.
The problem is in the button "Details", in the line:
MaterialPageRoute(builder: (context) => ArticlePage(article: article,))
Please help me solve the problem. Below is the code for this page:
class FavScreen extends StatefulWidget {
const FavScreen({Key? key}) : super(key: key);
#override
State<FavScreen> createState() => _FavScreenState();
}
class _FavScreenState extends State<FavScreen> {
late final Article article;
final _fireStore = FirebaseFirestore.instance.collection('favoriteItems');
#override
void initState() {
article = Article(
author: article.author,
title: article.title,
description: article.description,
url: article.url,
urlToImage: article.urlToImage,
publishedAt: article.publishedAt,
content: article.content,
source: article.source,
);
super.initState();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Favorite News', style: TextStyle(color: Colors.white)),
backgroundColor: Color(0xfff27935),
),
body:
StreamBuilder(
stream: _fireStore.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if(!snapshot.hasData) {
return Text('No featured news');
} else {
return ListView.builder(
itemCount: snapshot.data?.docs.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
child: Container(
margin: EdgeInsets.all(12.0),
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 3.0,
),
]),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 200.0,
width: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(snapshot.data?.docs[index].get('image')), fit: BoxFit.cover),
borderRadius: BorderRadius.circular(12.0),
),
),
SizedBox(
height: 8.0,
),
Container(
child: Row(
textDirection: TextDirection.ltr,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
padding: EdgeInsets.all(6.0),
decoration: BoxDecoration(
color: Color(0xfff27935),
borderRadius: BorderRadius.circular(30.0),
),
child: Text(
snapshot.data?.docs[index].get('name'),
style: TextStyle(
color: Colors.white,
),
),
),
IconButton(
onPressed: () {
_fireStore.doc(snapshot.data?.docs[index].id).delete();
},
icon: const Icon(Icons.bookmark_remove)),
]
)
),
SizedBox(
height: 8.0,
),
Text(
snapshot.data?.docs[index].get('title'),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
SizedBox(
height: 10.0,
),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ArticlePage(
article: article,
)));
},
child: new Text("DETAILS", style: TextStyle(
fontSize: 12.0,
),
),
)
],
),
),
);
}
);
}
},
)
);
}
}
article = Article(
author: article.author,
title: article.title,
description: article.description,
url: article.url,
urlToImage: article.urlToImage,
publishedAt: article.publishedAt,
content: article.content,
source: article.source,
);
You're trying to initialize article by creating a new Article with values from article. article is uninitialized however, so it fails to read these values and spits out an error.
I'm not quite sure what you want to achieve, but I guess you want to pass in an Article into the widget and initialize the article variable in your state class with that?
I am trying to create a Custom dialog when the text is clicked. but dialog is not creating.
below adding the Dialog box implementation code
child: new Center(
child: new RichText(
text: new TextSpan(
children: [
new TextSpan(
text: 'Accept the ',
style: new TextStyle(color: Colors.black),
),
new TextSpan(
text: 'Terms & Conditions',
style: new TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold),
recognizer: new TapGestureRecognizer()
..onTap = () {
CustomDialogBox(
title: "Custom Dialog Demo",
descriptions: "Hii all this is a custom dialog in flutter and you will be use in your flutter applications",
text: "Yes",
);
},
),
],
),
),
),
adding Custom Dialog Code. creating as new widget in new dart page and importing in the application.
we need it as a widget which we can use many times in the app.
so creating in a new dart page.
class CustomDialogBox extends StatefulWidget {
final String title, descriptions, text;
final Image img;
const CustomDialogBox({Key key, this.title, this.descriptions, this.text, this.img}) : super(key: key);
#override
_CustomDialogBoxState createState() => _CustomDialogBoxState();
}
class _CustomDialogBoxState extends State<CustomDialogBox> {
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(Constants.padding),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: contentBox(context),
);
}
contentBox(context){
return Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: Constants.padding,top: Constants.avatarRadius
+ Constants.padding, right: Constants.padding,bottom: Constants.padding
),
margin: EdgeInsets.only(top: Constants.avatarRadius),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.circular(Constants.padding),
boxShadow: [
BoxShadow(color: Colors.black,offset: Offset(0,10),
blurRadius: 10
),
]
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(widget.title,style: TextStyle(fontSize: 22,fontWeight: FontWeight.w600),),
SizedBox(height: 15,),
Text(widget.descriptions,style: TextStyle(fontSize: 14),textAlign: TextAlign.center,),
SizedBox(height: 22,),
Align(
alignment: Alignment.bottomRight,
child: FlatButton(
onPressed: (){
Navigator.of(context).pop();
},
child: Text(widget.text,style: TextStyle(fontSize: 18),)),
),
],
),
),
],
);
}
}
Nothing wrong with CustomDialogBox ... your onTap method is incorrect in the question posted.
You should do
showDialog(
context: context,
builder: (BuildContext context) => CustomDialogBox(),
)
You need wrap 'CustomDialogBox' with 'showDialog()' widget.
child: new Center(
child: new RichText(
text: new TextSpan(
children: [
new TextSpan(
text: 'Accept the ',
style: new TextStyle(color: Colors.black),
),
new TextSpan(
text: 'Terms & Conditions',
style: new TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold),
recognizer: new TapGestureRecognizer()
..onTap = () {
showDialog(
context: context,
builder: (BuildContext context) {
return CustomDialogBox(
title: "Custom Dialog Demo",
descriptions: "Hii all this is a custom dialog in flutter and you will be use in your flutter applications",
text: "Yes",
);
}
);
},
),
],
),
),
),
I'm new to flutter. When I adding new item or removing an item from the list, the list builder does update the list, but the problem is that the list builder also displaying the previous item list and showing new updated item list. So what I want to do is keeping the new updated item list instead of old item list.
class AlarmPage extends StatefulWidget {
final String title;
AlarmPage({Key key, this.title}) : super(key: key);
#override
_AlarmPageState createState() => _AlarmPageState();
}
class _AlarmPageState extends State<AlarmPage> {
String alarmName;
// Test Function
void _addAlarm() {
setState(() {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AddAlarm()));
});
}
#override
void initState() {
super.initState();
Provider.of<AlarmsProvider>(context, listen: false).getLocalStorage();
}
#override
Widget build(BuildContext context) {
List<Widget> allWidgetsAlarms = List<Widget>();
return Consumer<AlarmsProvider>(builder: (context, alarmProviderItem, _) {
List<String> localAlarms = alarmProviderItem.alarms;
if (localAlarms != null) {
localAlarms.forEach((item) {
allWidgetsAlarms.add(
Stack(
children: <Widget>[
InkWell(
child: Container(
color: Color(0xff212121),
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
// Alarm Name & Title
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 2),
)),
child: Row(
children: <Widget>[
Icon(Icons.alarm, color: Colors.yellow),
SizedBox(width: 20.0),
Text('$item',
style: TextStyle(
color: Color(0xffC1C1C1),
fontSize: 15.0,
fontWeight: FontWeight.w900)),
SizedBox(height: 5),
],
),
),
SizedBox(height: 10),
// Alarm Time & Toggle Switch
Container(
child: Row(
children: <Widget>[
Text(
'Time',
style: TextStyle(
fontSize: 30, color: Colors.white),
),
SizedBox(width: 20),
Text(
'AM / PM',
style: TextStyle(
fontSize: 20, color: Color(0xffB5B5B5)),
),
SizedBox(width: 150),
Icon(Icons.switch_camera, color: Colors.yellow),
],
),
),
// Alarm Repeat
Container(
child: Row(children: <Widget>[
Text(
'Repeat',
style: TextStyle(
fontSize: 11, color: Color(0xff616161)),
),
Container(
child: DaySelector(
value: null,
onChange: (value) {},
color: Colors.yellow[400],
mode: DaySelector.modeFull,
),
),
]),
),
],
),
),
onLongPress: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddAlarm(item: item)));
},
),
SizedBox(height: 180),
],
),
);
print(item);
});
}
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text('Azy Alarm'),
centerTitle: true,
),
body: Container(
decoration: BoxDecoration(
image: const DecorationImage(
fit: BoxFit.cover,
image: AssetImage('assets/images/background_image(dark).png')),
),
// child: ListView(children: allWidgetsAlarms),
child: ListView.builder(
itemCount: allWidgetsAlarms.length,
padding: const EdgeInsets.all(8.0),
itemBuilder: (BuildContext context, int index) {
return allWidgetsAlarms[index];
}),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: Colors.blue,
elevation: 0,
onPressed: _addAlarm,
),
);
});
}
}
So I think your issue is this line: allWidgetsAlarms.add( You construct allWidgetsAlarms in your builder, but the builder is not called again every time you Consumer rebuilds, hence it is just appending the new contents to the end of the list. To fix this, keep your original initialization of allWidgetsAlarms just at the top of the builder in your Consumer, add the following line:
allWidgetsAlarms = List<Widget>();
This will resert allWidgetsAlarms. Hope it helps!