I want to design a page for my Flutter app that can be displayed with the same aspect on all screen devices without having to scroll to see the bottom of the page. In the left image below you can see the result of my code :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
textTheme: TextTheme(
headline: TextStyle(fontSize: 64.0),
subhead: TextStyle(fontSize: 48.0),
title: TextStyle(fontSize: 36.0),
subtitle: TextStyle(fontSize: 24.0),
button: TextStyle(fontSize: 24, color: Colors.white),
body1: TextStyle(fontSize: 18.0, color: Colors.black),
body2: TextStyle(fontSize: 14.0, color: Colors.black),
),
),
home: Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: IconButton(
icon: Icon(Icons.settings),
onPressed: () {
Navigator.pushNamed(context, '/settings');
},
),
),
],
),
Text(
'My Title Here',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 64.0),
),
TextField(
style: Theme.of(context).textTheme.body1,
),
TextField(
style: Theme.of(context).textTheme.body1,
),
RaisedButton(child: Text('Start'), onPressed: () {}),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(Icons.star),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.star),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.star),
onPressed: () {},
),
],
),
],
),
),
),
);
}
}
It's very simple, and it's looking fine, but when I clicked on the second TextField, I have a problem of overflow like you can see in the right image : (I made my test on an iPhone 5s).
I tested to add a SingleChildScrollView, a SafeArea but when I do that I have a big blank space at the bottom of the screen and it's not what I m looking for. How can I solve this ?
Thanks for your help
Hi this is a closed issue on Flutter repo. Replace your column with ListView and instead of using alignment property add paddings and margins to your textfield
OR
You can use SingleChildScrollView as you said in the question
Both the cases you need to add padding to textField to fill the blank space
Related
I recently picked up Flutter and Dart and am attempting to create an app that has a modal with three parts: a header, actual content, and a footer.
For the header I am looking to add a title (Text) center aligned and a close button right aligned.
I have the following code:
Column(
children: [
Row(
children: [
Expanded(
child: Text(
"Filters",
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () {
Navigator.pop(context);
},
),
],
),
],
),
)
Visually, this looks like so:
At a glance this looks fine but if you stare at it for a bit it doesn't. The "Filters" title isn't actually centered because (I assume) of the width of the X-button. I am struggling to figure out how to deal with this.
What is the proper way to solve this?
You can add empty SizedBox with width as much as IconButton takes, try this:
Row(
children: [
SizedBox(
width: width: 24 +
8 +
8, // the default size of icon + two default horizontal padding for IconButton
),
Expanded(
child: Text(
"Filters",
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () {
Navigator.pop(context);
},
),
],
),
or you can add on other IconButton with opacity 0 to hide the button and make title center, like this:
Row(
children: [
Opacity(
opacity: 0,
child: IconButton(
icon: const Icon(Icons.close),
onPressed: () {},
),
),
Expanded(
child: Text(
"Filters",
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () {
Navigator.pop(context);
},
),
],
),
I have a widget that builds a list from an array. Each item in the array builds a widget with some columns and rows. I want the text to break so It doesnt overflow.
I've tried adding overflow: TextOverflow.ellipsis to the Text or wrapping the Row that wraps the icon and the text that overflow with a Expanded widget, but both didn't work.
Actually it looks like this:
This is my code:
child: Column(
verticalDirection: VerticalDirection.down,
textBaseline: TextBaseline.alphabetic,
textDirection: TextDirection.ltr,
children: < Widget > [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: < Widget > [
Row(
children: [
const Icon(Icons.medication),
//
// This is the text that overflows
//
Text(
entries[index].pillname,
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
],
),
Text(
entries[index].pillTimeStr,
style: const TextStyle(
fontSize: 28,
color: Color.fromARGB(255, 79, 79, 79),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: < Widget > [
Container(
margin: const EdgeInsets.all(4),
child: FloatingActionButton(
onPressed: () {
setState(() {
entries[index].pilldone = !entries[index].pillDone;
});
},
tooltip:
entries[index].pillDone ? 'Tomada' : 'No tomada',
backgroundColor: entries[index].pillDone ?
Colors.green :
Theme.of(context).primaryColor,
child: const Icon(Icons.check),
),
),
Container(
margin: const EdgeInsets.all(4),
child: FloatingActionButton(
onPressed: () {
showAdaptiveActionSheet(
context: context,
cancelAction: CancelAction(
title: const Text('Cancelar'),
),
actions: < BottomSheetAction > [
BottomSheetAction(
title: const Text('Modificar'),
onPressed: () {}),
BottomSheetAction(
title: const Text('Eliminar'),
onPressed: () {
Navigator.pop(context);
_askRemovePill(entries[index].iD);
}),
]);
},
tooltip: 'Eliminar',
backgroundColor: Colors.blue,
child: const Icon(Icons.mode_edit),
)),
],
),
],
),
In your case, all you need to do is wrap your Text inside the Row with an Expanded widget
Expanded(
child: Text(/*......your text widget........*/),
),
The Expanded widget gives your Text widget horizontal constraints
IF you don't wish to see the text go on to the next line,
use the overflow property on the text
overflow : TextOverflow.ellipsis, //inside Text
Use the Wrap widget instead of the Row widget. It will break the text to the next line should there be an overflow.
Like this,
Wrap(
children: [
const Icon(Icons.medication),
//
// This is the text that overflows
//
Text(
entries[index].pillname,
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
],
),
Text(
entries[index].pillTimeStr,
style: const TextStyle(
fontSize: 28,
color: Color.fromARGB(255, 79, 79, 79),
),
),
],
),
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: const Icon(Icons.home),
automaticallyImplyLeading: true,
title: const Text('test app'),
foregroundColor: Colors.black,
actions: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.menu),
),
],
),
body: Container(
child: Column(
children: [
Row(
children: [
const Text(
'New',
style: TextStyle(
color: Colors.black54,
fontSize: 40,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic,
height: 2,
shadows: [
Shadow(color: Colors.black12, offset: Offset(4, 10))
]),
),
ElevatedButton.icon(onPressed: (){}, icon: Icon(Icons.navigate_next),label: Text(' '),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.grey),
),
),
],
),
Row(),
],
),
),
),
);
}
use the Row widget properties for laying out its childrens
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [....]
)
the official docs are helpful in that matter
https://api.flutter.dev/flutter/widgets/Row-class.html
sidenote: if you are not planning to use any of the first container() properties then its better to get rid of it
There are 4 options u can use depending on what you want
If u want it below new u can use Column instead of Row .
If u want to put some space next to new u can use SizedBox(width:X) between the Text and the elevated button.
You can use mainAxisAlignment or crossAxisAlignment inside the row or column to customize the position
you can find examples about them here https://docs.flutter.dev/development/ui/layout
you can use margin or padding on elevated button to customize its own position
How can I reduce spacing between button ?
You can see four buttons on app bar takes so much space, I have tried Rows. but not worked
Below is my code --
AppBar(
backgroundColor: Colors.deepOrange,
iconTheme: new IconThemeData(color: Colors.white),
title: Text(
titleString,
style: TextStyle(color: Colors.white),
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.search,
color: Colors.white,
),
//iconSize: 20,
onPressed: null,
),
IconButton(
icon: Icon(
Icons.notifications_none,
color: Colors.white,
),
// iconSize: 20,
onPressed: null,
),
//Add more icon here
],
);
You can use VisualDensity and padding arguments together to reduce things:
actions: <Widget>[
IconButton(
visualDensity: VisualDensity(horizontal: -4.0, vertical: -4.0),
padding: EdgeInsets.zero,
icon: Icon(
Icons.search,
color: Colors.white,
),
//iconSize: 20,
onPressed: null,
),
//Add more icon here
],
This worked in my app at least. Hope it's helpful!
The problem is with the IconButton Widget. by default IconButton has a size of 48x48 pixels size and you can read about it in the top answer of this question.
A workaround would be to use the GestureDetector widget to handle your onPressed() method. Below is an example.
actions: <Widget>[
GestureDetector(
onTap: (){
//your code
},
child: Icon(Icons.search)
),
GestureDetector(
onTap: (){},
child: Icon(Icons.notifications)
)
//Add more icon here
],
Try using sizedbox
Example
Padding(
padding: const EdgeInsets.all(5.0),
child: SizedBox.fromSize(
size: Size(25, 20), // button width and height
child: InkWell(
splashColor: Colors.white, // splash color
onTap: () {}, // button pressed
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.search), // icon
],
),
),
),
),
I want to place two icons, side by side on the "trailing" side of a ListTile. I tried adding a Row widget with the two icons inside, but it completely messed up the layout of the entire ListTile, making it unusable. Is there any way to expand the space allocated for the trailing part?
Here's the code:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.play_arrow,),
title: Text("This is a title"),
subtitle: Text("This is subtitle"),
trailing: Row(
children: <Widget>[
Icon(Icons.flight),
Icon(Icons.flight_land)
]),
)
]
),
),
);
}
}
This is how it looks like:
Adding mainAxisSize: MainAxisSize.min to the Row() instance fixes the issue.
You can simply use Wrap in trailing
ListTile(
title: Text("This is my ListTile"),
trailing: Wrap(
spacing: 12, // space between two icons
children: <Widget>[
Icon(Icons.call), // icon-1
Icon(Icons.message), // icon-2
],
),
)
Try this code. I think this is working correctly:
trailing: FittedBox(
fit: BoxFit.fill,
child: Row(
children: <Widget>[
Icon(Icons.flight),
Icon(Icons.flight_land),
],
),
),
I took advantage of the FittedBox solution left above and solved my problem by displaying a TextButton and an IconButton when the screen is in landscape and when in portrait mode, only IconButton
trailing: MediaQuery.of(context).size.width > 480
? FittedBox(
fit: BoxFit.fill,
child: Row(
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
// padding: const EdgeInsets.all(16.0),
primary: Theme.of(context).errorColor,
textStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold),
),
onPressed: () => onRemove(tr.id),
child: const Text('Excluir'),
),
IconButton(
icon: Icon(Icons.delete),
color: Theme.of(context).errorColor,
onPressed: () => onRemove(tr.id),
),
],
),
)
: IconButton(
icon: Icon(Icons.delete),
color: Theme.of(context).errorColor,
onPressed: () => onRemove(tr.id),
),
Given negative value to spacing did the trick:
trailing: Wrap(
spacing: -16,
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {},
),
IconButton(
icon: const Icon(
Icons.delete,
color: Colors.redAccent,
),
onPressed: () {},
),
],
),