Related
Here's a mockup of the dialog I'm trying to create in Flutter:
Here's what I have so far:
I'm unable to position my two button's with rounded bottom corners at the bottom of the dialog so that it looks like in the mockup.
I was able to make those buttons fit within the Dialog width, without the stack, but then it would be positioned at the top.
Here's the code for the dialog:
SimpleDialog carDialog = SimpleDialog(
contentPadding: EdgeInsets.all(0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
children: <Widget>[
Container(
height: 400,
child: Stack(
children: <Widget>[
Positioned(
bottom: 0,
child: IntrinsicWidth(
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(6)),
color: Colors.lightBlueAccent,
),
height: 45,
child: Center(
child: Text(
allTranslations.text('wait_enroute').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(6)),
color: AppColors.action_button,
),
height: 45,
child: Center(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
allTranslations.text('new_order').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
),
],
),
),
),
],
),
),
],
);
showDialog(context: context, builder: (context) => carDialog);
I have found a working solution. It does not require the Stack widget, everything can be nested within a Column like so:
SimpleDialog carDialog = SimpleDialog(
contentPadding: EdgeInsets.all(0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
children: <Widget>[
Column(
children: <Widget>[
SizedBox(
height: 400,
),
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: InkWell(
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.only(bottomLeft: Radius.circular(6)),
color: Colors.lightBlueAccent,
),
height: 45,
child: Center(
child: Text(
allTranslations.text('wait_enroute').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.only(bottomRight: Radius.circular(6)),
color: AppColors.action_button,
),
height: 45,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
allTranslations.text('new_order').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
),
],
),
],
),
],
);
showDialog(context: context, builder: (context) => carDialog);
The result:
You can try this replacing with Row
LayoutBuilder(
builder:(BuildContext context, BoxConstraints constraints){
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
width : constraints.maxWidth/2
child:Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(6)),
color: Colors.lightBlueAccent,
),
height: 45,
child: Center(
child: Text(
allTranslations.text('wait_enroute').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
SizedBox(
width : constraints.maxWidth/2
child:Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(6)),
color: AppColors.action_button,
),
height: 45,
child: Center(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
allTranslations.text('new_order').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
),
],
);
}
),
Good morning. I made this screen and it works like a charm on high resolutions. Problem is, I want to support lower resolutions like Nexus 4 (768x1280).
So when I run this on an emulator (Nexus 4 size) and I touch the input fields, the keyboard either: blocks the inputs, or moves the two buttons at the bottom and overlaps them on something else.
So, to solve it I wrapped the entire layout on a ListView(), but now the bottom buttons, which are wrapped on a Row(), just won't stay at the bottom.
This is my code without the ListView and working on high res, but not on low:
return Form(
Stack(
Center(
Column(
...
),
),
Align(
alignment: Alignment.bottomCenter,
child: Row(
...
),
),
),
);
This is how it looks with resizeToAvoidBottomPadding: false
And this is how it looks with the value set to true
Thanks, everyone.
Did you try to use SingleChildScrollView ?
It is a widget for making the page able to resize the height and as well scrolling , for the listview thats not what is the listview for , you should add listview when you get an unknown amount of data,
We don't normally use it to just adjust the view.
ok so i edited the code as in here and i can scroll normally after the keyboard pop up and the view is good and i can click on the button normally try it.
Widget formWidget(){
return new Scaffold(
// appBar: AppBar(
// // Here we take the value from the MyHomePage object that was created by
// // the App.build method, and use it to set our appbar title.
// title: Text(widget.title),
// ),
body:Column(
children: <Widget> [
Expanded(
child:SingleChildScrollView(
child: Form(
child:
// Stack(
// children: <Widget>[
// Center(
// child: SingleChildScrollView(
// child:
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: (MediaQuery.of(context).size.height) > 600
? const EdgeInsets.only(top: 0.0)
: const EdgeInsets.only(top: 30.0),
child: Image(
image: AssetImage('assets/favIcon.png'),
width: 88.0,
height: 88.0,
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 28.0, 0, 12.0),
child: Text(
'Delegados',
style: TextStyle(
fontFamily: 'Archia',
fontSize: 32.0,
),
),
),
Text(
'Introduce tus datos de acceso aquí.',
style: TextStyle(
color: Color(0xff83868F),
fontFamily: 'Brutal',
fontSize: 14.0,
),
),
Padding(
padding:
const EdgeInsets.fromLTRB(16.0, 26.0, 16.0, 12.0),
child: TextFormField(
decoration: InputDecoration(
labelText: 'Correo',
filled: true,
fillColor: Color(0xffF0F1F5),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide(
width: 0,
style: BorderStyle.none,
),
),
),
style: TextStyle(
fontFamily: 'Brutal',
color: Color(0xff1A1B1F),
),
controller: TextEditingController() ,
textInputAction: TextInputAction.next,
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 0, 16.0, 12.0),
child: TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Contraseña',
filled: true,
fillColor: Color(0xffF0F1F5),
suffixIcon: Icon(Icons.remove_red_eye),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide(
width: 0,
style: BorderStyle.none,
),
),
),
style: TextStyle(
fontFamily: 'Brutal',
color: Color(0xff1A1B1F),
),
controller: TextEditingController() ,
//focusNode:FocusNode(),
obscureText: true,
),
),
Align(
alignment: Alignment.centerRight,
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 26.0),
child: CupertinoButton(
onPressed: () {},
child: Text(
'Olvidé mi Contraseña',
style: TextStyle(
color: Color(0xff565A66),
fontFamily: 'Brutal',
fontSize: 14.0,
),
),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 0, 16.0, 0),
child: ButtonTheme(
minWidth: double.infinity,
child: InkWell(
// onTap: state is! LoginLoading
// ? _onLoginButtonPressed
// : null,
child: Container(
height: 48.0,
width: 500.0,
decoration: BoxDecoration(
color: Color(0xff00CC36),
borderRadius: BorderRadius.circular(8.0),
),
child: Align(
alignment: Alignment.center,
child: Container(
child:
// state is LoginLoading
// ? CircularProgressIndicator():
Text(
'INGRESAR AHORA ›',
style: TextStyle(
color: Colors.white,
fontFamily: 'Brutal',
fontSize: 14.0,
),
),
)),
),
),
),
),
],
),
// ),
)
,
// aqui va <<<<<<<<<<<<
// ],
// ),
)
),
Align(
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CupertinoButton(
onPressed: () {},
child: Text(
'¿No tienes cuenta?',
style: TextStyle(
color: Color(0xff83868F),
fontFamily: 'Brutal',
fontSize: 14.0,
),
),
),
InkWell(
onTap: null,
child: Container(
height: 32.0,
width: 112.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
border: Border.all(
color: Color(0xffD7D9E0),
width: 1.0,
),
),
child: Align(
alignment: Alignment.center,
child: Text(
'CONTACTANOS',
style: TextStyle(
color: Color(0xff565A66),
fontFamily: 'Brutal',
fontSize: 11.0),
),
),
),
),
],
),
),
]
)
,
// )
);
}
In your Scaffold can you try this.
Scaffold(
resizeToAvoidBottomInset: false,
...
);
I position two elements in the center and bottom of the screen by this code.
body: Column(
children: [
Expanded(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 80,
width: 80,
child:
Image(image: AssetImage("assets/images/logo.png"))),
SizedBox(height: 10),
Text(
"Tings App",
style: TextStyle(fontSize: 36),
),
SizedBox(height: 10),
TextFormField(
controller: _emailController,
decoration: InputDecoration(
border: OutlineInputBorder(),
isDense: true,
labelText: 'Email/phone'),
validator: (value) {
if (value.isEmpty) {
return 'Please enter a valid email';
}
return null;
},
),
],
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
_isLoading
? CircularProgressIndicator()
: SizedBox(
width: MediaQuery.of(context).size.width * 0.7,
height: 60.0,
child: ElevatedButton(
style: ButtonStyle(
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
),
),
),
child: Text(
"SignIn",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w800,
fontSize: 18),
),
onPressed: () {
_login(context);
},
),
),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Don't have account?",
style: TextStyle(fontSize: 16),
),
SizedBox(width: 6),
TextButton(
onPressed: () {
Navigator.push(
context, SlideRightRoute(page: Signup()));
},
child: Text("SignUp"),
),
],
)
],
),
),
)
],
),
And I am Using this code: how to set this kind of layout in flutter
Container(
height: 200.0,
decoration: new BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: Center(
child: Stack(
children: <Widget>[
Icon(Icons.play_arrow, color: Colors.blue, size: 200.0,)
],
),
),
);
try this, you have to just make Stack alignment to center and add a Text in Stack array.
Container(
height: 200.0,
decoration: new BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: Center(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Icon(
Icons.play_arrow,
color: Colors.blue,
size: 200.0,
),
Text(
"Play",
style: TextStyle(fontSize: 18,color: Colors.white),
),
],
),
),
)
friends, I am thinking to make this type of view but I can't able to set the button overlapping like the given image I am using stack widget which is containing the text fields and the buttons as given image please check and help me out I also tried to use the center widgets as well but the view is coming as required in it also i had used the positioned widget but its getting button bottom of the screen like this but i need as the above image
MyLayoutDesign
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
MyAppState myAppState() => new MyAppState();
return myAppState();
}
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(home: new Scaffold(body: new Builder(
builder: (BuildContext context) {
return new Stack(
children: <Widget>[
new Image.asset(
'assets/images/bg.png',
fit: BoxFit.cover,
),
new Center(
child: new Container(
child: new Card(
color: Colors.white,
elevation: 6.0,
margin: EdgeInsets.only(right: 15.0, left: 15.0),
child: new Wrap(
children: <Widget>[
Center(
child: new Container(
margin: EdgeInsets.only(top: 20.0),
child: new Text(
'Login',
style: TextStyle(
fontSize: 25.0, color: secondarycolor),
),
),
),
new ListTile(
leading: const Icon(Icons.person),
title: new TextFormField(
decoration: new InputDecoration(
hintText: 'Please enter email',
labelText: 'Enter Your Email address',
),
keyboardType: TextInputType.emailAddress,
),
),
new ListTile(
leading: const Icon(Icons.lock),
title: new TextFormField(
decoration: new InputDecoration(
hintText: 'Please enter password',
labelText: 'Enter Your Password',
),
keyboardType: TextInputType.emailAddress,
obscureText: true,
),
),
Container(
margin: EdgeInsets.only(top: 10.0, bottom: 15.0),
child: Center(
child: Text(
"FORGOT PASSWORD",
style: TextStyle(
decoration: TextDecoration.underline,
color: Colors.black,
fontSize: 16.0),
),
),
),
Center(
child: Container(
margin: EdgeInsets.only(bottom: 40.0, top: 10.0),
child: Text.rich(
TextSpan(
children: const <TextSpan>[
TextSpan(
text: 'NEW USER ? ',
style: TextStyle(
fontSize: 16.0, color: Colors.black)),
TextSpan(
text: 'REGISTER',
style: TextStyle(
fontSize: 16.0,
decoration: TextDecoration.underline,
color: Colors.black)),
],
),
),
),
),
],
),
),
),
),
new RaisedButton(
onPressed: () {
print('Login Pressed');
},
color: primarycolor,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
child: new Text('Login',
style: new TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.bold)),
),
],
);
},
)));
}
}
this is just one the many ways you can achieve the expected result.
In this case, i assume you know the height of the background.
Again, there are many ways to achieve what you want. There is nothing wrong with your code, you just have to get an understanding of how 'things' work in Flutter
Widget demo = Stack(
children: <Widget>[
//First thing in the stack is the background
//For the backgroud i create a column
Column(
children: <Widget>[
//first element in the column is the white background (the Image.asset in your case)
DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white
),
child: Container(
width: 300.0,
height: 400.0,
)
),
//second item in the column is a transparent space of 20
Container(
height: 20.0
)
],
),
//for the button i create another column
Column(
children:<Widget>[
//first element in column is the transparent offset
Container(
height: 380.0
),
Center(
child: FlatButton(
color: Colors.red,
child: Text("Press Me"),
onPressed: () {},
),
)
]
)
],
);
Here you can find your solution code below.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
MyAppState myAppState() => new MyAppState();
return myAppState();
}
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(home: new Scaffold(body: new Builder(
builder: (BuildContext context) {
return new Stack(
children: <Widget>[
new Image.asset(
'assets/images/bg.jpeg',
fit: BoxFit.fitWidth,
),
new Center(
child: new Container(
height: 370.0,
child: Container(
height:250.0,
child: new Card(
color: Colors.white,
elevation: 6.0,
margin: EdgeInsets.only(right: 15.0, left: 15.0),
child: new Wrap(
children: <Widget>[
Center(
child: new Container(
margin: EdgeInsets.only(top: 20.0),
child: new Text(
'Login',
style: TextStyle(
fontSize: 25.0, color: Colors.red),
),
),
),
new ListTile(
leading: const Icon(Icons.person),
title: new TextFormField(
decoration: new InputDecoration(
hintText: 'Please enter email',
labelText: 'Enter Your Email address',
),
keyboardType: TextInputType.emailAddress,
),
),
new ListTile(
leading: const Icon(Icons.lock),
title: new TextFormField(
decoration: new InputDecoration(
hintText: 'Please enter password',
labelText: 'Enter Your Password',
),
keyboardType: TextInputType.emailAddress,
obscureText: true,
),
),
Container(
margin: EdgeInsets.only(top: 10.0, bottom: 15.0),
child: Center(
child: Text(
"FORGOT PASSWORD",
style: TextStyle(
decoration: TextDecoration.underline,
color: Colors.black,
fontSize: 16.0),
),
),
),
Center(
child: Container(
margin: EdgeInsets.only(bottom: 40.0, top: 10.0),
child: Text.rich(
TextSpan(
children: const <TextSpan>[
TextSpan(
text: 'NEW USER ? ',
style: TextStyle(
fontSize: 16.0, color: Colors.black)),
TextSpan(
text: 'REGISTER',
style: TextStyle(
fontSize: 16.0,
decoration: TextDecoration.underline,
color: Colors.black)),
],
),
),
),
),
Padding(padding: EdgeInsets.only(left: 120.0)),
],
),
),
),
padding: EdgeInsets.only(bottom: 30),
),
),
new Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 310.0)),
RaisedButton(
onPressed: () {
print('Login Pressed');
},
color: Colors.green,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
child: new Text('Login',
style: new TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.bold)),
),
],
)
)
],
);
},
)));
}
}
#ibhavikmakwana propsed a better solution to your question. The other answers all depend on the size of the background and are not screen independent. They both create an invisible object above the button (either by adding a Container or a Padding).
I was having that question too and did not find your question first.
His simple solution is to wrap the button in a Positioned widget and give it a bottom of 0 or < 0.
Positioned(
child: FlatButton(
color: Colors.red,
child: Text("Press Me"),
onPressed: () {},
),
right: 0,
left: 0,
bottom: 0,
)
I found out that the "bottom" attribute set to 0 will offset the widget by exactly 0.5*height of the widget.
I want to add a ripple on an item, it is working fine until I add a gradient on the item using BoxDecoration.
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: Material(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4.0)),
elevation: 6.0,
shadowColor: Colors.grey[50],
child: InkWell(
onTap: () {},
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: AlignmentDirectional.bottomStart,
end: AlignmentDirectional.topEnd,
colors: [
Colors.yellow[800],
Colors.yellow[700],
],
),
),
padding: EdgeInsets.all(16.0),
child: Text(
widget.title,
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
),
),
);
}
Update in 2019:
You should use Ink widget inside Material, instead of Container.
It takes decoration parameter as well:
Material(
child: Ink(
decoration: BoxDecoration(
// ...
),
child: InkWell(
onTap: () {},
child: child, // other widget
),
),
);
I found the solution:
I need one Material for Inkwell, and one Material for elevation and rounded borders.
The inner Material has a type of MaterialType.transparency so that it doesn't draw anything over the box decoration of its parent and still preserve the ink effect. The shadow and borders are controlled by outer Material.
Container(
margin: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: Material( // <----------------------------- Outer Material
shadowColor: Colors.grey[50],
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4.0)),
elevation: 6.0,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: AlignmentDirectional.bottomStart,
end: AlignmentDirectional.topEnd,
colors: [
AppColors.pinkDark,
AppColors.pink,
],
),
),
child: Material( // <------------------------- Inner Material
type: MaterialType.transparency,
elevation: 6.0,
color: Colors.transparent,
shadowColor: Colors.grey[50],
child: InkWell( //<------------------------- InkWell
splashColor: Colors.white30,
onTap: () {},
child: Container(
padding: EdgeInsets.all(16.0),
child: Row(
children: <Widget>[
Icon(
Icons.work,
size: 40.0,
color: Colors.white,
),
SizedBox(
width: 20.0,
),
Column(
children: <Widget>[
Text(
widget.title,
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
],
)
],
),
),
),
),
),
),
);
Simple splash effect widget I created that works perfect.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SplashEffect extends StatelessWidget {
final Widget child;
final Function onTap;
const SplashEffect({Key key, this.child, this.onTap}) : super(key: key);
#override
Widget build(BuildContext context) {
return Material(
type: MaterialType.transparency,
child: InkWell(
borderRadius: BorderRadius.all(Radius.circular(16)),
child: child,
onTap: onTap,
),
);
}
}
Splash color is overlap by container BoxDecoration
Try this
Widget build(BuildContext context) {
return new Container(
decoration: BoxDecoration(
borderRadius: new BorderRadius.all(new Radius.circular(4.0)),
gradient: LinearGradient(
begin: AlignmentDirectional.bottomStart,
end: AlignmentDirectional.topEnd,
tileMode: TileMode.repeated,
colors: [
Colors.yellow[800],
Colors.yellow[700],
],
),
boxShadow: <BoxShadow>[
new BoxShadow(
color: Colors.grey[50],
//blurRadius: 0.3,
blurRadius: 6.0,
offset: new Offset(0.0, 4.0)
)
]
),
margin: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: Material(
color: Colors.transparent,
//shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4.0)),
//elevation: 6.0,
//shadowColor: Colors.grey[50],
child: InkWell(
splashColor: const Color(0x8034b0fc),
onTap: () {},
child: Container(
//decoration: ,
padding: EdgeInsets.all(16.0),
child: Text(
'Click',
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
),
),
);
}
If anyone came here looking to do use an inkwell with a circle decoration (like I did), I used the accepted answer to come up with this.
Material(
child: Ink(
width: 150,
height: 150,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey[350],
border: Border.all(
color: Colors.red,
width: 4.0,
),
),
child: InkWell(
customBorder: const CircleBorder(),
onTap: onTap,
child: const Icon(Icons.add, size: 48, color: Colors.white),
),
));