How to split two containers in 60% / 40% and position text at the bottom of a container in Flutter? - positioning

I am trying to create something similar like the image below, where there are two containers, one that takes 40% of the screen and the other one the rest of the screen.
In the top container I would like to have a text at the top and one at the bottom, left aligned.
I have this:
// main page body
body: Container(
child: Column(
children: [
// top container
new Expanded(
child: null, // todo, add the two texts,
),
// bottom container
new Container(
height: 400.0, // this needs to be 60% of the page
child: new Text('test'),
),
],
),
),

You can use Expanded widget with flex property.
This is how I did it:
//with dart 2 new and const keywords are optional
void main() => runApp(new MaterialApp(home: new HomePage(),));
class HomePage extends StatelessWidget {
final text = new Text('Text here', style: new TextStyle(fontSize: 50.0),);
final margin = const EdgeInsets.only(bottom: 10.0, right: 10.0, left: 10.0);
final backColor = Colors.lightGreen;
#override
Widget build(BuildContext context) {
var width = MediaQuery.of(context).size.width; // Using this line I got the device screen width
return new Scaffold(
body: new SafeArea(//I didnt add appbar. this will add necessary padding for status bar.
child: new Column(
children: [
new Expanded(
flex: 2,
child: new Container(
width: width /1.5, // this will give you flexible width not fixed width
margin: margin, // variable
color: backColor,// variable
child: new Column(
children: <Widget>[
new Expanded(
flex: 1,
child: new Container(
alignment: Alignment.topCenter,
child: text, //varaible above
),
),
new Expanded(
flex: 1,
child: new Container(
alignment: Alignment.bottomCenter,
child: text, //variable above
),
),
],
),
),
),
new Expanded(
flex: 3,
child: new Container(
width: width /1.5, // this will give you flexible width not fixed width
margin: margin, //variable
color: backColor,//variable
),
),
],
),
),
);
}
}

Related

How to generate and validate a list of TextEditingController and upload the List of textEditingController to firebase -flutter

I created an upload page where user picks multiple images and then assign a price for each image.I'm want to achieve this with a list of TextEditing controllers and displaying textfield under each image.
First I created the list and later generate the list according to the length of the images.
List<TextEditingController> _controller;
Widget buildGridView() {
return Container(
height: 400,
child: GridView.count(
crossAxisCount: 1,
scrollDirection: Axis.horizontal,
children: List.generate(images.length, (index) {
//I can't use the index I defined below in controller.
//says (i) is undefined so I used the index which defined above.
//Am I doing it right?
_controller = List.generate(images.length, (i) => TextEditingController());
Asset asset = images[index];
return Padding(
padding: EdgeInsets.all(8.0),
child: Container(
height: 100,
width: 100,
child: Column(
children: [
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: AssetThumb(
asset: asset,
width: 300,
height: 300,
),
),
Form(
key: _formKey,
child: TextFormField(
keyboardType: TextInputType.number,
validator: (String value) {
double sal = double.tryParse(value);
if (sal == null) {
return 'enter or delete row';
}
return null;
},
controller: _controller[index],
),
),
],
),
),
);
}),
),
);
}
Here _formkey gives me error duplicate key found.Can I generate a list of formKeys according to the length of images?
at last I want to upload the list of textEditingControllers. I has .toList() parameter but not .text
You should have just one Form widget with one FormKey and that should wrap the all the TextFormField widgets.
Form class
An optional container for grouping together multiple form field
widgets (e.g. TextField widgets).
https://api.flutter.dev/flutter/widgets/Form-class.html
So in this case, your Form should wrap the GridView.
Here is your buildGridView method with the update:
Widget buildGridView() {
return Container(
height: 400,
child: Form(
key: _formKey,
child: GridView.count(
crossAxisCount: 1,
scrollDirection: Axis.horizontal,
children: List.generate(images.length, (index) {
//I can use the index I defined below in controller.
//says i is undefined so I used the index which defined above.
//Am I doing it right?
_controller =
List.generate(images.length, (i) => TextEditingController());
Asset asset = images[index];
return Padding(
padding: EdgeInsets.all(8.0),
child: Container(
height: 100,
width: 100,
child: Column(
children: [
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: AssetThumb(
asset: asset,
width: 300,
height: 300,
),
),
TextFormField(
keyboardType: TextInputType.number,
validator: (String value) {
double sal = double.tryParse(value);
if (sal == null) {
return 'enter or delete row';
}
return null;
},
controller: _controller[index],
),
],
),
),
);
}),
),
),
);
}
In order to get the list of text from the controller list, you need to map each controller to get the text.
List<String> textList = _controller.map((x) => x.text).toList();

I am having difficulty to align components(widgets, html components, react components etc.)

I am new to flutter. However, I am having difficulty to align the widgets. I have also tried to learn CSS in the past. The thoughest part of it was to align the html components.
There are many properties like padding, margin, alignment, crossAxisalignment etc. Actually, I know where to use that properties, but when I use them the result is not what I expected.
However, I think if I can learn how to align in flutter. It will be easier to position in all others. For instance, I need to learn how to locate the color palette in the right and bottom of the phone. Every time when I need to locate something like that I am searching it and find the solution. That takes a lot of my time. So, what is the best way to learn how to position that widgets. Is there any source that I can use?
Here is the code:
import 'package:flutter/material.dart';
class Todo extends StatefulWidget {
#override
_TodoState createState() => _TodoState();
}
class _TodoState extends State<Todo> {
TextEditingController _controller = new TextEditingController();
List colors = [ Colors.grey[800], Colors.deepPurpleAccent, Colors.teal,Colors.amber];
int index=0;
String _text;
int _maxLength = 30;
#override
Widget build(BuildContext context) {
final bottom = MediaQuery.of(context).viewInsets.bottom;
return Scaffold(
backgroundColor:colors[index] ,
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
body: SingleChildScrollView(
reverse: true,
child: Container(
padding: EdgeInsets.fromLTRB(0, 50, 0, bottom),
child: Stack(
children: [
TextField(
style: TextStyle(color: Colors.white),
maxLengthEnforced: true,
maxLength: _maxLength,
onTap: null,
controller: _controller,
autocorrect: false,
textCapitalization: TextCapitalization.sentences,
onChanged: (String text) {
if (text.length <= _maxLength)
_text = text;
else
_controller.text = text;
},
decoration: InputDecoration(
focusColor: Colors.red,
border: OutlineInputBorder(),
fillColor: Colors.white,
),
),
TextField(
style: TextStyle(color: Colors.white),
maxLines: null,
decoration: InputDecoration(
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
),
),
Positioned(
right: 5,
bottom: 0,
child: IconButton(
icon: Image.asset('assets/colorize.png'),
tooltip: 'Closes app',
onPressed: (){
setState(() {
if(index<colors.length)
index++;
if(index==colors.length)
index=0;
print("index: " + index.toString() + " len: " +colors.length.toString());
});
},
),
)
],
),
),
),
);
}
}
You can use a positioned widget, that will give you a freedom to position objects inside a STACK, but if you want your positioning to be more accurate / cleaner (still achievable with positioned widget), you can go with the Row and Column widgets,
Kindly refer to the flutter docs For Row Widget
they have some interactive examples to experiment with, for your need, what I would do is to use the "MediaQuery.of(context).size.height, and MediaQuery.of(context).size.width and reduce the icon size, or you can do this also,
This will position your palette in the right bottom of your screen and still have options to add other widgets to your app,
Stack(
children: [
Positioned(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [Text("Hello")],
)
],
))
],
);
you will find the "Hello" in the right bottom of your screen for the code above.
Replace the Text widget with a choice of your own, and Happy Coding :)
I found the answe. Just need to use floatingActionButton outside the SingleChildScrollView. Thus, The color palette will stick into bottom-wight.
Here is the code
floatingActionButton: IconButton(
icon: Image.asset('assets/colorize.png'),
tooltip: 'Closes app',
onPressed: () {
setState(() {
if (index < colors.length) index++;
if (index == colors.length) index = 0;
print("index: " +
index.toString() +
" len: " +
colors.length.toString());
});
},
),

Flutter: aligning buttons edge to edge to other components

I found it difficult to layout buttons in a way that their visual representation is harmonic with other widgets, yet their touchable area has additional extra space for users' fingers.
Please have a look at the attached picture.
Code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Material(child: HomePage()),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Container(
color: Colors.yellow,
padding: EdgeInsets.all(16),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text('Top Left'),
Spacer(),
Text('Top right')
],
),
Row(
children: <Widget>[
Text('Middle Left'),
Spacer(),
Text('Middle right')
],
),
Row(
children: <Widget>[
Text('Bottom Left'),
Spacer(),
Text('Bottom right')
],
),
],
),
),
Container(
color: Colors.orange,
padding: EdgeInsets.all(16),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text('Top Left'),
Spacer(),
FlatButton(
child: Text('Top right'),
onPressed: () {},
)
],
),
Row(
children: <Widget>[
Text('Middle Left'),
Spacer(),
Text('Middle right')
],
),
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.print),
onPressed: () {},
alignment: Alignment.bottomLeft,
),
Spacer(),
Text('Bottom right')
],
),
],
),
),
],
),
);
}
}
The "all texts" widgets are beautifully aligned. But when I add interactive widgets, it starts getting ugly.
The Flat button has the same font as Text. But it's touchable area is expanding it. I am aware of materialTapTargetSize but it shrinks the clickable area which has its inflated size to make it easy to tap it. Is there an easy way to render it exactly as the "Top right" text widget and still have the same touchable area? In that case, the touchable area should expand further out of 16px padding, because I would link the Ink to be distributed evently around the button.
IconButton is higher than text, but the problem is that it doesn't start where the texts starts (left edge). Even if I add the alignment: Alignment.centerLeft, it is slightly moved to the left but still not edge to edge with other texts. On top of that after changing this alignment it's no longer centred within its InkWell.
For now, I solve all these issues using Stack and Positioned widgets. With this approach, I can control exactly where the items are, and the InkWell keeps the content exactly in the centre. But I believe it's not a correct solution.
Appreciate your feedback.
Try this code,
For the flat button:
Container(
alignment: Alignment.centerRight,
width: 60,
child: FlatButton(
padding: EdgeInsets.all(0),
child: Text('Top right'),
onPressed: () {},
),
)
For the icon button:
IconButton(
padding: EdgeInsets.all(0),
icon: Icon(Icons.print),
onPressed: () {},
alignment: Alignment.bottomLeft,
),

Flutter: How can the position of buttons in a SingleChildScrollView be changed?

I would like to have a screen with a changeable amount of buttons. This is realized by a list of MaterialButtons. Because I don't know the amount of the buttons (maybe is too big to display all of them on the screen), I use a SingleChildScrollView to make the list of buttons scrollable. If there are less buttons, so that the screen is not filled completely, the buttons should always be displayed in the middle of the screen. At the moment, the button list always starts at the top of my screen.
Does anybody know how to implement this automatic position adjustment? And is it possible to change the space between the buttons?
This is my code (at the moment there is a fix number of 3 buttons but that will be changed soon):
class PlanState extends State<PlanForm> {
var namesList = new List<String>();
List<MaterialButton> buttonsList = new List<MaterialButton>();
#override
void initState() {
super.initState();
namesList.add("Button1");
namesList.add("Button2");
namesList.add("Button3");
List<Widget> _buildButtonsWithNames() {
int length = namesList.length;
for (int i = 0; i < length; i++) {
buttonsList
.add(new MaterialButton(
height: 40.0,
minWidth: 300.0,
color: Colors.blue,
textColor: Colors.white,
child: new Text(namesList[0], textScaleFactor: 2.0,),
onPressed: () {
Navigator.push(context, new MaterialPageRoute(builder: (context) => new viewPlanScreen()),);
}
));
namesList.removeAt(0);
}
return buttonsList;
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child:Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: _buildButtonsWithNames()
)
)
);
}
}
Because the SilgheChildScrollView has an "infinite" size in the main axis direction you can not center things like in other scenarios. If you check the documentation [1] there are some examples on how to achieve this like centering if there is enough room. I have no tried but should be something like this:
LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: _buildButtonsWithNames(),
)
)
)
}
)
[1] https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html

How to have a Flutter button be as wide as possible up to a maximum width?

In the following layout, I'd like the button to be able to grow to be as wide as possible on the screen, up to a maximum width. I've tried the following, which doesn't work (the button is always as wide as possible):
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(),
TextFormField(),
ConstrainedBox(
constraints: BoxConstraints(maxWidth: 200),
child: RaisedButton(child: Text("button"), onPressed: () {}),
),
],
),
),
),
),
);
}
}
To expand on the layout I'm looking for: the button must be the same width as the smaller of the following two quantities: 1) the width of the screen, 2) a given fixed maximum width.
Example scenarios:
A) the screen is 1000 pixels wide, and the given fixed maximum width is 600 pixels, then the button will be 600 pixels wide.
B) the screen is 400 pixels wide, and the given fixed maximum width is 600 pixels, then the button will be 400 pixels wide.
The solution is pretty simple, simply wrap your ConstrainedBox in Align and instead of using maxWidth use minWidth.
Align(
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: 200),
child: RaisedButton(child: Text("button"), onPressed: () {}),
),
)
Output:
If screen width > 200, button takes up 200 width
If screen width < 200, button takes up screen width
You can remove crossAxisAlignment: CrossAxisAlignment.stretch, because TextFormField is stretching anyway. This code will make the button width to be of a max width size, but no bigger than screen width:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) => MaterialApp(
home: Scaffold(
body: SafeArea(
child: Center(
child: Column(
children: [
TextFormField(),
TextFormField(),
Container(
width: 200,
child: RaisedButton(
onPressed: () {},
child: Text('button'),
),
),
Container(
width: 200,
child: RaisedButton(
onPressed: () {},
child: Text(
'Button with long text asf sadf sdf as df s df as '
'dfas dfsd f asfauhiusg isdugfisudgfi asudgk usgkdu'
'ksdfhk sudfhk sudhfk',
),
),
),
],
),
),
),
),
);
}
You can put the RaisedButton in a Row:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(),
TextFormField(),
ConstrainedBox(
constraints: BoxConstraints(maxWidth: 250),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(child: Text('test')),
),
],
),
),
],
),
),
),
),
);
}
}
The Row will create a horizontal row, and the RaisedButton widget will only take as much room as its own size.
first wrap with container and add width to infinity to be responsive:
Container(
width: double.infinity,
child: ElevatedButton(
child: Text("button"),
onPressed: (){}
),
),
you can add padding too..
known that RaisedButton is deprecated and migrated to ElevatedButton..

Resources