Stack() Widget not centering all sub widgets flutter - flutter

I have a Text() widget I am trying to stack on a CircularProgressIndicator()
I thought it would be as simple as just wrapping them both in a Stack() widget but the text is not centered.
I tried wrapping the Text() in a Center() widget but that did not solve the issue:
return Expanded(
child: PageView(
controller: pageViewController,
children: [
PackSummaryWeightGraph(
categoryWeightList: categoryWeightList,
totalWeight: totalWeight),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Stack(
children: [
Text((packedItemsPercent * 100)
.toString()),
SizedBox(
height: 150,
width: 150,
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
],
),
),
],
),
const Center(
child: Text('Third Page'),
),
],
),
);
Bonus points if there is a way to have the CircularProgressIndicator() fill the space without hard coding its width and height...

Stack has an alignment argument:
Stack(
alignment: Alignment.center,
children: [...],
),
If you want to fill the given space use the SizedBox.expand constructor:
SizedBox.expand(
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
One issue with the above is that if the available space has a different height than width you will end up with an oval shaped indicator rather than a circle. You can avoid this by wrapping it in an AspectRatio widget:
AspectRatio(
aspectRatio: 1,
child: SizedBox.expand(
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
),
See complete demo:
import 'package:flutter/material.dart';
void main() {
double packedItemsPercent = .67;
runApp(
MaterialApp(
home: Scaffold(
body: Stack(
alignment: Alignment.center,
children: [
Text((packedItemsPercent * 100).toString()),
AspectRatio(
aspectRatio: 1,
child: SizedBox.expand(
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
),
],
),
),
),
);
}
Make sure that any widget like Expanded or SizedBox.expand is not inside of an infinite sized container like a ListView or similar. Expanded means to take up the maximum available space, but that isn't possible if you have an infinite amount of space.

You'll need to set the alignment of the Stack to center:
Stack(
alignment: Alignment.center,
children: [
// ...
],
);
To get the circular progress indicator to fill the space, you should be able to use a FittedBox with a Positioned.fill widget:
Stack(
children: [
Positioned.fill(
child: FittedBox(
fit: BoxFit.fill,
child: CircularProgressIndicator(
value: packedItemsPercent
),
),
),
],
);

Related

flutter layout in singlechildscrollview

I have the below layout and want to push CustomPaints at the end of the page for any screen size, how to achieve that? I tried Spacer but got an error and tried Flexible but I don't know how to use them properly.
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
const HeaderShape(),
const SizedBox(
height: 50,
),
body,
SizedBox(
height: 150,
child: Stack(
children: [
CustomPaint(
painter: const FooterPainter1(),
child: Container(),
),
CustomPaint(
painter: const FooterPainter2(),
child: Container(),
),
],
),
),
],
),
),
);
}
You can not use spacer in a column widget, if you did not wrap your column widget with a container/sizedBox with a definite height.
Flexible widget will wrap your widget to take the available space of the parent widget, but will NOT force the child to fit the space.
Expanded will share the available space of the parent widget, and force the child widget to change its width/height to fill the available space.
So, wraping you column with a sizedbox with height and using spacer widget will help you to achieve what you are looking for. Check the code below:
SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height -kToolbarHeight - MediaQuery.of(context).padding.top -MediaQuery.of(context).padding.bottom,
child: Column(
children: [
Container(child: Text('My Header')),
const SizedBox(
height: 50,
),
Container(child: Text('My Body')),
Spacer(),
Container(child: Text('My Footer')),
],
),
),
)
If you are not using appbar in your page, just remove kToolbarHeight and MediaQuery.of(context).padding.top from your SizedBox height parameter.

SizedBox() not increasing size of CircularProgressIndicator()

I was having issues increasing the size of my circular progress indicator and after doing some research I landed on this Stack Overflow question: How to set size to CircularProgressIndicator?
So I wrapped my item in a SizedBox() and increased the height and width and nothing changed.
I Also tried adding an expanded to the circular progress indicator but that didnt work either:
return Expanded(
child: PageView(
controller: pageViewController,
children: [
PackSummaryWeightGraph(
categoryWeightList: categoryWeightList,
totalWeight: totalWeight),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 40,
width: 40,
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
],
),
const Center(
child: Text('Third Page'),
),
],
),
);
Edit:
IS there anyway to do this programmatically so I do not need to set the size of the width and height manually? I just want it to fill the space.
It needs a parent with constraint, try to wrap it inside a Center or Align
Center(
child: SizedBox(
height: 40,
width: 40,
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
),
Try wrapping the CircularProgessIndicator in a FittedBox like so:
SizedBox(
height: 40,
width: 40,
child: FittedBox(
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
)

Flexible scrolling content on overflow

I want to have a container with a flexible body (red) height and a fixed button height (gray).
The complete container should be as small as possible and have a max height.
If the content is overflowing the max height it should be scrollable.
I'm new to flutter, so I have no idea how to achieve this.
I tried it with a ConstraintBox with maxHeight, but then the whole container is bigger then it have to be, when the content is small.
return Container(
child: Column(
children: [
ConstrainedBox(
maxHeight: 400
child: //SomeWidget that could overflow
),
Container(
height: 150,
child: Center(
child: TextButton(child: Text('OK'))
),
)
],
),
);
Can someone help?
You can set constraints of your Container. Also you can use Flexible and SingleChildScrollView
Container(
constraints: BoxConstraints(
maxHeight: 300,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: SingleChildScrollView(
child: Column(
children: [
//SomeWidget that could overflow
],
),
)),
Container(
color: Colors.amber,
height: 150,
child:
Center(child: TextButton(onPressed: () {}, child: Text('OK'))),
)
],
),
)
I've achieved it now, with that code:
Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: SingleChildScrollView(
child: //SomeWidget that could overflow
),
),
Container(
alignment: Alignment.bottomCenter,
child: TextButton(
child: Text('OK')
)
)
]
)
)
According to your UI i think this one will be perfect, and let me know if you need any changes. use constraints to change size.
final widgets = List.generate(
12,
(index) => Container(
height: 100,
color: index % 2 == 0 ? Colors.cyanAccent : Colors.greenAccent,
child: Text("item $index"),
),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => Stack(
children: [
Align(
alignment: Alignment.topCenter,
child: SizedBox(
///* used 90% of screen for items
height: constraints.maxHeight * .9,
child: ListView(
children: [
Center(child: Text("inside listView")),
///your widgets
...widgets,
Center(child: Text("End of listView")),
],
),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
color: Colors.grey.withOpacity(.3),
///* used 10% of screen for Button
height: constraints.maxHeight * .1,
child: Center(
child: TextButton(
child: Text('OK'),
onPressed: () {},
),
),
),
),
],
),
),
);
}

Clipping a row child in flutter

I want to achieve this
This is my code
Row(
children: [
Expanded(
flex: 1,
child: Text(
"somethinig here..."),
),
Expanded(
child: ClipRect(
child: Wrap(
children: [
SvgPicture.asset(
"assets/3958830.svg",
width: autoHeight(550),
allowDrawingOutsideViewBox: true,
fit: BoxFit.fitHeight,
),
],
),
),
),
],
),
Result:
You can see how the image is clipped, I just want to clip all sides except the left side.
You can wrap the image widget with an Align widget to easily position the image inside the clipper. The widthFactor and heightFactor properties are used to decide the size of the clipper and alignment is used to decide the position of the `clipper
A Nice Example to use the Align Widget with ClipRect will be
ClipRect(
child: Container(
child: Align(
alignment: Alignment.centerLeft,
widthFactor: 0.6,
heightFactor: 1.0,
child: Image.network(
'https://images.unsplash.com/photo-1473992243898-fa7525e652a5'
),
),
),
);
To Know More about the Clippers see This Article
Just wrap your Text widget with Center.
And SvgPicture with Align. (I realize this later.)
Row(
children: [
Expanded(
flex: 1,
child: Center(child: Text("somethinig here...")),
),
Expanded(
child: ClipRect(
child: Wrap(
children: [
Align(
alignment: Alignment.centerRight,
child: SvgPicture.asset(
"assets/3958830.svg",
width: autoHeight(550),
allowDrawingOutsideViewBox: true,
fit: BoxFit.fitHeight,
)),
],
),
),
),
],
)

Is there a way to keep the aspect ratio of multiple Widgets in a Row (Flutter)?

I am using a Row to align two Widgets (VideoControllers) horizontally. Using Expanded and its flex attribute, I can split the available space. The problem is that the height of the videos always fills up the entire vertical space, thus, the videos get strechted.
What I want to achieve:
What I have tried:
Row(
children: <Widget>[
Expanded(
child: AspectRatio (
child: VideoPlayer(_leftPlayerController),
aspectRatio: _leftPlayerController.value.aspectRatio,
),
flex: 7, // 70%
),
Expanded(
child: Align (
child: AspectRatio (
child: VideoPlayer(_rightPlayerController),
aspectRatio: _rightPlayerController.value.aspectRatio,
),
),
flex: 3, // 30%
),
],
);
Try this and give a feedback
LayoutBuilder(
builder: (context, BoxConstraints constraints) {
return Container(
width: constraints.maxWidth,
child: Row(
children: <Widget>[
Container(
width: constraints.maxWidth*0.7,//70%
height: (constraints.maxWidth*0.7)/ratio,
child: //your videoplayer,
),
Container(
width: constraints.maxWidth*0.3,
height: (constraints.maxWidth*0.3)/ratio,//30%
child: //another video player,
),
],
),
);
}
Yes, you can do it with help of Expanded widget. See example:
Row(
mainAxisSize: MainAxisSize.max,
children: [
MyItem(Colors.orange),
MyItem(Colors.blue),
MyItem(Colors.orange),
MyItem(Colors.blue),
MyItem(Colors.orange),
],
)
Where MyItem:
class MyItem extends StatelessWidget {
final Color color;
MyItem(this.color);
#override
Widget build(BuildContext context) => Expanded(
child: AspectRatio(
aspectRatio: 1,
child: Container(
color: color,
),
));
}
Result: