I need to make an animation, but I don't know how to do it. When the user clicks on one of the avatars, the avatar will have a blue outline and the camera icon will appear on the selected avatar, the text accompanies the blue color when the avatar is selected. Can you help me please :___.
This is the code:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SettingUser(),
);
}
}
class SettingUser extends StatefulWidget {
const SettingUser({Key? key}) : super(key: key);
#override
State<SettingUser> createState() => _SettingUserState();
}
class _SettingUserState extends State<SettingUser> {
bool saved = false;
ImagePicker imagePicker = ImagePicker();
XFile? imageSelect;
Future<bool?> showConfirmationDialog() {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
'Exit App',
style: TextStyle(fontWeight: FontWeight.bold),
),
content: const Text(
'Exit app'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('CANCELAR'),
),
TextButton(
onPressed: () {},
child: const Text(
'EXIT',
style: TextStyle(color: Colors.red),
)),
],
);
});
}
imageGallery() async {
final XFile? imageTemp = await imagePicker.pickImage(
source: ImageSource.gallery,
);
setState(() {
imageSelect = imageTemp;
});
}
Widget _buildUserAvatar({
required ImageProvider image,
required String name,
}) {
return GestureDetector(
onTap: () {
imageGallery();
},
child: Padding(
padding: const EdgeInsets.only(left: 16, top: 10.0, right: 0.0, bottom: 5.0),
child: Column(
children: [
SizedBox(
child: CircleAvatar(
backgroundColor: Color(0xFFF3E0A6),
radius: 30.0,
backgroundImage: image, // if image is a Image
child: Align(
alignment: Alignment.bottomRight,
child: CircleAvatar(
backgroundColor: Colors.blue,
radius: 12.0,
child: Icon(
Icons.camera_alt,
size: 12.0,
color: Colors.white,
),
),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
name,
style: TextStyle(fontSize: 14),
),
),
],
),
),
);
}
Widget _renderUserAvatar() {
if (imageSelect != null) {
return _buildUserAvatar(
name: 'Avatar 1',
image: FileImage(File(imageSelect!.path)),
);
}
return _buildUserAvatar(
name: 'Avatar 1',
image: AssetImage('assets/images/euQ.png'),
);
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (!saved) {
final confirmation = await showConfirmationDialog();
return confirmation ?? false;
}
return true;
},
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
iconTheme: IconThemeData(color: Colors.blue),
actions: [
IconButton(
icon: Icon(Icons.help_outline,
),
onPressed: () {},
),
],
),
body: ListView(
children: [
Padding(
padding: EdgeInsets.only(left: 16, top: 5.0),
child: Text(
'Select Avatar:',
style: TextStyle(
color: Color(0xff8194A9),
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_renderUserAvatar(),
_buildUserAvatar(
name: 'Avatar 2',
image: AssetImage('assets/images/'),
),
_buildUserAvatar(
name: 'Avatar 3',
image: AssetImage('assets/images/'),
),
],
),
// ButtonConfig(),
Padding(
padding: const EdgeInsets.only(left: 15.0, top: 10.0, right: 180.0),
child: ElevatedButton(
onPressed: () {
showConfirmationDialog();
},
child: Text(
'Exit App',
style: TextStyle(color: Colors.blue),
),
style: ElevatedButton.styleFrom(
//elevation: 1,
primary: Colors.white,
padding:
EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
textStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
side: BorderSide(
width: 1.0,
color: Colors.grey,
),
),
),
),
],
),
),
);
}
}
I managed to make it work only on the first avatar.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SettingUser(),
);
}
}
class SettingUser extends StatefulWidget {
const SettingUser({Key? key}) : super(key: key);
#override
State<SettingUser> createState() => _SettingUserState();
}
class _SettingUserState extends State<SettingUser> {
bool saved = false;
ImagePicker imagePicker = ImagePicker();
XFile? imageSelect;
Future<bool?> showConfirmationDialog() {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
'Exit App',
style: TextStyle(fontWeight: FontWeight.bold),
),
content: const Text(
'Exit app'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('CANCELAR'),
),
TextButton(
onPressed: () {},
child: const Text(
'EXIT',
style: TextStyle(color: Colors.red),
)),
],
);
});
}
imageGallery() async {
final XFile? imageTemp = await imagePicker.pickImage(
source: ImageSource.gallery,
);
setState(() {
imageSelect = imageTemp;
});
}
Widget _buildUserAvatar(bool hasFocus, {
required ImageProvider image,
required String name,
}) {
return GestureDetector(
onTap: () {
imageGallery();
},
child: Padding(
padding: const EdgeInsets.only(left: 16, top: 10.0, right: 0.0, bottom: 5.0),
child: Column(
children: [
SizedBox(
child: AnimatedContainer(
duration: const Duration(milliseconds: 1000),
width: hasFocus ? 120 : 100,
height: hasFocus ? 120 : 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
width: hasFocus ? 4 : 3,
color: hasFocus ? Colors.black : Colors.blue,
),
),
child: CircleAvatar(
backgroundColor: Color(0xFFF3E0A6),
radius: 30.0,
backgroundImage: image, // if image is a Image
child: Align(
alignment: Alignment.bottomRight,
child: CircleAvatar(
backgroundColor: Colors.blue,
radius: 12.0,
child: Icon(
Icons.camera_alt,
size: 12.0,
color: Colors.white,
),
),
),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
name,
style: const TextStyle(fontSize: 14),
),
),
],
),
),
);
}
Widget _renderUserAvatar(bool hasFocus) {
if (imageSelect != null) {
return _buildUserAvatar(
true,
name: "Avatar 1",
image: FileImage(File(imageSelect!.path)),
);
}
return _buildUserAvatar(
false,
name: 'Avatar 1',
image: AssetImage('assets/images/euQ.png'),
);
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (!saved) {
final confirmation = await showConfirmationDialog();
return confirmation ?? false;
}
return true;
},
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
iconTheme: const IconThemeData(color: Colors.blue),
actions: [
IconButton(
icon: const Icon(Icons.help_outline,
),
onPressed: () {},
),
],
),
body: ListView(
children: [
const Padding(
padding: EdgeInsets.only(left: 16, top: 5.0),
child: Text(
'Select Avatar:',
style: TextStyle(
color: Color(0xff8194A9),
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_renderUserAvatar(true),
_buildUserAvatar(
false,
name: 'Avatar 2',
image: AssetImage('assets/images/euQ.png'),
),
_buildUserAvatar(
false,
name: 'Avatar 3',
image: AssetImage('assets/images/euQ.png'),
),
],
),
// ButtonConfig(),
Padding(
padding: const EdgeInsets.only(left: 15.0, top: 10.0, right: 180.0),
child: ElevatedButton(
onPressed: () {
showConfirmationDialog();
},
child: const Text(
'Exit App',
style: TextStyle(color: Colors.blue),
),
style: ElevatedButton.styleFrom(
//elevation: 1,
primary: Colors.white,
padding:
const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
textStyle: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
side: const BorderSide(
width: 1.0,
color: Colors.grey,
),
),
),
),
],
),
),
);
}
}
Related
I created 2 pages, in first one i have TextField to pass data to second one.
In second file i created class and Text class to output the phone number, but compiler says it's undefined. Both Class and Text() are in same dart file.
Class with constructor:
class ProfilePage extends StatefulWidget {
final String phonenum;
const ProfilePage({Key? key, required this.phonenum}) : super(key: key);
#override
_ProfilePageState createState() => _ProfilePageState();
}
Text Class that must output name
Text(phonenum),
Function in first file to pass the phone number
void _submit() {
Route route = MaterialPageRoute(builder: (context) => ProfilePage(phonenum: _phonenumber,)); // (constructors name: class member)
Navigator.push(context, route);
}
Page 1 code:
import 'package:flutter/material.dart';
import 'package:untitled/pages/ProfilePage.dart';
import 'package:untitled/pages/StadiumPage.dart';
void main() {
runApp(LogInPage());
}
class LogInPage extends StatefulWidget {
const LogInPage({Key? key}) : super(key: key);
#override
_LogInPageState createState() => _LogInPageState();
}
class _LogInPageState extends State<LogInPage> {
String _phonenumber = '';
#override
Widget build(BuildContext context) {
double _wid = MediaQuery.of(context).size.width;
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 180,
),
Container(
margin: EdgeInsets.only(left: 40),
width: _wid,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'stadion.kg',
style: TextStyle(
fontSize: 35,
color: Colors.redAccent,
fontWeight: FontWeight.bold),
),
SizedBox(height: 20),
Text(
'Добро пожаловать!',
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
SizedBox(height: 50),
Text(
'Номер телефона:',
style: TextStyle(fontSize: 15, color: Colors.redAccent),
),
],
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: TextField(
keyboardType: TextInputType.phone,
onChanged: (value) {
_phonenumber = value;
},
maxLength: 9,
decoration: InputDecoration(
prefixIcon: Icon(Icons.phone), prefixText: '+996'))),
SizedBox(height: 45),
ElevatedButton(
onPressed: _submit,
child: Text('Войти'),
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(horizontal: 140, vertical: 15),
primary: Colors.redAccent),
),
SizedBox(height: 10),
TextButton(
onPressed: _submitnoregist,
child: Text(
'Продолжить без регистрации!',
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w400),
))
],
),
),
);
}
void _submitnoregist() {
Route route = MaterialPageRoute(builder: (context) => HomePage()); // (constructors name: class member)
Navigator.push(context, route);
}
void _submit() {
Route route = MaterialPageRoute(builder: (context) => ProfilePage(phonenum: _phonenumber,)); // (constructors name: class member)
Navigator.push(context, route);
}
}
Page 2 Code:
import 'package:flutter/material.dart';
import 'package:untitled/pages/FavoritesPage.dart';
import 'package:untitled/pages/MapPage.dart';
import 'package:untitled/pages/StadiumPage.dart';
class ProfilePage extends StatefulWidget {
final String phonenum;
const ProfilePage({Key? key, required this.phonenum}) : super(key: key);
#override
_ProfilePageState createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
int _selind = 0;
List<Widget> _widgetopt = <Widget>[
Text('Index 4'),
Text('Index 2'),
Text('Index 3'),
Text('Index 4'),
];
void OnBeingTapped(int index) {
setState(() {
_selind = index;
if (index == 0) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => HomePage()));
} else if (index == 1) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => MapPage()));
} else if (index == 2) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => FavoritesPage()));
}
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.indigo[50],
appBar: AppBar(
title: Text('Профиль', style: TextStyle(color: Colors.black)),
backgroundColor: Colors.white,
toolbarHeight: 80,
centerTitle: true,
),
body: Column(
children: [
SizedBox(
height: 20,
),
Center(
child: Column(
children: [
CircleAvatar(
backgroundImage: AssetImage('lib/assets/ava.jpg'),
maxRadius: 60,
),
SizedBox(
height: 20,
),
Text(
'Неизвестный\nпользователь',
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 25),
),
SizedBox(
height: 10,
),
Text(phonenum,
style: TextStyle(color: Colors.redAccent, fontSize: 20)),
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 1.5,
offset: Offset(
1.5, // horizontal, move right 10
1.5, // vertical, move down 10
),
)
],
color: Colors.white,
border: Border.all(color: Colors.white70),
borderRadius: BorderRadius.all(Radius.circular(20))),
child: ButtonBar(
alignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 30,
),
TextButton(
onPressed: () {},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('Пользовательское соглашение',
style: TextStyle(
color: Colors.black, fontSize: 20)),
Icon(
Icons.arrow_forward_ios_rounded,
color: Colors.black,
)
]),
),
TextButton(
onPressed: () {},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Пригласить друзей',
style: TextStyle(
color: Colors.black, fontSize: 20)),
Icon(
Icons.arrow_forward_ios_rounded,
color: Colors.black,
)
],
),
),
TextButton(
onPressed: () {},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Выйти',
style: TextStyle(
color: Colors.black, fontSize: 20)),
Icon(
Icons.arrow_forward_ios_rounded,
color: Colors.black,
)
],
),
),
SizedBox(
height: 30,
),
],
),
),
)
],
),
)
],
),
bottomNavigationBar: SizedBox(
height: 80,
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.white,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(
Icons.add_box_outlined,
color: Colors.black,
),
label: ''),
BottomNavigationBarItem(
icon: Icon(
Icons.location_on_outlined,
color: Colors.black,
),
label: ''),
BottomNavigationBarItem(
icon: Icon(
Icons.favorite_outline,
color: Colors.black,
),
label: ''),
BottomNavigationBarItem(
icon: Icon(
Icons.person_outline_outlined,
color: Colors.black,
),
label: ''),
],
currentIndex: _selind,
selectedItemColor: Colors.yellow,
onTap: OnBeingTapped,
),
),
),
title: 'Stadium',
);
}
}
phonenum is a class variable of ProfilePage and _ProfilePageState cannot access it directly. Because _ProfilePageState is a State class of ProfilePage you have a property called widget that you can use to access variables of ProfilePage class.
So your code should be like that:
Text(
widget.phonenum,
...
...
)
Hi there a Flutter newbie here.
I have a project to be submitted via flutter. This is my main code and it's not updating text to stop when button was clicked.
import 'package:assets_audio_player/assets_audio_player.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'firebase_options.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FM Mahanama',
theme: ThemeData(
primaryColor: const Color(0xfffbc02d),
primarySwatch: Colors.amber,
useMaterial3: true,
),
darkTheme: ThemeData(
primaryColor: const Color(0xfffbc02d),
primarySwatch: Colors.amber,
brightness: Brightness.dark,
useMaterial3: true,
),
themeMode: ThemeMode.system,
debugShowCheckedModeBanner: false,
home: const MyHomePage(title: 'FM Mahanama'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedAppIndex = 0;
IconData iconPlayStop = Icons.play_arrow_rounded;
String txtPlayStop = "Play";
static final assetsAudioPlayer = AssetsAudioPlayer();
#override
void initState() {
WidgetsFlutterBinding.ensureInitialized();
initFirebaseActivities();
}
void initFirebaseActivities() {
Firebase.initializeApp();
}
static Future<void> initRadioPlayer(param0) async {
try {
await assetsAudioPlayer.open(
Audio.liveStream(param0),
showNotification: true,
autoStart: true,
);
} catch (t) {
AlertDialog(title: const Text("Error"), content: Text(t.toString()),);
}
}
void updateButtonText(String txt, IconData iconData){
setState(() {
txtPlayStop = txt;
iconPlayStop = iconData;
});
}
#override
void dispose() {
if(assetsAudioPlayer.isPlaying.value){
assetsAudioPlayer.stop();
}
}
static void _openFacebookPage() async {
String fbProtocolUrl = "fb://page/865683116816630";
String fallbackUrl = "https://www.facebook.com/mcrcofficial/";
try {
bool launched = await launchUrlString(fbProtocolUrl);
if (!launched) {
await launchUrlString(fallbackUrl);
}
} catch (e) {
await launchUrlString(fallbackUrl);
}
}
late final Set<Widget> _appPages = <Widget>{
Center(
child: StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection("public")
.doc("stream")
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>> data) {
if (data.hasData) {
if (!data.data?.get("onair")) {
if (assetsAudioPlayer.isPlaying.value) {
assetsAudioPlayer.stop();
}
}
return Visibility(
replacement: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 20.0),
child: Image.asset(
"assets/images/app_logo.png",
width: 200.0,
fit: BoxFit.cover,
),
),
const Text(
"FM Mahanama is currently offline!",
style: TextStyle(fontSize: 18.0),
),
const Padding(
padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 20.0),
child: Text(
"Checkout our Facebook for page more information"),
),
Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 20.0),
child: TextButton.icon(
onPressed: () {
_openFacebookPage();
},
icon: const Icon(Icons.link_rounded),
label: const Text("Facebook Page"),
),
),
],
),
),
visible: data.data?.get("onair"),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 30.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0)),
elevation: 10.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: Image.network(
data.data?.get("cover_img"),
width: 300.0,
height: 300.0,
fit: BoxFit.fitHeight,
),
),
),
),
const Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 5.0),
child: Text(
"Now Playing",
style: TextStyle(fontSize: 22.0),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 20.0),
child: Text(
data.data!.get("nowplaying").toString(),
style: const TextStyle(
fontSize: 24.0, fontWeight: FontWeight.w600),
),
),
const Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 5.0),
child: Text(
"By",
style: TextStyle(fontSize: 18.0),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 30.0),
child: Text(
data.data!.get("by").toString(),
style: const TextStyle(
fontSize: 22.0, fontWeight: FontWeight.w600),
),
),
ElevatedButton.icon(
onPressed: () {
if(!assetsAudioPlayer.isPlaying.value) {
initRadioPlayer(data.data?.get("link"));
updateButtonText("Stop", Icons.stop_rounded);
}else{
assetsAudioPlayer.stop();
updateButtonText("Play", Icons.play_arrow_rounded);
}
},
label: Text(getButtonString(), style: const TextStyle(fontSize: 24.0),),
icon: Icon(iconPlayStop, size: 24.0,),
),
],
),
),
);
} else {
return const Text("There is a error loading data!");
}
},
),
),
const Center(
child: Text("Scoreboard"),
),
const Center(
child: Text("About"),
),
};
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(
child: Text(widget.title),
),
),
body: Center(
child: _appPages.elementAt(_selectedAppIndex),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.transparent,
elevation: 0,
currentIndex: _selectedAppIndex,
selectedFontSize: 14,
unselectedFontSize: 14,
showUnselectedLabels: false,
onTap: (value) {
setState(() {
_selectedAppIndex = value;
});
},
items: const [
BottomNavigationBarItem(
label: "Player",
icon: Icon(Icons.music_note_rounded),
),
BottomNavigationBarItem(
label: "Scoreboard",
icon: Icon(Icons.scoreboard_rounded),
),
BottomNavigationBarItem(
label: "About",
icon: Icon(Icons.info_rounded),
),
],
),
);
}
static String getButtonString() {
if(assetsAudioPlayer.isPlaying.value){
return "Stop";
}else{
return "Play";
}
}
}
What I want is to update the button text and icon stop text and icon to when the button is pressed and the player is playing and vice versa.
I am using the latest build of flutter with material design widgets. I am building for android and ios.
you need to tell your code when did you change the state by doing setState()
ElevatedButton.icon(
onPressed: () {
setState(() {// add this whenever you want to change the values and update your screen
if(!assetsAudioPlayer.isPlaying.value) {
initRadioPlayer(data.data?.get("link"));
updateButtonText("Stop", Icons.stop_rounded);
}else{
assetsAudioPlayer.stop();
updateButtonText("Play", Icons.play_arrow_rounded);
}
});
},
label: Text(getButtonString(), style: const
TextStyle(fontSize: 24.0),),
icon: Icon(iconPlayStop, size: 24.0,),
),
You can use like that:
ElevatedButton.icon(
onPressed: () async {
await getButtonString();
setState(() {
});
},
label: Text(getButtonString(), style: const
TextStyle(fontSize: 24.0),),
icon: Icon(iconPlayStop, size: 24.0,),
),
For more information https://dart.dev/codelabs/async-await
I found a solution for this. It seems that setState isn't working for my app. So I implemented ValueNotifier and ValueListenableBuilder to update the values.
First I initialised the variables
ValueNotifier<IconData> iconPlayStop = ValueNotifier(Icons.play_arrow_rounded);
ValueNotifier<String> txtPlayStop = ValueNotifier("Play");
Then in button on click I updated the code to change the values on both value notifiers.
onPressed: () {
if(!assetsAudioPlayer.isPlaying.value) {
initRadioPlayer(data.data?.get("link"));
txtPlayStop.value = "Stop";
iconPlayStop.value = Icons.stop_rounded;
iconPlayStop.notifyListeners();
}else{
assetsAudioPlayer.stop();
txtPlayStop.value = "Play";
iconPlayStop.value = Icons.play_arrow_rounded;
}
},
Then on both label and icon I added ValueListenableBuilders
label: ValueListenableBuilder(
valueListenable: txtPlayStop,
builder: (BuildContext context, String value, Widget? child) => Text(value, style: const TextStyle(fontSize: 24.0),),
),
icon: ValueListenableBuilder(
valueListenable: iconPlayStop,
builder: (BuildContext context, IconData value, Widget? child) => Icon(value, size: 24.0,),
),
enter image description hereAs per image I want popup in app-bar in flutter
Try the below code and you will store the SVG image in image directory
actions[
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 5),
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(width: 2, color: Colors.blue)),
child: SvgPicture.asset(
"images/ic_more.svg",
height: 30,
color: Colors.white,
),
),
onTapDown: (details) {
_showPopUpMenu(details.globalPosition);
})
)
]
popUpMenu:
_showPopUpMenu(Offset offset) async {
final screenSize = MediaQuery.of(context).size;
double left = offset.dx;
double top = offset.dy;
double right = screenSize.width - offset.dx;
double bottom = screenSize.height - offset.dy;
await showMenu<MenuItemType>(
context: context,
position: RelativeRect.fromLTRB(left, top, right, bottom),
items: MenuItemType.values
.map((MenuItemType menuItemType) =>
PopupMenuItem<MenuItemType>(
value: menuItemType,
child: Text(getMenuItemString(menuItemType)),
))
.toList(),
).then((MenuItemType item) {
if (item == MenuItemType.EDIT) {
// here set your route
}
});
}
And your enum data for popup menu
import 'package:flutter/foundation.dart';
enum MenuItemType {
EDIT,
DUPLICATE
}
getMenuItemString(MenuItemType menuItemType) {
switch (menuItemType) {
case MenuItemType.EDIT:
return "Edit";
case MenuItemType.DUPLICATE:
return "Duplicate";
}
}
Please refer to below code
Using custom_pop_up_menu: ^1.2.2
https://pub.dev/packages/custom_pop_up_menu
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<ChatModel> messages;
List<ItemModel> menuItems;
CustomPopupMenuController _controller = CustomPopupMenuController();
#override
void initState() {
menuItems = [
ItemModel('Chat', Icons.chat_bubble),
ItemModel('Add', Icons.group_add),
ItemModel('View', Icons.settings_overscan),
];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('CustomPopupMenu'),
actions: <Widget>[
CustomPopupMenu(
child: Container(
child: Icon(
Icons.more_horiz,
color: Colors.white,
size: 24.0,
),
padding: EdgeInsets.symmetric(
horizontal: 30.0,
vertical: 20.0,
),
),
menuBuilder: () => ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Container(
color: Colors.white,
child: IntrinsicWidth(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: menuItems
.map(
(item) => GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: _controller.hideMenu,
child: Container(
height: 40,
padding: EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: <Widget>[
Icon(
item.icon,
size: 15,
color: Colors.black,
),
Expanded(
child: Container(
margin: EdgeInsets.only(left: 10),
padding:
EdgeInsets.symmetric(vertical: 10),
child: Text(
item.title,
style: TextStyle(
color: Colors.black,
fontSize: 12,
),
),
),
),
],
),
),
),
)
.toList(),
),
),
),
),
pressType: PressType.singleClick,
verticalMargin: -10,
controller: _controller,
barrierColor: Colors.black54,
horizontalMargin: 0.0,
arrowColor: Colors.white,
showArrow: true,
),
],
),
body: Container(
child: Center(
child: Text(
"Pop up menu",
),
),
),
);
}
}
Solution Using PopupmenuButton
Widget popMenus({
List<Map<String, dynamic>> options,
BuildContext context,
}) {
return PopupMenuButton(
iconSize: 24.0,
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
icon: Icon(
Icons.more_horiz_rounded,
color: Colors.black,
size: 24.0,
),
offset: Offset(0, 10),
itemBuilder: (BuildContext bc) {
return options
.map(
(selectedOption) => PopupMenuItem(
height: 12.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
selectedOption['menu'] ?? "",
style: TextStyle(
fontSize: ScreenUtil().setSp(14.0),
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
color: Colors.blue,
),
),
(options.length == (options.indexOf(selectedOption) + 1))
? SizedBox(
width: 0.0,
height: 0.0,
)
: Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
),
child: Divider(
color: Colors.grey,
height: ScreenUtil().setHeight(1.0),
),
),
],
),
value: selectedOption,
),
)
.toList();
},
onSelected: (value) async {},
);
}
class PopUpmenusScreen extends StatefulWidget {
const PopUpmenusScreen({Key key}) : super(key: key);
#override
_PopUpmenusScreenState createState() => _PopUpmenusScreenState();
}
class _PopUpmenusScreenState extends State<PopUpmenusScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Examples"),
actions: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0,),
child: popMenus(
context: context,
options: [
{
"menu": "option 1" ?? '',
"menu_id": 1,
},
{
"menu": "option 2" ?? "",
"menu_id": 2,
},
{
"menu": "option 3" ?? "",
"menu_id": 3,
},
{
"menu": "option 4" ?? "",
"menu_id": 4,
},
],
),
)
],
),
);
}
}
Solution 2:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Examples"),
actions: [
IconButton(
icon: Icon(
Icons.more_horiz,
color: Colors.black,
size: 20.0,
),
onPressed: () {},
)
],
),
);
}
You can do that easily using DropdownButton2 which is customizable Flutter's core DropdownButton.
It has customButton parameter which will replace the normal Button with Image, Icon or any widget you want. You can customize everything and design what you need by using many options described with the package. Also, you can change the position of the dropdown menu by using the offset parameter.
Here's an example of using DropdownButton2 as a Popup Menu with Icon:
class CustomButtonTest extends StatefulWidget {
const CustomButtonTest({Key? key}) : super(key: key);
#override
State<CustomButtonTest> createState() => _CustomButtonTestState();
}
class _CustomButtonTestState extends State<CustomButtonTest> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton2(
customButton: const Icon(
Icons.list,
size: 46,
color: Colors.red,
),
customItemsIndexes: const [3],
customItemsHeight: 8,
items: [
...MenuItems.firstItems.map(
(item) =>
DropdownMenuItem<MenuItem>(
value: item,
child: MenuItems.buildItem(item),
),
),
const DropdownMenuItem<Divider>(enabled: false, child: Divider()),
...MenuItems.secondItems.map(
(item) =>
DropdownMenuItem<MenuItem>(
value: item,
child: MenuItems.buildItem(item),
),
),
],
onChanged: (value) {
MenuItems.onChanged(context, value as MenuItem);
},
itemHeight: 48,
itemWidth: 160,
itemPadding: const EdgeInsets.only(left: 16, right: 16),
dropdownPadding: const EdgeInsets.symmetric(vertical: 6),
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Colors.redAccent,
),
dropdownElevation: 8,
offset: const Offset(0, 8),
),
),
),
);
}
}
class MenuItem {
final String text;
final IconData icon;
const MenuItem({
required this.text,
required this.icon,
});
}
class MenuItems {
static const List<MenuItem> firstItems = [home, share, settings];
static const List<MenuItem> secondItems = [logout];
static const home = MenuItem(text: 'Home', icon: Icons.home);
static const share = MenuItem(text: 'Share', icon: Icons.share);
static const settings = MenuItem(text: 'Settings', icon: Icons.settings);
static const logout = MenuItem(text: 'Log Out', icon: Icons.logout);
static Widget buildItem(MenuItem item) {
return Row(
children: [
Icon(
item.icon,
color: Colors.white,
size: 22
),
const SizedBox(
width: 10,
),
Text(
item.text,
style: const TextStyle(
color: Colors.white,
),
),
],
);
}
static onChanged(BuildContext context, MenuItem item) {
switch (item) {
case MenuItems.home:
//Do something
break;
case MenuItems.settings:
//Do something
break;
case MenuItems.share:
//Do something
break;
case MenuItems.logout:
//Do something
break;
}
}
}
Please, help. This is my first project using Flutter. I am making an app for pets.
I have Homepage widget that has 4 bottom Navbar (Home, Photos, Medical, Profile). In Profile I have a button "About", which opens a widget about us.
But when I am trying to return to back from About, it returns to "Home" NavBottombar. I am trying to select Profile NavBottomBar.
I think that is related to current index in Homepage, which equals 0 at the beginning. But how can I change from 0 to 2 while routing?
homepage.dart
import 'package:flutter/material.dart';
import 'placeholder_widget.dart';
import 'dashboard.dart';
import 'medical.dart';
import 'profile.dart';
import 'about.dart';
void main() => runApp(MaterialApp(
home: Homepage(),
));
class Homepage extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<Homepage> {
int _currentIndex = 0;
final List<Widget> _children = [
Dashboard(),
PlaceholderWidget(Colors.deepOrange),
PlaceholderWidget(Colors.red),
// Medical(),
Profile()
];
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Furball Tales'),
backgroundColor: Colors.cyanAccent[400],
),
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
currentIndex: _currentIndex,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.perm_media),
title: Text('Photos'),
),
BottomNavigationBarItem(
icon: Icon(Icons.local_hospital),
title: Text('Medical'),
),
BottomNavigationBarItem(
icon: Icon(Icons.perm_identity),
title: Text('Profile'),
),
],
selectedItemColor: Colors.cyanAccent[400],
unselectedItemColor: Colors.grey[600],
),
),
);
}
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
}
about.dart
import 'package:flutter/material.dart';
import 'profile.dart';
import 'homepage.dart';
class About extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('About FurBallTales'),
backgroundColor: Colors.cyanAccent[400],
leading: GestureDetector(
onTap: () {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) {
return Homepage();
}), ModalRoute.withName('/'));
},
child: Icon(
Icons.arrow_back,
)),
),
body: ListView(
padding: const EdgeInsets.all(2),
children: <Widget>[
Container(
decoration:
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: Column(
children: <Widget>[
Container(
height: 30,
margin: EdgeInsets.all(5),
child: Text(
'OUR MISSION',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.tealAccent[400]),
),
),
Container(
height: 25,
margin: EdgeInsets.all(5),
child: Text(
'Strengthening the bond of owners and pets, more than ever',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.black),
),
),
],
),
),
Container(
height: 50,
color: Colors.amber[600],
child: const Center(child: Text('Entry A')),
),
Container(
height: 50,
color: Colors.amber[500],
child: const Center(child: Text('Entry B')),
),
Container(
height: 50,
color: Colors.amber[100],
child: const Center(child: Text('Entry C')),
),
],
),
);
}
}
profile.dart
import 'package:flutter/material.dart';
import 'sign_in.dart';
import 'login_page.dart';
import 'about.dart';
import 'donation.dart';
class Profile extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircleAvatar(
radius: 80,
backgroundImage: NetworkImage(
'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcSxDoD5caxFUy_dn0w6wl01m882CeJHNVOCRg&usqp=CAU'),
),
Text(
'<$name>',
style: TextStyle(
fontFamily: 'SourceSansPro',
fontSize: 25,
),
),
Text(
'<$email>',
style: TextStyle(
fontSize: 20,
fontFamily: 'SourceSansPro',
color: Colors.red[400],
letterSpacing: 2.5,
),
),
SizedBox(
height: 20.0,
width: 200,
child: Divider(
color: Colors.teal[200],
),
),
// this is about page-----------------------------------------
InkWell(
onTap: () {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) {
return About();
}), ModalRoute.withName('/about'));
},
child: Card(
color: Colors.white,
margin:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 25.0),
child: ListTile(
leading: Icon(
Icons.help,
color: Colors.teal[900],
),
title: Text(
'About',
style:
TextStyle(fontFamily: 'BalooBhai', fontSize: 20.0),
),
)),
),
InkWell(
onTap: () {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) {
return Donation();
}), ModalRoute.withName('/about'));
},
child: Card(
color: Colors.white,
margin:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 25.0),
child: ListTile(
leading: Icon(
Icons.monetization_on,
color: Colors.teal[900],
),
title: Text(
'Donation',
style: TextStyle(fontSize: 20.0, fontFamily: 'Neucha'),
),
),
),
),
InkWell(
onTap: () {
signOutGoogle();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) {
return LoginPage();
}), ModalRoute.withName('/'));
},
child: Card(
color: Colors.white,
margin:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 25.0),
child: ListTile(
leading: Icon(
Icons.account_circle,
color: Colors.teal[900],
),
title: Text(
'LOGOUT',
style: TextStyle(fontSize: 20.0, fontFamily: 'Neucha'),
),
),
),
),
],
),
),
),
);
}
}
Instead of using pushAndRemoveUntil in your About page, you can use Navigator.pop(context)( which removes the view from the Navigator stack):
I added a demo using your code as an example:
class About extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('About FurBallTales'),
backgroundColor: Colors.cyanAccent[400],
leading: GestureDetector(
onTap: () {
Navigator.pop(context); // pop the view
},
child: Icon(
Icons.arrow_back,
)),
),
...
);
}
}
NOTE:
With this approach, the state of the BottomNavigationBar is reserved.
Thank you for everyone, who helped me.
The problem has been solved this way:
First, I pushed to new page.
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => About()));
}
Then made pop context.
onTap: () {
Navigator.pop(context);
},
It returned initial position.
Where it says return Homepage(); in about.dart you could change that to return the profile widget.
I'm building a food ordering app in flutter. What I want is, when the user adds items to the cart, I want the cart icon in the bottom navigation bar to obtain a red dot on top to notify the user of the addition of items to the cart.
To achieve this, I have created a global variable called no_of_cart_items and when the user adds an item to the cart, I increment this variable in the setState() function as follows:
setState(() {
GlobalVariables.no_of_cart_items+=1;
// change icon here
});
In this setState() function, I wish to change the icon in the bottom navigation bar. How should I do this?
Thank you.
FULL CODE
This is main.dart
//import lines
void main() => runApp(CanteenApp());
class CanteenApp extends StatefulWidget {
#override
_CanteenAppState createState() => _CanteenAppState();
}
class _CanteenAppState extends State<CanteenApp> {
int _currentindex=0; // index of bottom tab
int admin=GlobalVariables.admin;
BottomNavigationBadge badger = new BottomNavigationBadge(
backgroundColor: Colors.red,
badgeShape: BottomNavigationBadgeShape.circle,
textColor: Colors.white,
position: BottomNavigationBadgePosition.topRight,
textSize: 8);
Widget callpage(int currentIndex) {
switch (currentIndex) {
case 0: return UserProfile();
case 1: return Menu();
case 2: return Cart();
break;
default: return UserProfile();
}
}
#override
Widget build(BuildContext context) {
if(admin==1 && _currentindex==2) {
//if you're the admin and have called the history page
return MaterialApp(
debugShowCheckedModeBanner: false,
home: DefaultTabController(
length: 2,
child: Scaffold(
resizeToAvoidBottomPadding: false,
appBar: PreferredSize(
preferredSize: Size.fromHeight(80.0),
child: AppBar(
bottom: TabBar(
indicatorColor: Colors.white,
indicatorWeight: 5,
tabs: <Widget>[
Tab(
child: Align(
alignment: Alignment.center,
child: Text(
'Order History',
style: TextStyle(
fontSize: 20
),
)
)
),
Tab(
child: Align(
alignment: Alignment.center,
child: Text(
'Deposit / Withdraw\nHistory',
style: TextStyle(
fontSize: 17
),
textAlign: TextAlign.center,
)
)
),
],
),
),
),
body: TabBarView(
children: <Widget>[
AdminOrderHistory(),
DepositWithdrawHistory()
],
),
bottomNavigationBar: BottomNavigationBar(
elevation: 10,
currentIndex: _currentindex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
title: Text('Profile'),
),
BottomNavigationBarItem(
icon: Icon(Icons.restaurant_menu),
title: Text('Menu'),
),
BottomNavigationBarItem(
icon: Icon(Icons.history),
title: Text('History'),
),
],
onTap: (index){
setState(() {
_currentindex=index;
});
}
),
),
),
theme: appTheme,
);
}
else if(admin==1){
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
resizeToAvoidBottomPadding: false,
body: callpage(_currentindex),
bottomNavigationBar: BottomNavigationBar(
elevation: 10,
currentIndex: _currentindex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
title: Text('Profile'),
),
BottomNavigationBarItem(
icon: Icon(Icons.restaurant_menu),
title: Text('Menu'),
),
BottomNavigationBarItem(
icon: Icon(Icons.history),
title: Text('History'),
),
],
onTap: (index){
setState(() {
_currentindex=index;
});
}
),
),
theme: appTheme,
);
}
else if(admin==0){
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
resizeToAvoidBottomPadding: false,
body: callpage(_currentindex),
bottomNavigationBar:BottomNavigationBar(
elevation: 10,
currentIndex: _currentindex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
title: Text('Profile'),
),
BottomNavigationBarItem(
icon: Icon(Icons.restaurant_menu),
title: Text('Menu'),
),
BottomNavigationBarItem(
title: Text('Cart'),
icon: Badge(
showBadge: true,
badgeContent: Text(
GlobalVariables.no_of_cart_items.toString(),
style: TextStyle(
color: Colors.white
),
),
child: Icon(Icons.shopping_cart)
)
),
],
onTap: (index){
setState(() {
_currentindex=index;
});
}
),
),
theme: appTheme,
);
}
}
}
This is menu.dart
//import lines
int admin=GlobalVariables.admin;
List snacksmenuitems=[
['Vada Pav', 15],
['Samosa Pav', 15],
['Punjabi Samosa', 25],
['Pav', 5]
];
List ricemenuitems=[
['Fried Rice', 62],
['Schezwan Rice', 69],
['Singapore Rice', 69],
['Manchow Rice', 73],
];
class Menu extends StatefulWidget {
#override
_MenuState createState() => _MenuState();
}
class _MenuState extends State<Menu> {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
MenuTopPart(),
MenuBottomPart(),
],
);
}
}
Color firstColor = Color(0xFFF47D15);
Color secondColor = Color(0xFFEF772C);
class MenuTopPart extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
ClipPath(
clipper: CustomShapeClipper(),
child: Container(
height:140.0,
width:MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [firstColor, secondColor],
)
),
child: Column(
children: <Widget>[
SizedBox(height: 53.0),
Text(
'MENU',
style: TextStyle(
fontSize: 30.0,
color: Colors.white,
),
textAlign: TextAlign.center,
),
],
)
)
)
],
);
}
}
class MenuBottomPart extends StatefulWidget {
#override
_MenuBottomPartState createState() => _MenuBottomPartState();
}
class _MenuBottomPartState extends State<MenuBottomPart> {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
SizedBox(height: 10),
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 10),
child: Container(
height: MediaQuery
.of(context)
.size
.height * 0.60,
child: ListView(
padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
scrollDirection: Axis.vertical,
children: <Widget>[
Card(
child: Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
child: ExpansionTile(
title: Text('SNACKS'),
children: snacksmenuitems.map((menuitem) {
//print(menuitem);
return MenuItem(menuitem: menuitem);
/*SizedBox(height:10),
MenuItem(),
SizedBox(height:10),
MenuItem(),
SizedBox(height:10),
MenuItem()*/
}).toList()
),
)
),
SizedBox(height: 10),
Card(
child: Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
child: ExpansionTile(
title: Text('RICE ITEMS'),
children: ricemenuitems.map((menuitem) {
//print(menuitem);
return MenuItem(menuitem: menuitem);
/*SizedBox(height:10),
MenuItem(),
SizedBox(height:10),
MenuItem(),
SizedBox(height:10),
MenuItem()*/
}).toList()
),
)
)
]
),
),
)
]
);
}
}
class MenuItem extends StatefulWidget {
List menuitem=[];
MenuItem({Key key, this.menuitem}): super(key: key);
#override
_MenuItemState createState() => _MenuItemState();
}
class _MenuItemState extends State<MenuItem> {
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
border: Border.all(color: Colors.black12),
borderRadius: BorderRadius.all(Radius.circular(10))
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image(
image: NetworkImage('https://www.whiskaffair.com/wp-content/uploads/2018/08/Mumbai-Pav-Bhaji-4.jpg'),
width: 80,
height: 80
),
SizedBox(width:10),
Padding(
padding: const EdgeInsets.fromLTRB(0, 5, 0, 0),
child: Container(
width:190,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
widget.menuitem[0],
style: TextStyle(
fontSize:19,
color: Colors.grey[900]
),
),
SizedBox(height:5.0),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Row(
children: <Widget>[
Row(
children: <Widget>[
Text(
'₹',
style: TextStyle(
fontSize: 15,
color: Colors.grey[800]
),
),
Text(
widget.menuitem[1].toString(),
style: TextStyle(
fontSize: 15,
color: Colors.grey[800]
),
)
],
),
SizedBox(width:70),
Container(
child: Row(
children: <Widget>[
SizedBox(
width:30,
height:30,
child: FloatingActionButton(
onPressed: (){
setState(() {
if(GlobalVariables.allcartitems[widget.menuitem[0]][0]>0){
GlobalVariables.no_of_cart_items-=1;
GlobalVariables.allcartitems[widget.menuitem[0]][0]-=1;
GlobalVariables.totalcost-=GlobalVariables.allcartitems[widget.menuitem[0]][1];
// CHECK IF CART HAS NO ITEMS AND REMOVE BADGE HERE
}
});
},
elevation: 1,
child: Icon(Icons.remove, size: 18),
backgroundColor: Colors.red[300],
mini: true,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5.0))),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
child: Text(
GlobalVariables.allcartitems[widget.menuitem[0]][0].toString(),
style: TextStyle(
fontSize: 18
),
),
),
SizedBox(
width:30,
height:30,
child: FloatingActionButton(
onPressed: (){
setState(() {
GlobalVariables.no_of_cart_items+=1;
GlobalVariables.allcartitems[widget.menuitem[0]][0]+=1;
GlobalVariables.totalcost+=GlobalVariables.allcartitems[widget.menuitem[0]][1];
// SET BADGE HERE
});
},
elevation: 1,
child: Icon(Icons.add, size: 20),
backgroundColor: Colors.green[300],
mini:true,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5.0))),
),
)
],
)
)
],
),
),
],
),
),
)
],
),
);
}
}
This is cart.dart:
import 'dart:convert';
import 'package:canteen_app/pages/globalvar.dart';
import 'package:canteen_app/pages/globalvar.dart' as prefix0;
import 'package:canteen_app/pages/orderReceipt.dart';
import 'package:flutter/material.dart';
import 'package:canteen_app/pages/CustomShapeClipper.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
class Cart extends StatefulWidget {
#override
_CartState createState() => _CartState();
}
class _CartState extends State<Cart> {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
CartTopPart(),
CartBottomPart()
],
);
}
}
class CartTopPart extends StatefulWidget {
#override
_CartTopPartState createState() => _CartTopPartState();
}
Color firstColor = Color(0xFFF47D15);
Color secondColor = Color(0xFFEF772C);
class _CartTopPartState extends State<CartTopPart> {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
ClipPath(
clipper: CustomShapeClipper(),
child: Container(
height:140.0,
width:MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [firstColor, secondColor],
)
),
child: Column(
children: <Widget>[
SizedBox(height: 53.0),
Text(
'CART',
style: TextStyle(
fontSize: 30.0,
color: Colors.white,
),
textAlign: TextAlign.center,
),
],
)
)
)
],
);
}
}
var cartmenuitems = GlobalVariables.allcartitems.keys.toList();
class CartBottomPart extends StatefulWidget {
#override
_CartBottomPartState createState() => _CartBottomPartState();
}
class _CartBottomPartState extends State<CartBottomPart> {
bool _isLoading=false;
createAlertDialog(BuildContext context, String errormessage){
return showDialog(
context: context,
builder: (context){
return AlertDialog(
content: Text(errormessage)
);
}
);
}
#override
Widget build(BuildContext context) {
if(GlobalVariables.no_of_cart_items>0) {
return _isLoading==true ? Center(child: CircularProgressIndicator()) : Padding(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 10),
child: Column(
children: <Widget>[
Container(
height: MediaQuery
.of(context)
.size
.height * 0.40,
child: ListView(
padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
scrollDirection: Axis.vertical,
children: cartmenuitems.map((menuitem) {
//print(cartmenuitems);
// print(GlobalVariables.allcartitems[menuitem]);
//if(GlobalVariables.allcartitems[menuitem]>=1) {
//print('heyy');
return CartOrderDish(menuitem: menuitem);
//}
}).toList()
),
),
Divider(
color: Colors.black
),
Row(
children: <Widget>[
Text(
'Total Amount:',
style: TextStyle(
fontSize: 20
),
),
SizedBox(width: 140),
Row(
children: <Widget>[
Text(
'₹',
style: TextStyle(
fontSize: 20
),
),
Text(
GlobalVariables.totalcost.toString(),
style: TextStyle(
fontSize: 20
)
)
],
)
],
),
SizedBox(height: 5),
Align(
alignment: Alignment.centerLeft,
child: Text(
'(Inclusive of GST)',
style: TextStyle(
fontSize: 15
),
),
),
SizedBox(height: 18),
RaisedButton(
onPressed: () {
if((GlobalVariables.accountbalance-GlobalVariables.totalcost)<0){
createAlertDialog(context, "Whoops! The total cost exceeds your account balance!\n\nYour account balance can be updated at the CASH COUNTER.");
}
else {
setState(() {
_isLoading = true;
});
// creating a list of all cart items to send to php
List cart = [];
cartmenuitems.map((menuitem) {
if (GlobalVariables.allcartitems[menuitem][0] > 0) {
cart.add([menuitem, GlobalVariables.allcartitems[menuitem][0], GlobalVariables.allcartitems[menuitem][1] * GlobalVariables.allcartitems[menuitem][0]]);
}
}).toList();
print(jsonEncode(cart));
Future placeOrderFunction() async {
print(GlobalVariables.username);
final response = await http.post(
"https://kjscecanteenapp.000webhostapp.com/place_order_sys.php",
body: {
"cart": json.encode(cart),
"username": GlobalVariables.username
});
// print(response.body);
var decodedResponse = json.decode(response.body);
print(decodedResponse);
setState(() {
_isLoading = false;
});
if (decodedResponse['error'] != -1) {
// means no error
int orderId=decodedResponse['error'];
int cost=GlobalVariables.totalcost;
GlobalVariables.no_of_cart_items = 0;
String date=DateFormat('dd-MMM-yyyy').format(DateTime.now());
cartmenuitems.map((menuitem) {
if (GlobalVariables.allcartitems[menuitem][0] > 0) {
GlobalVariables.allcartitems[menuitem][0] = 0;
}
});
GlobalVariables ob = new GlobalVariables();
ob.resetcart();
GlobalVariables.accountbalance -= GlobalVariables.totalcost;
GlobalVariables.totalcost = 0;
Navigator.of(context)
.push(MaterialPageRoute<Null>(
builder: (BuildContext context) {
return new OrderReceipt(orderId: orderId, cost: cost, date: date, cart: cart);
}));
}
else{
createAlertDialog(context, "There was some error during the order placement. Don't worry tho try again in a few seconds!");
}
}
placeOrderFunction();
}
},
elevation: 5.0,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0)),
padding: const EdgeInsets.all(0.0),
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
Color(0xFF0083B0),
Color(0xFF00B4DB),
]
)
),
padding: const EdgeInsets.fromLTRB(40, 15, 40, 15),
child: Text(
'Place Order',
style: TextStyle(
fontSize: 20
),
),
)
)
],
),
);
}
else {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
height: MediaQuery.of(context).size.height*0.6,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Please add some items into your cart.',
style: TextStyle(
fontSize: 20,
),
textAlign: TextAlign.center,
),
],
),
),
);
}
}
}
class CartOrderDish extends StatefulWidget {
String menuitem;
CartOrderDish({Key key, this.menuitem}): super(key: key);
#override
_CartOrderDishState createState() => _CartOrderDishState();
}
class _CartOrderDishState extends State<CartOrderDish> {
#override
Widget build(BuildContext context) {
if(GlobalVariables.allcartitems[widget.menuitem][0]>0) {
int price=GlobalVariables.allcartitems[widget.menuitem][0]*GlobalVariables.allcartitems[widget.menuitem][1];
return Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: <Widget>[
Expanded(
child: Text(
widget.menuitem,
style: TextStyle(
fontSize: 20
),
),
),
SizedBox(width: 50),
Container(
child: Row(
children: <Widget>[
SizedBox(
width: 30,
height: 30,
child: FloatingActionButton(
heroTag: 'fab1',
elevation: 1,
child: Icon(Icons.remove, size: 18),
backgroundColor: Colors.red[300],
mini: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5.0))),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
child: Text(
GlobalVariables.allcartitems[widget.menuitem][0].toString(),
style: TextStyle(
fontSize: 18
),
),
),
SizedBox(
width: 30,
height: 30,
child: FloatingActionButton(
heroTag: 'fab2',
elevation: 1,
child: Icon(Icons.add, size: 20),
backgroundColor: Colors.green[300],
mini: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5.0))),
),
)
],
)
),
SizedBox(width: 50),
Row(
children: <Widget>[
Text(
'₹',
style: TextStyle(
fontSize: 20
),
),
Text(
price.toString(),
style: TextStyle(
fontSize:20
)
)
],
)
],
),
);
}
else{
return Container();
}
}
}
Instead of changing the entire icon to indicate items added to cart, you could use Badge
Badge package: https://pub.dev/packages/badges
Update-1: For implementing the badges:
var p1badge = false;
var p2badge = false;
List<BottomNavigationBarItem> buildBottomNavBarItems() {
return [
BottomNavigationBarItem(
icon: Badge(
showBadge: p1badge,
child: Icon(Icons.filter_1),
),
title: Text('Page-1')),
BottomNavigationBarItem(
icon: Badge(
showBadge: p2badge,
child: Icon(Icons.filter_2),
),
title: Text('Page-2'))
];
}
Use a VoidCallback to update the badge:
class Page1 extends StatelessWidget {
VoidCallback onP1Badge;
Page1({this.onP1Badge});
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
RaisedButton(
child: Text('P1 BADGE'),
onPressed: () {onP1Badge();},
),
],
);
}
}
Change the value of p1badge to true and call setState():
pages = [
Page1(
onP1Badge: () {
p1badge = true;
setState(() {});
},
),
Page2()
];
Update-2: Check this out: https://github.com/TheArhaam/Flutter-BottomNavigationBar-Badge
GIF: