i got problem when i dont know to make each buildrow go to each page?this is for buildDrawer can you help me with this?
builDrawer fuction this for profile screen.dart
_buildDrawer() {
return ClipPath(
clipper: OvalRightBorderClipper(),
child: Drawer(
Container(
height: 90,
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient:
LinearGradient(colors: [Colors.pink, Colors.red])),
child: CircleAvatar(
radius: 40,
backgroundImage: NetworkImage(profile),
),
),
SizedBox(height: 5.0),
Text(
"Mohd Amin bin Yaakob",
style: TextStyle(color: Colors.white, fontSize: 18.0),
),
Text(
"Pegawai",
style: TextStyle(color: active, fontSize: 16.0),
),
SizedBox(height: 30.0),
_buildRow(Icons.home, "Home"),
_buildDivider(),
_buildRow(Icons.person_pin, "Your profile"),
_buildDivider(),
_buildRow(Icons.settings, "Settings"),
_buildDivider(),
_buildRow(Icons.email, "Contact us"),
_buildDivider(),
_buildRow(Icons.info_outline, "Help"),
_buildDivider(),
],
),
),
),
),
),
);
}
How to make Functional Navigator each buildRow
You need to make rows with clickable widgets like listtile.
Try this inside your _buildRow()
Widget _buildRow(IconData icon, String title) {
final TextStyle tStyle = TextStyle(color: active, fontSize: 16.0);
return ListTile(
title: Text( title, style: tStyle, ),
leading: Icon( icon, color: active, ),
onTap: () {
// Your navigation code here
},
);
}
You can remove the container as well and try contentPadding in ListTile
Its explained in the drawer documentation https://docs.flutter.dev/cookbook/design/drawer
You can require an onTap function in your _buildRow method. Also wrap you Container inside an InkWell widget and this function in onTap property.
Following is the revised code:
Widget _buildRow(IconData icon, String title, VoidCallback onTap) {
final TextStyle tStyle = TextStyle(color: active, fontSize: 16.0);
return InkWell(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [
Icon(
icon,
color: active,
),
SizedBox(width: 10.0),
Text(
title,
style: tStyle,
),
],
),
),
onTap: onTap,
);
}
When calling the above function, provide the onTap callback like this:
_buildRow(Icons.home, "Home", () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return HomePage();
},
),
);
});
Related
I am building a flutter ecommerce app and I am having an issue where ontap isn't working inside my inkwell widget. I want the ontap to work so that I can show the product description. I have placed the inkwell widget as a child inside a Positioned widget, which happens to be one of the children of a Stack. How can I solve this?
Here's my code:
return Card(
shadowColor: Colors.grey,
surfaceTintColor: Colors.amber,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
child: Stack(
children: [
Positioned(
right: 0,
child: InkWell(
onTap: () {
print('tapped');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ProductDetails(
id: bottleCategory
.bottleList[index].id,
bottleName: bottleCategory
.bottleList[index]
.bottleName,
image: bottleCategory
.bottleList[index]
.image,
price: bottleCategory
.bottleList[index]
.price)));
},
child: IconButton(
icon: favoriteProvider.isExist(
bottleCategory.bottleList[index])
? Icon(
Icons.favorite,
color: Colors.redAccent,
)
: Icon(
Icons.favorite_border,
),
onPressed: (() {
favoriteProvider.toggleFavorites(
bottleCategory.bottleList[index]);
if (favoriteProvider.isExist(
bottleCategory.bottleList[index])) {
ScaffoldMessenger.of(context)
.hideCurrentSnackBar();
ScaffoldMessenger.of(context)
.showSnackBar(
const SnackBar(
content: Text(
"Product Added to Favorite!",
style: TextStyle(fontSize: 16),
),
backgroundColor: Colors.green,
duration: Duration(seconds: 1),
),
);
} else {
ScaffoldMessenger.of(context)
.hideCurrentSnackBar();
ScaffoldMessenger.of(context)
.showSnackBar(
const SnackBar(
content: Text(
"Product Removed from Favorite!",
style: TextStyle(fontSize: 16),
),
backgroundColor: Colors.red,
duration: Duration(seconds: 1),
),
);
}
}),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.asset(
bottleCategory.bottleList[index].image,
height: 200.0,
),
),
Center(
child: Text(
bottleCategory
.bottleList[index].bottleName,
style: const TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold))),
Center(
child: Text(
'R${bottleCategory.bottleList[index].price}'),
)
],
),
Positioned(
bottom: 0,
right: 10,
child: IconButton(
icon: const Icon(Icons.add_circle),
iconSize: 40.0,
onPressed: () {
cart.addToCart(
bottleCategory.bottleList[index].id,
bottleCategory
.bottleList[index].bottleName,
bottleCategory
.bottleList[index].price,
bottleCategory
.bottleList[index].image);
},
))
],
),
);
Why do you use IconButton in the child of InkWell?
use one of them and Put all of your onPress functions into that widget.
This is the output:
I try to make an app but when I use the TextButton, I get the space between two Buttons
I need one by one without space
If I use the Expanded Widget, ScrollChildView doesn't work
I try but I can't clear this stuff.
I try to make this type of TextButton.
Anyone know or have any idea about this?
import "package:flutter/material.dart";
import 'package:audioplayers/audio_cache.dart';
class Account extends StatefulWidget {
Account({Key key}) : super(key: key);
#override
_AccountState createState() => _AccountState();
}
class _AccountState extends State<Account> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Stack(
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextButton(
child: Container(
child: Text(
'One',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.red),
),
onPressed: () {
final player = AudioCache();
player.play('note1.wav');
},
),
SizedBox(
height: 1,
),
TextButton(
child: Container(
child: Text(
'Two',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.green),
),
onPressed: () {
final player = AudioCache();
player.play('note2.wav');
},
),
TextButton(
child: Container(
child: Text(
'Three',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.blue),
),
onPressed: () {
final player = AudioCache();
player.play('note3.wav');
},
),
TextButton(
child: Container(
child: Text(
'Four',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.grey),
),
onPressed: () {
final player = AudioCache();
player.play('note4.wav');
},
),
TextButton(
child: Container(
child: Text(
'Five',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.purple),
),
onPressed: () {
final player = AudioCache();
player.play('note5.wav');
},
),
],
),
),
],
),
),
),
);
}
}
You just wrap your text button with the SizedBox and set height and width as follows:
SizedBox(
height: 30,
width: 150,
child: TextButton(...),
)
Full available height:
SizedBox(
height: double.infinity, // <-- match_parent
child: TextButton(...)
)
Specific height:
SizedBox(
height: 100, // <-- Your height
child: TextButton(...)
)
In Flutter 2.0, you can set the height of the TextButton directly without depending on other widgets by changing the ButtonStyle.fixedSize:
TextButton(
child: Text('Text Button'),
style: TextButton.styleFrom(fixedSize: Size.fromHeight(150)),
),
If you want to modify all TextButtons, put it in the ThemeData like below:
return MaterialApp(
theme: ThemeData(
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(fixedSize: Size.fromHeight(150)),
),
),
Live Demo
use the following to even add your preferred size as well
N/B: child sized box is the main child widget inside Padding widget
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(30.0),
child: SizedBox(
height: 60,
width: 200,
child: ElevatedButton.icon(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RegistrationMenu()));
},
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.red.shade800),
),
icon: Icon(Icons.person_add_alt_1_rounded, size: 18),
label: Text("Register Users"),
),
),
),
],
),
Wrap the TextButton in an "Expanded" Widget.
Expanded(
child: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.red,
padding: EdgeInsets.zero,
),
child: const Text(''),
onPressed: () {
playSound(1);
},
),
),
Another solution would be wrapping with ConstrainedBox and using minWidth & minHeight
properties.
ConstrainedBox(
constraints:BoxConstraints(
minHeight:80,
minWidth:200
),
child:TextButton(..)
)
You need to do two things
Determine text button height using
Sizedbox
Remove padding around text button using
TextStyle.StyleFrom()
SizedBox(
height: 24.0,
child: TextButton(
onPressed: () {},
child: Text('See more'),
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
),
),
),
TextButton(
onPressed: _submitOrder,
child: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: Text("Raise")),
style: ButtonStyle(
shape: MaterialStateProperty.all(
const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(50)),
side: BorderSide(color: Colors.green)))),
)
TextButton(
style: ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap
),
child: Text(''),
);
I created a custom rounded AppBar using a code found here, but with just a title in the center.
I wanted to add a backbutton in the top left corner inside AppBar and I tried nesting a button and the text in a Row, but the result is that neither the button or the text are shown. Any help?
Here the code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class RoundedAppBar extends StatelessWidget implements PreferredSizeWidget {
String title;
RoundedAppBar(this.title);
#override
Widget build(BuildContext context) {
return PreferredSize(
child: LayoutBuilder(builder: (context, constraints) {
final width =
constraints.maxWidth * 16; //per modificare "rotondità" app Bar
return OverflowBox(
maxHeight: double.infinity,
maxWidth: double.infinity,
child: SizedBox(
height: width,
width: width,
child: Padding(
padding: EdgeInsets.only(
bottom: width / 2 - preferredSize.height / 2),
child: Container(
alignment: Alignment.bottomCenter,
padding: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: const Color(0xff000350),
shape: BoxShape.circle,
),
child: Row(
children: [
Align(
alignment: Alignment.centerLeft,
child: IconButton(
color: Colors.black,
icon: Icon(Icons.chevron_left),
onPressed: () => Navigator.pop(context),
),
),
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Conformity',
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.normal),
),
],
)),
),
),
);
}),
preferredSize: preferredSize);
}
#override
Size get preferredSize => Size.fromHeight(80);
EDIT:
Tried using ListTile as suggested, something happened but didn't work properly.
Here the result.
child: ListTile(
title: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Conformity',
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.normal),
),
leading: IconButton(
color: Colors.white,
icon: Icon(Icons.chevron_left),
onPressed: () => Navigator.pop(context),
),
),
EDIT:
I inserted your code as shown. With trial and error, using 35 as height I was able to see the title, but still no button.
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_buildBack(true, context),
Container(
height: 35,
child: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Conformity',
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.normal),
),
),
_buildBack(false, context),
],
and
Widget _buildBack(bool isPlaceHolder, BuildContext context) {
return Visibility(
child: InkWell(
child: Icon(
Icons.close,
size: 35,
),
onTap: () => Navigator.of(context, rootNavigator: true).pop('dialog'),
),
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: !isPlaceHolder,
);
}
and here the result
You can use a ListTile and use a IconButton as leading.
ListTile(
leading: IconButton(
icon: Icon(Icons.back),
title: '',
onPressed => Navigator.pop(context),
),
),
Another possibility I see:
As the child from the AppBar
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_buildBack(true, context),
Container(
height: height,
child: Text(
'$_title',
style: Theme.of(context).textTheme.headline2,
),
),
_buildBack(false, context),
],
),
In another place outside the builder.
Widget _buildBack(bool isPlaceHolder, Buildcontext context) {
return Visibility(
child: InkWell(
child: Icon(
Icons.close,
size: widget.height,
),
onTap: () => Navigator.of(context, rootNavigator: true).pop('dialog'),
),
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: !isPlaceHolder,
);
}}
Here there is again a row as you have tried it yourself, but this one is set up a little differently and an iconButton is built before and after the text, but so that the text remains in the center, the second one is made invisible,
I am using a drawer to create a menu that houses ListTiles for the options. I want to create a popup when the tiles are tapped by the user. Currently, the code displays nothing when the tiles are tapped even though after the showDialog there is a Navigator.pop().
// Drawer that includes the ListTiles in question
Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Smash Tracker'),
),
),
ListTile(
title: Text(
'About',
style: TextStyle(
fontFamily: 'Smash',
fontSize: 15.0,
color: Color.fromRGBO(77, 114, 152, 1.0),
),
),
onTap: () {
// Show PopUp
showDialog(context: context, child:
new AlertDialog(
title: new Text(
'About',
style: TextStyle(fontFamily: "Smash"),
),
content: new Text(
'This is a placeholder. This is a placeholder. This is a placeholder. This is a placeholder.',
style: TextStyle(fontFamily: "Smash"),
),
)
);
// Doesn't run
Navigator.pop(context);
},
),
Here is a demo:
via GIPHY
The other ListTiles have the only have Navigator.pop() inside of their onTap() method.
The dialog isn't showing because you are popping it immediately with the Navigator.pop(context). You can await the Dialog since it returns a Future<T> before popping.
I added a demo using your widget tree as an example:
Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Smash Tracker'),
),
ListTile(
title: Text(
'About',
style: TextStyle(
fontFamily: 'Smash',
fontSize: 15.0,
color: Color.fromRGBO(77, 114, 152, 1.0),
),
),
onTap: () async { // mark the function as async
print('tap');
// Show PopUp
// await the dialog
await showDialog(
context: context,
child: new AlertDialog(
title: new Text(
'About',
style: TextStyle(fontFamily: "Smash"),
),
content: new Text(
'This is a placeholder. This is a placeholder. This is a placeholder. This is a placeholder.',
style: TextStyle(fontFamily: "Smash"),
),
));
// Doesn't run
Navigator.pop(context);
},
),
],
),
),
OUTPUT:
This is my dialog Code
Here is am getting an error of setstate() or MarkerneedsBuild called during the build. this overlay widget cannot be marked as needing to process of building widgets.
When I am trying to call _onAlertOtp widget it will show me this error.in the build method, i've bloc and state when my signup is successful then i have to call alert dialog. but when I am trying to do that it will show me the error. Hope you understand the question please help me.
_onAlertotp(BuildContext context) {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Enter OTP'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 2.7,
width: MediaQuery.of(context).size.width,
alignment: Alignment.center,
child: ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'We have Texted and/or Emailed OTP (One Time Pin) to your registered cell phone and/ or email account. Please check and enter OTP below to activate your TUDO account.',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 15),
textAlign: TextAlign.center,
),
),
SizedBox(
height: 5,
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
length: 6, // must be greater than 0
obsecureText: false, //optional, default is false
shape: PinCodeFieldShape
.underline, //optional, default is underline
onDone: (String value) {
setState(() {
passcode = value;
print(value);
});
},
textStyle: TextStyle(
fontWeight: FontWeight
.bold), //optinal, default is TextStyle(fontSize: 18, color: Colors.black, fontWeight: FontWeight.bold)
onErrorCheck: (bool value) {
setState(() {
hasError = value;
});
},
shouldTriggerFucntions:
changeNotifier.stream.asBroadcastStream(),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Text(
hasError
? "*Please fill up all the cells and press VERIFY again"
: "",
style: TextStyle(
color: Colors.red.shade300, fontSize: 12),
),
),
SizedBox(
height: 20,
),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: "Didn't receive the code? ",
style:
TextStyle(color: Colors.black54, fontSize: 15),
children: [
TextSpan(
text: " RESEND",
// recognizer: onTapRecognizer,
style: TextStyle(
color: colorStyles["primary"],
fontWeight: FontWeight.bold,
fontSize: 16))
]),
),
SizedBox(
height: 7,
),
Container(
margin: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 30),
child: ButtonTheme(
height: 50,
child: FlatButton(
onPressed: () async {
/// check the [_onData] fucntion to understand better
changeNotifier.add(Functions.submit);
// at first we will check error on the press of the button.
if (!hasError) {
_onAlertrunnigbusiness(context);
}
},
child: Center(
child: Text(
"VERIFY".toUpperCase(),
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
)),
),
),
decoration: BoxDecoration(
color: colorStyles["primary"],
borderRadius: BorderRadius.circular(5),
),
),
],
),
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Regret'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Here Is Another DIalog. which open on first dialog verify button click
_onAlertrunnigbusiness(context) {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Are you running Business?'),
content: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: 10,
),
Text(
"TUDO.App aims at Businesses bridging gaps between Business Service Providers and Consumers collaborate on unique technology platform. If you own a business, we strongly recommend, provide your business information to grow your customer base and expand your business services. Any questions? Call us #1-800-888-TUDO"),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('No'),
color: colorStyles["primary"],
textColor: Colors.white,
padding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
NavigationHelper.navigatetoMainscreen(context);
},
),
SizedBox(height: 10),
FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('Yes'),
color: colorStyles["primary"],
textColor: Colors.white,
padding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
NavigationHelper.navigatetoBspsignupcreen(context);
},
),
],
)
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
And Here i am calling my dialog
#override
Widget build(BuildContext context) {
return BlocListener<SignupBloc, SignupState>(
bloc: widget._signupBloc,
listener: (
BuildContext context,
SignupState currentState,
) {
if (currentState is InSignupState) {
_countries = currentState.countries.countries;
return Container(child: content(_signupBloc, context, _countries));
}
if (currentState is SignupButtonClickedEvent) {
print('SignupButtonClickedEvent clicked');
return Container();
}
if (currentState is SignupSuccessState) {
print(
' You are awesome. you have successfully registered without confirmation');
print(currentState.signupUser.toJson());
print("Hey Otp Is opned");
if (!_isError) {
return _onAlertotp(context);
}
// NavigationHelper.navigatetoMainscreen(context);
_isLoading = false;
showAlertBox = true;
return Container(
child: content(_signupBloc, context, _countries),
);
}
if (currentState is SignupVerficationOtp) {
print('signup verficitaion otp button clicked');
return Container();
}
return Container(child: content(_signupBloc, context, _countries));
},
);
}
}
try using below code to display an alert dialog
in place of return _onAlertotp(context);
WidgetsBinding.instance.addPostFrameCallback((_) {
// show alert dialog here
_onAlertotp(context);
});
You should use a BlocListener at the root of your build method to handle events that do not return a widget (in your case the showDialog method)
Your if (currentState is SignupSuccessState) { part would be in the BlocListener and not in the BlocBuilder