I'm creating a card game and my UI has a Column() with various combinations of children widgets. One child is a Row
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(),
Container(),
],
),
The Container() widgets each display what looks like playing cards. They have BoxDecorationsto provide a border + a child that's a Row(). The Row's children display a number (text) and a suit (image).
I would like to flash text over the two playing cards, something that's visible for just a couple seconds, e.g., "Well done." Although I'm always open to help, I assume this will amount to (Rich)Text() widgets and some sort of timer or Duration object, and that I can figure it out.
What I'm struggling with is figuring out how to create a text overlay that is both on top of and spans the two images. Do I have to do something like wrap the higher level Row() object in a Stack()? I hate all that nesting, plus I don't know how to have the text always be on top of everything else.
I think you are looking for Overlay widget:
Scaffold(
body: Container(child: Overlay(initialEntries: [
OverlayEntry(builder: (_) => Image.network("https://source.unsplash.com/random", fit: BoxFit.cover,)),
OverlayEntry(builder: (_) => Center(child: Text("Overlay", style: TextStyle(color: Colors.yellow),))),
])),
),
For now I am going with (pseudocode):
Stack(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(),
Container(),
],
),
Center(
child: Text(),
),
],
),
With the Row() centered and the child:Text() centered, everything lines up and looks good. I do, however, think I need to spend time and learn about Positioned() widgets. I think that will ultimately be a better solution.
Related
I have a home/login screen which is made up of a column that fills the entire screen like so:
Column(
children: <Widget>[
Expanded(
child: Container(
child: Logo(),
),
),
showThis ? This() : That(),
],
),
The second child of the column is dynamic and can have different heights, and this screen will have inputs so the keyboard will also affect the height.
I want to center Logo() vertically within the container when it's small (e.g. when keyboard is active), but limit how much the 'top margin' is able to grow, so that when the keyboard is hidden and This()/That() is small enough, Logo() will be in a static position on the screen, say 150 from the top (no longer centred vertically).
One method I have tried was using 2 empty Expanded() above and below Logo() and wrapping the top part in a ConstraintedBox(), but I am not able to get it to behave correctly.
Have you tried with Center() and also if you wanna in a specific position use Stack, for example
Stack(
children: <Widget>[
showThis(),
Positioned(top: 150, child: Logo())
],
)
This is what ended up working for me:
Column(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
// constrain top spacing with a max height
Flexible(child: Container(height: 160)),
_logo(),
Spacer(),
],
),
),
_bottomWidget(),
],
),
I'm trying to build an interface in Flutter.
I have a Container with Text (several lines depending on screen size) and a Button.
I also have a List of Widgets that have to be in front of the Container.
The first item of the list has to be below the Container. The List should be able tp scroll over the Container and the Container should fade away (but not move). The button should still be clickable.
I can't find a way to implement it.
Container
Widget container = Container(
child: Column(
children: <Widget>[
Container(child: Text("BlaBlabla ... long line"),
Container(child: Text("BlaBlabla ... another long line"),
Container(child: ButtonWidget(),
],
),
)
List
Widget list = ListView(
children: <Widget>[
CustomWidget(),
CustomWidget(),
CustomWidget(),
],
)
Put together: inside Scaffold Body
Stack(
children: <Widget>[
container,
Positioned(
#don't know height of the container
child: list,
),
],
)
or
Stack(
children: <Widget>[
container,
ListView(
children: <Widget>[
IgnorePointer( #can't click on the real container
child: Opacity(
child: container,
opacity: 0,
),
),
list #as column
],
),
],
)
or
Column(
children:<Widget>[
container,
list, #list can't scroll over the container because the ListView is not the whole body
],
)
edit: I added some of the combinations I thought could have been the solution, but unfortunately, none of them give worked for my intended purpose.
I appreciate any ideas that help.
It should look similar to the pictures below.
I am trying to render a dribbble sample.
In normal android using XML, I can make any part stick to any side of another view. If I were using ConstraintLayout, I could make the bottom part stick to the bottom of the parent and let the top part expand to available height.
The design on both emulators is Flutter code.
On larger screens, there is some empty space on the bottom. How do I remove that?
Currently, I am using Flexible with flex values but it doesn't look right. How to make this reactive?. Is the use of Flexible correct?
The code can found here on pastebin
There is nothing like android:layout_gravity in Flutter, however you can pretty much achieve anything in Flutter. So, here you can use use Spacer(). Like:
return Column(
children: <Widget>[
Spacer(),
Align(alignment: Alignment.centerRight, child: Text("123")),
YourButtonsWidget(),
],
);
try to change CalculatorPrototype's build function like this
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min, // actually this line and the next one doesn't needed
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: display,
),
Container(
child: keypad,
),
],
),
);
}
I am trying to create a Card that displays the score in a game. The card will be more complex than this example, but in the middle of the card I want to have a Row. That Row contains two Columns. The first Column contains two Rows. In each of those two Rows is the team name and the score.
Widget build(BuildContext context) {
return Card(
child: Row(
children: <Widget>[
Column(
children: <Widget>[
Row(
children: <Widget>[
Text('Team A'),
Text('100'),
],
),
Row(
children: <Widget>[
Text('Team B'),
Text('100'),
],
),
],
),
Text('15:00'),
],
),
);
}
Now I want t wrap the Text widgets that display the team name in a Expanded. Once I do that I get a long descriptive error that basically says my Row has a parent that does not have a finite width, but it has a child that is asking to expand and these two are in conflict. I get that they are in conflict. How do I fix it? I definitely don't want to give the parent Widget (the Card) a finite width.
It's not 100% clear what you want the scoreboard to look like - this is an instance where a quick mock-up would be a great help.
However, I can tell you why you're getting an exception.
When you wrap your 'Team A' text in an Expanded, during the layout pass flutter gets confused. The top level row has two items, neither of which define any sort of size, so it makes them as large as possible in the cross axis (vertical) and as small as possible in the main axis (horizontal). This means that they delegate their size to their children.
By wrapping 'Team A' in an Expanded, you're basically telling it:
"Hey you, your parent widget is pretty big. I want you to take up all of it that isn't already being used instead of being how big you would normally be."
It responds with
"Sure boss, but I've just checked and none of my parents actually have
a defined size.... so I don't know what to do. Guess I'll just throw an
exception."
The fix is to size the parent, which in this case is the column that contains the two rows (geez, that's confusing).
I think from your description what you want is for that column to take up as much space as possible, so you just have to wrap it in expanded as well. So if you do this, your problem should resolve itself:
Widget build(BuildContext context) {
return Card(
child: Row(
children: <Widget>[
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
children: <Widget>[
Expanded(child: Text('Team A')),
Text('100'),
],
),
Row(
children: <Widget>[
Expanded(child: Text('Team B')),
Text('100'),
],
),
],
),
),
Text('15:00'),
],
),
);
}
That way, the column containing the two rows expands to take all available space during its layout pass. Once the 'Team A' text gets around to trying its layout pass it can simply size itself (horizontally) to that column.
You can then play around with the flex factor to get everything how you want.
Just an FYI - once you start getting lots of nested containers and rows you might want to consider a CustomMultiChildLayout. It's slightly more manual as you need to do the layout calculations yourself, but it might be easier in the long run depending on how complex your scoreboard is.
I am trying to make a widget take up 1/3 the screen regardless of the phone orientation. How do I accomplish this?
I got what I wanted by using a Column and wrapping the contents in Flexible and changing the flex to get the child to take up 1/3 the screen:
new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Flexible(flex: 2, child: new SizedBox()),
new Flexible(flex: 1, child: createTextBox())
]
);
There's a few widgets that might help: AspectRatio, Column/Expanded, and CustomSingleChildLayout in particular. It's hard to give a good answer without knowing exactly what you want to do though.
You should try using Expanded widgets as the children of your row, like so:
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Expanded(
child: yourFirstContentWidget,
),
new Expanded(
child: yourNextContentWidget,
),
new Expanded(
child: yourLastContentWidget,
)
]
)
The Expanded widgets will each try to fill as much space of the row as possible. Since there are three of them, they will have to share the space and you'll end up with each taking up 1/3 of the row.