i'm new to flutter and wanted to ask how to perform the bottom centre overflow the container in the stack widget. I'm tried but have not been able to get the expected result that I want.
Actual Result:
Expected Result:
Position(
bottom: 0, // 0 means at the bottom of defined Spaces by its Parent Widget
)
if you want to access over that spaces than u can use negative value.
Position(
bottom: -0 to ...... any as u desired
)
** but remember one thing usually Stack doesn't allow to show that overflowed area, as it initially defined "clipBehavior: false", so to change this
Stack(
clipBehavior: Clip.none,
children:[ Position(bottom: -50)]
)
here is what you need:
class ProfileLayout extends StatelessWidget {
const ProfileLayout({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Stack(
alignment: AlignmentDirectional.topCenter,
children: [
Container(
height: 200,
color: Colors.blue[100],
),
Column(
mainAxisSize: MainAxisSize.min,
children: const [
SizedBox(height: 150,),
SizedBox(
height: 100,
width: 100,
child: Placeholder()),
],
)
],
),
);
}
}
as you see, when you want to use Stack, imagine that every child in Stack is a separate screen.
please attention to code that you have a Container with height of 200,
and your Placeholder you are showing is separated. and because your placeholder height is 100 you need to have SizedBox(height: 150,).
happy coding...
Stack(
children: [
Positioned(
left: 20.0,
top: 20.0,
child: Text('Child Widget 1'),
),
Positioned(
right: 20.0,
bottom: 20.0,
child: Text('Child Widget 2'),
),
],
)
Related
I have a Flutter app which I'm building for Android. The structure goes broadly like this:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("")),
body: SingleChildScrollView(
child: Container(
decoration: const BoxDecoration(
gradient: ...
),
child: ...
),
)
);
}
The goal here is to have the gradient background fill all the screen below the app bar, and if the content is larger than that space then to make it scrollable.
If I omit the SingleChildScrollView, the Container fills the space. But of course if it overflows then there is no scrolling. With the code as above, the scroll view does its thing on small screens but on large screens the gradient background doesn't fill the whole available area.
If I change it around like this:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("")),
body: Container(
decoration: const BoxDecoration(
gradient: ...
),
child: Column(children: [
SingleChildScrollView(
child: ...
),
Expanded(child:Container())
]),
)
);
}
then the gradient fills the background but the scroll view doesn't do the right thing - the content overflows the screen but can't be scrolled. How do I get it to do both?
The reason you're facing this issue is that your container is inside the SingleChildScrollView Widget and is getting scrolled along the SingleChildScrollView Widget. And Removing the SingleChildScrollView will result in renderflex overflow error
The Expanded keyword will throw incorrect use of ParentDataWidget
Also, you have added SingleChildScrollView widget inside the column you have to swap these well
Here is an example that I have given which will help you achieve it.
Widget build(BuildContext context) {
return Scaffold(
body: Container(
// Add The Container gradient here
width: double.infinity,
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
child: Column(
children: [
Container(
height: 100,
width: 50,
color: Colors.red,
),
Container(
height: 100,
width: 50,
color: Colors.blue,
),
Container(
height: 1000,
width: 50,
color: Colors.yellow,
),
Container(
height: 1000,
width: 50,
color: Colors.orange,
),
],
)),
));
}
I have a text element which should be aligned to the left but for some reason it appears centered and I can't figure out why.
What code should be changed / added to make the result string aligned to the right?
return Positioned(
bottom: 0,
right: 0,
left: 0,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.fromLTRB(10, 0, 10, 30),
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
//First row here. The one below is the second row:
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 5.0),
child: Icon(Icons.comment),
),
Expanded(
child: Column(children: [
Padding(
padding: EdgeInsets.only(
top: 10.0, left: 5.0, right: 0),
child: Text(
result, //This text is centered. Why?
maxLines: 7,
overflow: TextOverflow.ellipsis,
)),
]),
)
],
),
],
)
)
)
);
It's because row or column alignment.
By default column is centering children, to change that update:
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
...
If this does not solve your problem check:
Under which circumstances textAlign property works in Flutter?
More info on column/row alignment:
https://medium.com/jlouage/flutter-row-column-cheat-sheet-78c38d242041
You can use direction for this purpose.
For example:
MaterialApp(
builder: (context, child) {
return Directionality(
textDirection: TextDirection.rtl,
child: child,
);
},
);
In accordance to https://api.flutter.dev/flutter/widgets/Column-class.html on Column-Class, the Column widget does not scroll (and in general it is considered an error to have more children in a Column than will fit in the available room). If you have a line of widgets and want them to be able to scroll if there is insufficient room, consider using a ListView. For a horizontal variant, see Row.
Also, if you only have one child, then consider using Align or Center to position the child.
For your case, you could add the property crossAxisAlignment to your column as following
... Column(crossAxisAlignment: CrossAxisAlignment.end, ...
as mentioned by #nuts so the text will be align right. Here is a full example also from the above reference under https://api.flutter.dev/flutter/widgets/Expanded-class.html, that i just modified to illustrate how to do it:
/// Flutter code sample for Expanded
// This example shows how to use an [Expanded] widget in a [Column] so that
// its middle child, a [Container] here, expands to fill the space.
//
// ![This results in two thin blue boxes with a larger amber box in between.](https://flutter.github.io/assets-for-api-docs/assets/widgets/expanded_column.png)
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({
Key ? key
}): super(key: key);
static
const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatelessWidget(),
);
}
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({
Key ? key
}): super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Expanded Column Sample'),
),
body: Center(
child: Column(
children: < Widget > [
Container(
color: Colors.blue,
height: 100,
width: 100,
),
Expanded(
child: Container(
color: Colors.amber,
width: 100,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: < Widget > [
Text('We moved this text to the right')
],
),
Container(
color: Colors.blue,
height: 100,
width: 100,
),
],
),
),
);
}
}
Hope, this will help!
I'm quite seeing the effect of MainAxisSize but I don't understand its purpose. Please explain like I'm 5. Thank you.
For further reference:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Color(0xffEDE7F6),
body: SafeArea(
child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Container(
height: 100,
width: 100,
color: Color(0xff9575CD),
child: Text('Container 1'),
),
Container(
height: 100,
width: 100,
color: Colors.black45,
child: Text('Container 2'),
),
Container(
height: 100,
width: 100,
color: Colors.black12,
child: Text('Container 3'),
),
]),
),
),
);
}
}
Output on emulator:
Let's say you have a container of height 400 wrapped around a column containing 3 rows of height 100 (either defined by height or intrinsic by what is in there), that leaves you 100pt of height unused.
MainAxisSize.max says, distribute all space between the column's items, so create spaces of 50 between the rows.
MainAxisSize.min says, squeeze the rows together and leave unused space (100) at the end (or beginning or both ends depending on alignment)
I've very much a beginner in Dart and Flutter, and my project is to learn while building an app. I've learned the basics with an online class and I have basis in Java.
Now, in my homepage, I'm trying to have 4 buttons take the whole screen. My current layout is to have them all take an equal amount of space and be stacked vertically.
Problem is, I can't find a way to make the RaisedButton fill automatically. I've tried retrieving the height of the screen and dividing that between the buttons but it's not working. Here's how I do it :
First, the homescreen layout:
class Homescreen extends StatelessWidget {
Widget build(context) {
double height = MediaQuery.of(context).size.height - 60;
return Scaffold(
body: SafeArea(
child: ListView(
children: [
PlanningButton(height),
Container(margin: EdgeInsets.only(top: 20.0)),
BookingButton(height),
Container(margin: EdgeInsets.only(top: 20.0)),
ModifyButton(height),
Container(margin: EdgeInsets.only(top: 20.0)),
CancelButton(height),
],
),
),
);
}
As you can see, I pass the height argument to my buttons all built around this model:
Widget PlanningButton(double pixel_y) {
return RaisedButton(
padding: EdgeInsets.all(pixel_y / 8.0),
onPressed: () {}, //goes to the planning screen
color: Colors.blue[200],
child: Text("Planning"),
);
}
Yet, it's never quite right. I don't think it's taking into account the notification bar or the navigation bar.
I suspect there is a workaround that involves wrapping the buttons into a container or using a different kind of widget that have button-like properties but I can't find what suits my needs.
Thanks for any help !
edit: I'm basically trying to do this
Try removing the variable height logic, and simply wrap your buttons in Expanded widgets. This is pretty much what it was built for.
Check it out here: https://api.flutter.dev/flutter/widgets/Expanded-class.html
You could use a Column and Expanded to do the job. If you want to make your Column scrollable, you can wrap it with SingleChildScrollView. I used SizedBox instead of Container to make the spacing because it is way more efficient and is designed for it.
class Homescreen extends StatelessWidget {
Widget build(context) {
double height = MediaQuery.of(context).size.height - 60;
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: PlanningButton(height)
),
SizedBox(height:20),
Expanded(
child: BookingButton(height),
),
SizedBox(height:20),
Expanded(
child: ModifyButton(height),
),
SizedBox(height:20),
Expanded(
child: CancelButton(height),
),
],
),
),
);
}
If 4 buttons are the only widgets, you dont need to use ListView just use a Column with mainAxisAlignment: MainAxisAlignment.spaceEvenly
class Sample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Container(
color: Colors.red,
child: Center(
child: RaisedButton(
onPressed: () {},
child: Text("button"),
),
),
),
),
Expanded(
child: Container(
color: Colors.blue,
child: Center(
child: RaisedButton(
onPressed: () {},
child: Text("button"),
),
),
),
),
Expanded(
child: Container(
color: Colors.green,
child: Center(
child: RaisedButton(
onPressed: () {},
child: Text("button"),
),
),
),
),
Expanded(
child: Container(
color: Colors.yellow,
child: Center(
child: RaisedButton(
onPressed: () {},
child: Text("button"),
),
),
),
),
],
),
),
);
}
}
Before you read this, it's not the best way to do things but it's one I'm using at least for prototyping. You may find using a container with a list and the argument MainAxisAlignment to work better for you.
A lot of comments here might give a solution that works for you but here's mine. I got it to work like I wanted by using SizedBox.
First, I recovered the width of the screen, then I created the buttons and put them into SizedBox fitting the screen's width, I put them in a Column and I added a few Container for the style points.
Result:
Code :
class Homescreen extends StatelessWidget {
Widget build(context) {
double width = MediaQuery.of(context).size.width; //getting screen width
return Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(margin: EdgeInsets.only(bottom: 20.0)),
PlanningButton(width),
Container(margin: EdgeInsets.only(bottom: 20.0)),
BookingButton(width),
Container(margin: EdgeInsets.only(bottom: 20.0)),
ModifyButton(width),
Container(margin: EdgeInsets.only(bottom: 20.0)),
CancelButton(width),
Container(margin: EdgeInsets.only(bottom: 20.0)),
],
),
),
);
}
Widget PlanningButton(double width) {
return Expanded(
child: SizedBox(
width: width - 20,
child: RaisedButton(
onPressed: () {},
color: Colors.blue,
child: Text(
"planning",
textScaleFactor: 4.0,
),
),
//fit: BoxFit.cover,
),
);
}
The user can tap anywhere on the colored buttons and it will register. Now I'll add images and transparency to make it look good!
Building a hero animation for list->detail, with responsive layouts for screen sizes.
Initially upon transitioning I get a brief renderflex error then it adjusts and is fine.
I solved this with the column (phone) layout with a ListView but the other layout is a row (side by side screens). No matter what combination of flexes and expanded and Lists and every other widget I could think of, I can't get it solved. Thanks
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
child: Hero(
tag: content.timestamp,
child: MediaQuery.of(context).size.width < 600
? ... Column layout
: Row(
children: [
FadeInImage.assetNetwork(
placeholder: 'assets/icons/barc-lodge.png',
image: 'https://www.barclodge.ca/android/diary/${content.image}',
width: 300,
),
// Expanded exists to wrap text
Expanded(
child: diaryContent(context, content),
),
],
),
),
onTap: () => Navigator.pop(context),
),
);
}
Widget diaryContent(BuildContext ctx, BarcLodgeDiary words) {
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(12.0, 12.0, 0.0, 0.0),
child: Text(words.title, style: Theme.of(ctx).textTheme.headline1),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Text('${words.datestamp} at ${words.timestamp}', style: Theme.of(ctx).textTheme.caption),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: Text(words.diaryentry, style: Theme.of(ctx).textTheme.bodyText1),
),
],
);
}
This might be your issue. The Hero widget needs a Material widget inside it to provide a canvas for the splash, you can read about it in the docs here. The section is about building your own hero widget but I think it still applies, if this doesn't fix your issue, try wrapping the Hero widget with the Material widget.
One thing I did not try apparently in a couple hours was GridView. Remove the Expanded, change Row to GridView.count and everything is a-ok.