Flutter UI: Absolute positioned element with fixed height and 100% width - dart

In flutter, I'd like to have a Container with a fixed height and 100% width.
To accomplish this, I used:
Row(
children: <Widget>[
Flexible(
child: Container(
color: Colors.blue,
height: 40.0,
),
),
],
),
Now, I'd like to offset this row a few pixels offscreen. To accomplish this, I'm attempting to use:
Stack(
children: <Widget>[
Positioned(
left: -5.0,
child: Row(
children: <Widget>[
Flexible(
child: Container(
color: Colors.blue,
height: 40.0,
),
),
],
),
),
],
),
This gives me the error:
The following assertion was thrown during performLayout(): RenderFlex children have non-zero flex but incoming width constraints are unbounded.
How would I create this layout effect?

Try giving specific size of children widgets. Positioned widget can't have flexible size of children.
So I gave screen width to Positioned(parent widget) and height 40. And you just need to give width of each children in Row. If you want to give them some flexible relationship, try MainAxisAlignment property inside Row widget.
Here is my example.
Positioned(
width: MediaQuery.of(context).size.width,
height: 40.0,
left: -5.0,
child: Container(
color: Colors.grey,
child: Row(
children: <Widget>[
Container(
color: Colors.green,
width: MediaQuery.of(context).size.width / 3,
child: Center(
child: Text("Green")
),
),
Container(
color: Colors.pink,
width: MediaQuery.of(context).size.width / 3,
child: Center(child: Text("Pink"))
),
Container(
color: Colors.blue,
width: MediaQuery.of(context).size.width / 3,
child: Center(child: Text("Blue")),
)
],
),
),
),

If you have a scenario where you don't want to set a fixed width for your children, you can set left and right both to 0 to stretch the Positioned element to the full width:
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(child: Text('Previous'), onPressed: () => {}),
ElevatedButton(child: Text('Next'), onPressed: () => {}),
],
),
),
You can also achieve the same effect with Positioned.fill() (passing null or a value for properties you want to override. https://api.flutter.dev/flutter/widgets/Positioned/Positioned.fill.html
https://youtu.be/EgtPleVwxBQ?t=66
Positioned.fill(
top: null,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(child: Text('Previous'), onPressed: () => {}),
ElevatedButton(child: Text('Next'), onPressed: () => {}),
],
),
),

Related

How to make slider discrete?

How to make slider discrete look like image above in Flutter?
slider discrete
Use the divisions property of the Slider widget to divide it into equal portions, then you have to put Text widgets under them:
Container(
width: MediaQuery.of(context).size.width,
height: 200.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Slider(min: 0.0, max: 1.0, divisions: 9, value: 0.0, onChanged: null); // you have to provide an `onChanged` function to let slider pointer change place, and to execute other related actions.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
child: Text('6'),
),
Container(
child: Text('7'),
),
Container(
child: Text('8'),
),
Container(
child: Text('9'),
),
Container(
child: Text('10'),
),
Container(
child: Text('11'),
),
Container(
child: Text('12'),
),
Container(
child: Text('13'),
),
Container(
child: Text('14'),
),
]
),
]),
)

Positioned Widget in Column Causes Card to Overflow

I am currently learning flutter and have come across an issue where the card is not staying within the boundaries of Column, but is not causing an overflow. My goal is to have the card positioned at the bottom and with Text positioned above the card.
Here is my code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height,
child:
Image.asset("assets/testimage.jpg", fit: BoxFit.cover)),
Positioned(
bottom: 10.0,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
child: Text(
"A description would be going here, this is just placeholder text.",
style: TextStyle(fontSize: 30),
),
),
)
],
),
],
),
),
);
}
}
and an image example of the problem and desired outcome
Problem
Desired Outcome
You need to define - right: 1.0, left: 1.0, also along with bottom in Positioned. widget.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height,
child: Image.network("https://placeimg.com/640/480/any",
fit: BoxFit.cover)),
Positioned(
bottom: 1.0,
right: 1.0,
left: 1.0,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"A description would be going here, this is just placeholder text.",
style: TextStyle(fontSize: 30),
),
),
),
)
],
),
],
),
);
}
Output:

fitting texts inside a stack

I have a stack contains two texts .. sometimes one of the text is really long and it will be in two lines like this:
So i tried to use FittedBox like this:
new Container(
height: 44.0,
decoration: BoxDecoration(
borderRadius: BorderRadius
.all(const Radius
.circular(30.0)),
border: new Border.all(
color:
Color(0xff606060),
width: 2.5),
),
child: new Stack(
children: <Widget>[
Align(
alignment: globals
.currentLang ==
'ar'
? Alignment
.centerRight
: Alignment
.centerLeft,
child: Padding(
padding:
EdgeInsets.only(
right: 15.0,
left: 15.0),
child: FittedBox(
fit: BoxFit
.contain,
child: Text(
),
),
),
),
Align(
alignment: globals
.currentLang ==
'ar'
? Alignment
.centerLeft
: Alignment
.centerRight,
child: Padding(
padding:
EdgeInsets.only(
left: 15.0,
right:
15.0),
child: new Text(
),
),
),
],
),
),
and i got this result:
I want a space between the two texts so it will not be covered by each other .. how to solve this?
UPDATE:
UPDATE 2:
Check this solution if it is ok for you to scale only text aligned to the right.
Container(
height: 44.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(const Radius.circular(30.0)),
border: Border.all(color: Color(0xff606060), width: 2.5),
),
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Text('Some text'),
SizedBox(width: 8.0),
Expanded(
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
'Demo text. Long demo text. Duplicated long demo text.',
textAlign: TextAlign.end
)
)
)
],
),
)
UPDATE:
Flex instead of Row and Expanded looks better. Check it out
Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(child: Text('10%'), flex: 0, fit: FlexFit.tight,),
SizedBox(width: 8.0),
Flexible(
flex: 1,
fit: FlexFit.loose,
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
'Demo text. Demo text. Demo text. Demo text. Demo text.',
textAlign: TextAlign.start
),
)
)
],
)

A problem in using ClipRRect() in Flutter

I have used ClipRRect for rounded corners in the UI. The ClipRRect wraps topContent and bottomContent are a stack and a Column respectively. But, the bottom corners are not round. What may be the reason behind this?
The cardModel class is used to store the image path in this case.
class FeaturedCard extends StatelessWidget {
final FeaturedCardModel cardModel;
final double parallaxPercent;
FeaturedCard({
this.cardModel,
this.parallaxPercent = 0.0, //default value
});
#override
Widget build(BuildContext context) {
final topContent = Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(
left: 10.0,
),
height: MediaQuery.of(context).size.height * 0.3,
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(cardModel.imgUrl),
fit: BoxFit.fill,
),
)),
],
);
final bottomContentText = Text(
'This is the sample text',
style: TextStyle(fontSize: 18.0),
);
final bottomContent = Container(
height: MediaQuery.of(context).size.height * 0.5,
width: MediaQuery.of(context).size.width,
color: Colors.white,
padding: EdgeInsets.all(40.0),
child: Center(
child:
bottomContentText,
),
);
return ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Column(
children: <Widget>[
topContent,
bottomContent,
],
),
);
}
}
If you go to Flutter Inspector and do "Toggle Debug Paint" you will see that the clipping occurs in the blue area below.
You can fix it by giving a size to your clipper.
return SizedBox(
height: MediaQuery.of(context).size.height * 0.8,
child: ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Column(
children: <Widget>[
topContent,
//bottomContent,
],
),
),
);
The column that is the child of ClipRRect is taking as much space as it can get. so the border radius is applied to the bottom of the screen.
to solve that you just need to set mainAxisSize property of Column to MainAxisSize.min:
return ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
topContent,
bottomContent,
],
),
);

How to overlay a view partially using the Stack widget in Flutter

I am using Flutter for my app development.
I would like to overlay a poster image view on top of a background image just like in this screenshot below.
The code snippet below does this, but it requires me to also position every other widget including the movie title, release date, etc based on poster's position and background image's position, which is not reliable across several devices and orientation. Is there an example or suggestion to solve this problem?
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new PlatformAdaptiveAppBar(
title: new Text(widget.movie.title),
),
body: new Container(
constraints: new BoxConstraints.expand(),
child: new Stack(
children: <Widget>[
new Container(
child: new Image(
image: new AdvancedNetworkImage(
movieGridUtil.getUrlFromPath(widget.movie.backdrop_path,
MovieGridImageTypes.BACKDROP),
useMemoryCache: false,
useDiskCache: true)),
constraints: new BoxConstraints.expand(height: 250.0),
),
new Positioned(
left: 12.0,
top: 220.0,
child: new Image(
width: 100.0,
height: 150.0,
image: new AdvancedNetworkImage(
movieGridUtil.getUrlFromPath(widget.movie.poster_path,
MovieGridImageTypes.POSTER),
useMemoryCache: false,
useDiskCache: true),
)),
],
)),
);
}
Create Stack
Then inside Stack add Column and make full layout without the poster.
Then as a second Child of Stack, add this combination:
new Stack(
children: [
new Column(
children: _layout()
new Positioned(
top:200,
left:50,
child: _child // or optionaly wrap the child in FractionalTranslation
)]
)
)
Stack(
children: <Widget>[
Container(
color: Colors.blue,
height: 200.0,
),
Padding(
padding: const EdgeInsets.only(left: 20.0,right: 20.0, top:160.0),
child: Container(
color: Colors.pink,
height: 150.0,
width: 110.0,
),
)
],
),
By Creating the Stack,
You can add multiple Container, whichever is last added will be on the top.
Stack(
children: <Widget>[
Container(
color: Colors.blue,
height: 200.0,
),
Padding(
padding: const EdgeInsets.only(left: 20.0,right: 20.0, top:160.0),
child: Container(
color: Colors.pink,
height: 150.0,
width: 110.0,
),
)
],
),

Resources