flutter - row with elements of unequal weight - flutter

I have a row that spans the width of the screen and with three buttons and a text that are equally spaced(flex = 1). I want the text to be aligned to the center of the screen and the buttons at the ends. is this possible?

To cause a child to expand to fill the available space in the direction of this widget's main axis, wrap the child in an Expanded widget.
So you can try Expanded and declare Flex in second Expanded widget.
Solution
Row(
children: <Widget>[
Expanded(child: Container(padding: EdgeInsets.all(16),color: Colors.red,child: Text("text 1"))),
Expanded(flex: 3,child: Container(padding: EdgeInsets.all(16),color: Colors.blue,child: Text("text 2"))),
Expanded(child: Container(padding: EdgeInsets.all(16),color: Colors.yellow,child: Text("text 3"))),
Expanded(child: Container(padding: EdgeInsets.all(16),color: Colors.green,child: Text("text 4"))),
],
),
Output:

Hey check the code bellow I think it does what you want:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter buttons demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
List<int> values = [1, 2, 3];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Buttons demo'),
centerTitle: true,
),
body: Row(
children: <Widget>[
Flexible(
child: Container(
color: Colors.redAccent,
child: FlatButton(
onPressed: () => {},
child: Text('Button'),
),
),
),
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Some text',
textAlign: TextAlign.right,
),
)),
Flexible(
child: Container(
color: Colors.green,
child: FlatButton(
onPressed: () => {},
child: Text('Button'),
),
),
),
Flexible(
child: Container(
color: Colors.purple,
child: FlatButton(
onPressed: () => {},
child: Text('Button'),
),
),
),
],
));
}
}

There are a few ways. The simplest I can think of is using a SizedBox widget.
In your example, you can use the SizedBox widget and add one additional box with the same dimensions as your left button on the left. The SizedBox will occupy the space but won't be rendered on screen.

Related

ListTile title makes it's children take full width no matter what

I need to insert a TextField in ListTile's title and make it take only the width of the text inside. It works perfectly outside of a ListTile, but inside a title it takes full width of a ListTile no matter what. What can I do?
DartPad: https://dartpad.dev/87f397c71f3e449e866cea9914d13bb0
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key? key, required this.title}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IntrinsicWidth(
child: TextField(
decoration: InputDecoration(
hintText: 'Title',
),
),
),
Container(
width: 300,
child: Card(
clipBehavior: Clip.antiAlias,
child: InkWell(
onLongPress: () {
print('Longpress fired');
},
child: ListTile(
title: IntrinsicWidth(
child: TextField(
decoration: InputDecoration(
isDense: true,
hintText: 'Title',
contentPadding: EdgeInsets.all(0),
),
),
),
subtitle: Text('subtitle'),
),
),
),
),
],
),
),
);
}
}
UPDATE:
I managed to make the TextField take needed space with this code, but now I am sufferng from overflow:
ListTile(
title: Expanded(
child: Row(
children: [
IntrinsicWidth(
child: TextField(),
),
],
),
),
),
I suggest you use a SizedBox for the trailing property in ListView.
It's probably better to just create your own custom widget for this, it's actually not that hard. Looks something like:
Column(
children: [
Column(
children: [
SizedBox(
width: use an approriate MediaQuery here,
child: TextField(),
),
Text('subtitle')
],
),
Maybe even throw in a padding in the Container.

null && minWidth >= 0.0': is not true error when using a SingleChildScrollView

I have a RoundedLoadingButton in a SingleChildScrollView. There are 2 issues.
1: the bottom of the button is cut off (see the bottom shadow)
2: When I click the button or the button becomes a loader, an error pops up on the screen.
I tried adding an Expanded widget to the Column and RoundedLoadingButton, but nothing changed. I also tried changing the mainAxisSize of the column to min and max, but they both didn't help.
What am I doing wrong and how can I fix it?
return SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 40),
child: Form(
child: Column(
children: [
SizedBox(height: Constants.verticaleSectionSpacing * 2),
TextFormField(),
TextFormField(),
TextFormField(),
RoundedLoadingButton(
height: 45,
width: double.infinity,
controller: saveBtnController,
child: Text('Save'),
onPressed: _doSomething,
),
],
),
),
),
);
You can copy paste run full code below
You can change width from double.infinity to MediaQuery.of(context).size.width or a fixed number like 300
working demo
full code
import 'package:flutter/material.dart';
import 'package:rounded_loading_button/rounded_loading_button.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 40),
child: Form(
child: Column(
children: [
//SizedBox(height: Constants.verticaleSectionSpacing * 2),
TextFormField(),
TextFormField(),
TextFormField(),
RoundedLoadingButton(
height: 45,
width: MediaQuery.of(context).size.width,
//controller: saveBtnController,
child: Text('Save'),
onPressed: () {},
),
],
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Size Widgets in Rows/Columns by size of other Widgets in that Row/Column

I want to size a Widget inside a Row/Column with the minimum size of another widget of the same Row/Column
example:
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topCenter,
child: FittedBox(
child: Column(
children: [
LongWidget(),
FlatButton(child: Text("flat button"),
color: Colors.red,
onPressed: () {},
),
],
),
),
);
}
}
it look currently like this:
i want to size the button to the size of the long widget. I tried Expanded and CrossAxisAlignment.Stretch but both break the column
You can copy paste run full code below
You can use IntrinsicWidth and set FlatButton's minWidth: double.infinity
code snippet
return Align(
alignment: Alignment.topCenter,
child: IntrinsicWidth(
child: Column(
children: [
Text("long" * 12),
FlatButton(
minWidth: double.infinity,
child: Text("flat button"),
color: Colors.red,
onPressed: () {},
),
],
),
),
);
working demo
full code
import 'package:flutter/material.dart';
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topCenter,
child: IntrinsicWidth(
child: Column(
children: [
Text("long" * 12),
FlatButton(
minWidth: double.infinity,
child: Text("flat button"),
color: Colors.red,
onPressed: () {},
),
],
),
),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: "test",),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Example(),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

How to constrain ListTile in widget hierarchy

How can I make a ListTile work inside this widget hierarchy:
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Radio(
value: 1,
groupValue: 1,
onChanged: (sel) {},
),
GestureDetector(
child: Row(
children: <Widget>[
//Text('Title'), -- This is OK, but ListTile fails
ListTile(
title: Text('Title'),
subtitle: Text('Subtitle'),
),
],
),
onTap: () {},
),
],
),
],
),
),
Please understand that I am not in full control of the widget hierarchy -- a framework is building the SingleChildScrollView, Radio, GestureDetector, etc. I am simply trying to supply a child widget for an option. (I replicated the hierarchy in a simplified form to debug and experiment.)
I'm getting an exception:
flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown during performLayout():
flutter: BoxConstraints forces an infinite width.
flutter: These invalid constraints were provided to RenderParagraph's layout() function by the following
flutter: function, which probably computed the invalid constraints in question:
flutter: _RenderListTile._layoutBox (package:flutter/src/material/list_tile.dart:1318:9)
flutter: The offending constraints were:
flutter: BoxConstraints(w=Infinity, 0.0<=h<=Infinity)
Normally when I encounter this kind of problem, I simply wrap the widget in an Expanded, but that is not working in this case.
Note that if I replace the ListTile with a simple Text widget, then it renders fine.
You can wrap the ListTile in a Container or a ConstrainedBox and set its maxWidth:
ConstrainedBox(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width - 50,
),
child: ListTile(
title: Text('Title'),
subtitle: Text('Subtitle'),
trailing: Text('Trailing'),
),
),
You can copy paste run full code below
You can use IntrinsicWidth wrap Row and Expanded wrap ListTile and you can have more than one Expaned ListTile
GestureDetector(
child: IntrinsicWidth(
child: Row(
children: <Widget>[
//Text('Title'), -- This is OK, but ListTile fails
Expanded(
child: ListTile(
title: Text('Title'),
subtitle: Text('Subtitle'),
),
),
],
),
),
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Radio(
value: 1,
groupValue: 1,
onChanged: (sel) {},
),
GestureDetector(
child: IntrinsicWidth(
child: Row(
children: <Widget>[
//Text('Title'), -- This is OK, but ListTile fails
Expanded(
child: ListTile(
isThreeLine: true,
title: Text('Title'),
subtitle: Text('this is long text this is long text this is long text \n'* 10),
),
),
],
),
),
onTap: () {},
),
],
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
full code 2 relayout
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
flex: 1,
child: Radio(
value: 1,
groupValue: 1,
onChanged: (sel) {},
),
),
Expanded(
flex: 5,
child: GestureDetector(
child: LayoutBuilder(
builder:(context, constraints) {
print(constraints.maxWidth);
print(constraints.minWidth);
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: constraints.maxWidth),
child: ListTile(
//isThreeLine: true,
title: Text('Title'),
subtitle: Text(
'Textlargeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: TextStyle(
fontSize: 13.0,
fontFamily: 'Roboto',
color: Color(0xFF212121),
fontWeight: FontWeight.bold,
),
),
),
);
}
),
onTap: () {},
),
),
],
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Flutter : how to make an entire row clickable

How do I make the entire row clickable in flutter?. I have the following code wrap in a "GestureDetector". The individual items in the row are clickable but white space around the widget are not.
if ((auth.isLoggedIn)) ...[
GestureDetector(
onTap: () {
auth.signOut();
},
child: buildItem(
Image.asset("assets/images/logoff.png",),
"logout"
),
),
],
This is the "buildItem" method
Widget buildItem(Widget icon, String title) {
return Padding(
padding: const EdgeInsets.only(left: 20, right: 15),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
child: Row(
children: <Widget>[
icon,
SizedBox(width: 20.0),
Text(
title,
style: TextStyle(
fontSize: 16.0,
),
),
],
)),
Icon(
Icons.arrow_forward_ios,
size: 20.0,
),
],
),
);
}
This is the output. Each item in the row (icon, text and the >) respond to the tap gesture. However, the white space(e.g between the text and the ">") does not respond to tap
How can I make entire row respond to the tap.
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
///
},
replace GestureDetector with InkWell works great
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: () {
print("click");
},
child: buildItem(
Image.network("https://picsum.photos/250?image=9",),
"logout"
),
),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Widget buildItem(Widget icon, String title) {
return Padding(
padding: const EdgeInsets.only(left: 20, right: 15),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
child: Row(
children: <Widget>[
icon,
SizedBox(width: 20.0),
Text(
title,
style: TextStyle(
fontSize: 16.0,
),
),
],
)),
Icon(
Icons.arrow_forward_ios,
size: 20.0,
),
],
),
);
}
row: mainAxisAlignment: MainAxisAlignment.spaceBetween
For space between, the first and the last object will stick to the edge of the container, while leaving the empty unused space in between (if there is other objects, it will distributed it evenly), like shown in the screenshot below:
Hence to solve this, you just have to make sure that there is no empty space between.
One way is to use mainAxisSize: MainAxisSize.max and MainAxisAlignment.start in the Row where you put your icon and text.