I want widgets that has certain size but shrink if available space is too small for them to fit.
Let's say available space is 100px, and each of child widgets are 10px in width.
Say parent's size got smaller to 90px due to resize.
By default, if there are 10 childs, the 10th child will not be rendered as it overflows.
In this case, I want these 10 childs to shrink in even manner so every childs become 9px in width to fit inside parent as whole.
And even if available size is bigger than 100px, they keep their size.
Wonder if there's any way I can achieve this.
return Expanded(
child: Row(
children: [
...List.generate(Navigation().state.length * 2, (index) => index % 2 == 0 ? Flexible(child: _Tab(index: index ~/ 2, refresh: refresh)) : _Seperator(index: index)),
Expanded(child: Container(color: ColorScheme.brightness_0))
]
)
);
...
_Tab({ required this.index, required this.refresh }) : super(
constraints: BoxConstraints(minWidth: 120, maxWidth: 200, minHeight: 35, maxHeight: 35),
...
you need to change Expanded to Flexible
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(appBar: AppBar(), body: Body()),
);
}
}
class Body extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
width: 80,
color: Colors.green,
child: Row(
children: List.generate(10, (i) {
return Flexible(
child: Container(
constraints: BoxConstraints(maxWidth: 10, maxHeight: 10),
foregroundDecoration: BoxDecoration(border: Border.all(color: Colors.yellow, width: 1)),
),
);
}),
),
);
}
}
two cases below
when the row > 100 and row < 100
optional you can add mainAxisAlignment property to Row e.g.
mainAxisAlignment: MainAxisAlignment.spaceBetween,
Try this
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 10,maxHeigth:10),
child: ChildWidget(...),
)
The key lies in a combination of using Flexible around each child in the column, and setting the child's max size using BoxContraints.loose()
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Make them fit',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int theHeight = 100;
void _incrementCounter() {
setState(() {
theHeight += 10;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Playing with making it fit'),
),
body: Container(
color: Colors.blue,
child: Padding(
// Make the space we are working with have a visible outer border area
padding: const EdgeInsets.all(8.0),
child: Container(
height: 400, // Fix the area we work in for the sake of the example
child: Column(
children: [
Expanded(
child: Column(
children: [
Flexible(child: SomeBox('A')),
Flexible(child: SomeBox('A')),
Flexible(child: SomeBox('BB')),
Flexible(child: SomeBox('CCC')),
Flexible(
child: SomeBox('DDDD', maxHeight: 25),
// use a flex value to preserve ratios.
),
Flexible(child: SomeBox('EEEEE')),
],
),
),
Container(
height: theHeight.toDouble(), // This will change to take up more space
color: Colors.deepPurpleAccent, // Make it stand out
child: Center(
// Child column will get Cross axis alighnment and stretch.
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Press (+) to increase the size of this area'),
Text('$theHeight'),
],
),
),
)
],
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class SomeBox extends StatelessWidget {
final String label;
final double
maxHeight; // Allow the parent to control the max size of each child
const SomeBox(
this.label, {
Key key,
this.maxHeight = 45,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return ConstrainedBox(
// Creates box constraints that forbid sizes larger than the given size.
constraints: BoxConstraints.loose(Size(double.infinity, maxHeight)),
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Container(
decoration: BoxDecoration(
color: Colors.green,
border: Border.all(
// Make individual "child" widgets outlined
color: Colors.red,
width: 2,
),
),
key: Key(label),
child: Center(
child: Text(
label), // pass a child widget in stead to make this generic
),
),
),
);
}
}
Related
i want to divide my screen vertically in three equal parts with three diffrent color and i am getting only white screen in output.
import 'package:flutter/material.dart';
void main() {
runApp(const DivideVertically3EqualParts());
}
class DivideVertically3EqualParts extends StatefulWidget {
const DivideVertically3EqualParts({super.key});
#override
State<DivideVertically3EqualParts> createState() =>
_DivideVertically3EqualPartsState();
}
class _DivideVertically3EqualPartsState
extends State<DivideVertically3EqualParts> {
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: Container(
color: Colors.orange,
)),
Expanded(
child: Container(
color: Colors.white,
)),
Expanded(
child: Container(
color: Colors.green,
))
],
);
}
}
here is code , i am getting white screen it should be orange , white and green.
You are seeing white screen probably because of the following error
Horizontal RenderFlex with multiple children has a null textDirection,
so the layout order is undefined.
You can check Flutter error: RenderFlex with multiple children has a null textDirection to learn more about solutions of this error.
The easiest way to fix this is to wrap your widget with MaterialApp.
void main() async {
runApp(
MaterialApp(
home: DivideVertically3EqualParts(),
),
);
}
class DivideVertically3EqualParts extends StatefulWidget {
const DivideVertically3EqualParts({super.key});
#override
State<DivideVertically3EqualParts> createState() =>
_DivideVertically3EqualPartsState();
}
class _DivideVertically3EqualPartsState
extends State<DivideVertically3EqualParts> {
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: Container(
color: Colors.orange,
)),
Expanded(
child: Container(
color: Colors.white,
)),
Expanded(
child: Container(
color: Colors.green,
))
],
);
}
}
Your code need little bit changes.
double width = MediaQuery.of(context).size.width;
Row(
children: [
Expanded(
child: Container(
width : width : width /3
color: Colors.orange,
)),
Expanded(
child: Container(
width : width /3
color: Colors.white,
)),
Expanded(
child: Container(
width : width /3
color: Colors.green,
))
],
);
Btw your code is perfect. And it's working for me as well,
I am trying to make my first color item in column expanding based on parent width ..
this is my simple code
import 'package:agora_rtc_engine/rtc_engine.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Ff extends StatefulWidget {
const Ff({Key? key}) : super(key: key);
#override
State<Ff> createState() => _FfState();
}
class _FfState extends State<Ff> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
body: Center(
child: Container(
color: Colors.red,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
color: Colors.green,
child: Text('Hello world',style: TextStyle(color: Colors.white),) // here i need to expanding my color
),
Container(
width: 200,// Note : This width item is not fixed, it depends on user input text, it could be changed depends on user all the time
height: 100,
)
],
),
),
),
);
}
}
OK now I have the parent container that has a red color, and my second item in Column is not fixed all the time. it depends on user width text and i make the width 200 for example only ..
Now the output in UI looks like the following:
but I need it to look like this:
I find way to make my green container width infinity work, but the problem is the whole parent red container will be expanding that I don't want like following
Container(
width: double.infinity,
color: Colors.green,
child: Text('Hello world',style: TextStyle(color: Colors.white),)
),
Final note: in my case the width of my red container (parent one) it's width comes based on my SECOND ITEM in my column which is Text input and it could be changed all the time but I make the width 200 for example .. so I can't make direct width to the parent it's self
How can I achieve this? Thanks all
for your example this should work:
class Ff extends StatefulWidget {
const Ff({Key? key}) : super(key: key);
#override
State<Ff> createState() => _FfState();
}
class _FfState extends State<Ff> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
body: Center(
child: Container(
color: Colors.red,
child: IntrinsicWidth(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(children: [
Expanded(
child: Container(
color: Colors.green,
child: Text(
'Hello world',
style: TextStyle(color: Colors.white),
)
))
]),
Container(
width: 200,
height: 100,
)
],
),
),
),
));
}
}
Try:
crossAxisAlignment: CrossAxisAlignment.stretch
inside your column. That force to set max width posible inside the parent
Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
// ... some widgets
Padding(
padding: const EdgeInsets.all(-20.0), // Error: How to do something like this?
child: FooWidget()
),
// ... more widgets
BarWidget(), // Remove padding from here also
// ... and some more widgets
],
),
)
I'm providing a padding of 20 to my Column, but I want to remove this padding from some of its children, like FooWidget, BarWidget, etc. How can I do that?
Note: I'm not looking for workarounds like provide the padding to other widgets instead of the root Column or wrap those widgets in another Column and provide that column a padding, etc.
you can apply transformation to the widgets that you want to remove the padding for, for example:
Container(
transform: Matrix4.translationValues(-20.0, 0, 0.0), //here
child: FooWidget()),
This working solution uses UnconstrainedBox that only takes away the left side and right side of padding. You might do the calculation of overflowWidth first when screenWidth is not feasible to use.
In addition, this comes up with a RenderConstraintsTransformBox overflowed exception that will be gone away in app release version, e.g. flutter build appbundle for android app.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
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: UnboundedWidget(),
);
}
}
class UnboundedWidget extends StatelessWidget {
const UnboundedWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final double overflowWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: const Text('Unbounded demo'),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
UnconstrainedBox(
child: Container(
color: Colors.red,
width: overflowWidth,
child: const Text('123'),
),
),
],
)),
);
}
}
There is no such thing as negative margins in flutter.
You can try workarounds with transforms on x, y, z axis as transform property on Container widget.
Or try with SizedBox which ignores parent padding.
Here is a similar example that should work:
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Container(
width: double.infinity, height: 20, color: Colors.green),
// This child ignores parent padding.
SizedBox(
width: MediaQuery.of(context).size.width,
height: 20,
child: Expanded(
child: OverflowBox(
maxWidth: MediaQuery.of(context).size.width,
child: Container(
width: double.infinity,
height: 20,
color: Colors.red)),
),
),
Container(
width: double.infinity,
height: 20,
color: Colors.blue),
],
),
),
Use Stack widget with Positioned widget Positioned(left: -20, child: widget)
on the other hand, for padding less.
you can create custom 2 widget name as:
paddingLessWidget(child: your widget)
paddingWithWidget(child: your widget)
then use this into column() widget.
Remove padding from column's parents.
use as:
Column(
children:[
paddingLessWidget(child: your widget),
paddingWithWidget(child: your widget)
]
),
I am trying to achieve an effect where there is expandable content on the top end of a sidebar, and other links on the bottom of the sidebar. When the content on the top expands to the point it needs to scroll, the bottom links should scroll in the same view.
Here is an example of what I am trying to do, except that it does not scroll. If I wrap a scrollable view around the column, that won't work with the spacer or expanded that is needed to keep the bottom links on bottom:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
#override
State<MyWidget> createState() {
return MyWidgetState();
}
}
class MyWidgetState extends State<MyWidget> {
List<int> items = [1];
#override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
setState(() {
items.add(items.last + 1);
});
},
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
setState(() {
if (items.length != 1) items.removeLast();
});
},
),
],
),
for (final item in items)
MyAnimatedWidget(
child: SizedBox(
height: 200,
child: Center(
child: Text('Top content item $item'),
),
),
),
Spacer(),
Container(
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all()),
height: 200,
child: Text('Bottom content'),
)
],
);
}
}
class MyAnimatedWidget extends StatefulWidget {
final Widget? child;
const MyAnimatedWidget({this.child, Key? key}) : super(key: key);
#override
State<MyAnimatedWidget> createState() {
return MyAnimatedWidgetState();
}
}
class MyAnimatedWidgetState extends State<MyAnimatedWidget>
with SingleTickerProviderStateMixin {
late AnimationController controller;
#override
initState() {
controller = AnimationController(
value: 0, duration: const Duration(seconds: 1), vsync: this);
controller.animateTo(1, curve: Curves.linear);
super.initState();
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (context, child) {
return SizedBox(height: 200 * controller.value, child: widget.child);
});
}
}
I have tried using a global key to get the size of the spacer and detect after rebuilds whether the spacer has been sized to 0, and if so, re-build the entire widget as a list view (without the spacer) instead of a column. You also need to listen in that case for if the size shrinks and it needs to become a column again, it seemed to make the performance noticeably worse, it was tricky to save the state when switching between column/listview, and it seemed not the best way to solve the problem.
Any ideas?
Try implementing this solution I've just created without the animation you have. Is a scrollable area at the top and a persistent footer.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
home: SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("My AppBar"),
),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
// Your scrollable widgets here
Container(
height: 100,
color: Colors.green,
),
Container(
height: 100,
color: Colors.blue,
),
Container(
height: 100,
color: Colors.red,
),
],
),
),
),
Container(
child: Text(
'Your footer',
),
color: Colors.blueGrey,
height: 200,
width: double.infinity,
)
],
),
),
),
);
}
}
I've been attempting to define a bespoke Card in Flutter using row and column and cannot seem to get a fixed format layout similar to the image above (the red lines denote the areas of the card and are just there to show the areas).
e.g.
return Card(child: Column(
children: [
Row(
children: [
Column( children: [
Text('Riverside cafe...'),
Ratingbar(),
],),
ImageWidget(),
],
),
Container(child: Text('Pubs & restaurants'), color : Colors.purple)
],
The resulting cards are to be displayed in a listview and using rows and columns above results in the areas being different sized depending on the data.
It seems to me that using row and column may not be the best way to achieve this. Is there a better way?
As for the best, I suppose that's for you and your client to decide.
For as long as I've been working with Flutter, I haven't come across anything like CSS grid which is great for situations like this. The closest comparison is StaggeredGrid (https://pub.dev/packages/flutter_staggered_grid_view) but that doesn't offer as much control as CSS grid and doesn't seem to quite fit your use case.
Rows, Columns (and other layout widgets) can get the job done:
Here's the main.dart that produced the above example. Code quality isn't perfect, but hopefully you can follow it well enough and it helps you get done what you need to get done.
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
static const String _title = 'Bespoke card example';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Bespoke card example')),
body: Center(
child: Wrap(runSpacing: 10.0, children: [
BespokeCard(title: 'Short name', width: 350),
BespokeCard(
title: 'Riverside Cafe with a really long name', width: 350)
]),
),
);
}
}
class BespokeCard extends StatelessWidget {
final String title;
final double width;
BespokeCard({this.title, this.width});
#override
Widget build(BuildContext context) {
Widget _restaurantNameContainer = Container(
constraints: BoxConstraints(
minHeight: 0,
maxHeight: 120,
maxWidth: (500.0 - 40 - 175 + 1),
minWidth: (500.0 - 40 - 175 + 1),
),
child: AutoSizeText(
title,
style: TextStyle(fontSize: 60),
maxLines: 2,
minFontSize: 10,
stepGranularity: 0.1,
overflow: TextOverflow.ellipsis,
),
);
Widget _rightSideSection = Container(
width: 175,
height: Size.infinite.height,
child: Center(
child: Icon(
Icons.umbrella,
size: 70,
),
),
);
Widget _topSection = Flexible(
flex: 1,
child: Row(
children: [
Flexible(
fit: FlexFit.tight,
flex: 3,
child: Padding(
padding: EdgeInsets.only(left: 40.0, top: 25.0),
child: Column(
children: [
Flexible(child: Container(), flex: 1),
_restaurantNameContainer,
Text('* * * * *', style: TextStyle(fontSize: 70)),
],
),
),
),
_rightSideSection
],
),
);
Widget _bottomSection = Container(
height: 70,
width: Size.infinite.width,
child: Center(
child: Text('Pubs & Restaurants',
style: TextStyle(color: Colors.white, fontSize: 40)),
),
color: Colors.purple);
Widget unfittedCard = Card(
child: SizedBox(
width: 500,
height: 300,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [_topSection, _bottomSection],
),
));
return Container(
width: this.width,
child: FittedBox(fit: BoxFit.fitWidth, child: unfittedCard));
}
}
NOTES:
Be aware of flexFit (tight or loose) property: https://api.flutter.dev/flutter/widgets/Flexible/fit.html
You can either define fixed ratios with all flexibles, or you can mix Flexibles with Containers / SizedBoxes what have you
The package auto_size_text is great for situations like this. (Add auto_size_text: ^2.1.0 to your dependencies)
Be aware of box constraints. I needed them to make the title autosizing text be able to grow tall without also sitting in a large container.
Fitted box is really handy and makes scaling very easy in flutter.