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: () {},
),
),
),
),
],
),
),
);
}
Related
I need a Column to expand to a constrained width. So it expands until the maxWidth but doesn't mind being smaller if there isn't enough space. But the Expanded ignores the ConstrainedBox.
Row(
children: [
const Spacer(),
Expanded(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 50),
child: Column(
children: [
Expanded(child: Container(color: Colors.red)),
Expanded(child: Container(color: Colors.green)),
],
),
),
),
],
)
Here's my full code for context:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GetBuilder<TimerController>(
builder: (_) => CustomBackground(
color: _timerController.currentChild?.color ?? Colors.blue,
child: SafeArea(
child: Center(
child: Padding(
padding:
EdgeInsets.symmetric(horizontal: AppSizes.pagePadding),
child: OrientationBuilder(
builder: (context, orientation) =>
(orientation == Orientation.portrait)
? ConstrainedBox(
constraints: BoxConstraints(
maxWidth: AppSizes.maxWidth,
minWidth: AppSizes.minWidth,
),
child: Column(
children: [
SizedBox(height: AppSizes.pagePadding),
Expanded(child: TimerClock()),
Expanded(
child: Column(
children: [
NameText(),
ControlButtons(),
SizedBox(height: 25),
Expanded(child: QueueList()),
],
),
),
],
),
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: AppSizes.maxWidth,
minWidth: AppSizes.minWidth,
),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: AppSizes.pagePadding),
child: TimerClock(),
),
),
),
SizedBox(width: AppSizes.pagePadding),
Expanded(
child: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: AppSizes.maxWidth, // this get's ignored
minWidth: AppSizes.minWidth,
),
child: Column(
children: [
Expanded(child: NameText()),
ControlButtons(),
SizedBox(height: 25),
Expanded(child: QueueList()),
],
),
),
),
],
),
),
),
),
),
),
),
),
);
}
And if I remove the Expanded, the Column has a fixed width (maxWidth) and throws an error if there isn't enough space.
Change the outer most Expanded to a Flexible. Then the child ConstrainedBox will be respected.
In my case I also added a width:double.infinity to the child of the Flexible to force the widget to always be as big as the maxWidth, and only reduce its size when there is no space.
My example:
Flexible(
child: Container(
constraints: BoxConstraints(maxWidth: screenWidth * 0.25),
width: double.infinity,
),
);
You are using Expanded in a Column widget which means that it will try to expand to fill the space vertically (based on the height of the parent not its width). As mentioned in the documentation of Expanded:
Using an Expanded widget makes a child of a Row, Column, or Flex
expand to fill the available space along the main axis (e.g.,
horizontally for a Row or vertically for a Column).
source
And as you did not precise a maxHeight in your constraints it will be considered as double.infinity.
In the picture below, I tried using the SizedBox Widget and I set the height:
SizedBox(
height: MediaQuery.of(context).size.height / 5.9,
),
The second solution is I try to use LayoutBuilder widget and builder and I specify the height: constraints.maxHeight * 0.4 but I'm getting the same result.
Here's the code:
body: SingleChildScrollView(
child: Column(
children: [
Stack(
children: <Widget>[
_buildCoverImage(screenSize),
SafeArea(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
SizedBox(height:MediaQuery.of(context).size.height / 5.9),
_buildProfileImage(),
_buildFullName(context),
_buildStatContainer(context),
]
),
),
),
],
),
],
),
),
);
output
Hope you want something like this, while using LayoutBuilder use it at top level of widget tree.
example code
import 'package:flutter/material.dart';
class BackSide extends StatelessWidget {
const BackSide({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => SizedBox(
height: constraints.maxHeight,
width: constraints.maxWidth,
child: Stack(
fit: StackFit.expand,
alignment: Alignment.topCenter,
children: <Widget>[
// _buildCoverImage(screenSize),
Container(
height: constraints.maxHeight,
width: constraints.maxWidth,
color: Colors.amberAccent,
child: Text("Background"),
),
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: constraints.maxHeight * .4,
),
...List.generate(
15,
(index) => Container(
height: 100,
width: double.infinity,
color: index % 2 == 0
? Colors.pinkAccent
: Colors.cyanAccent,
child: Text("item $index"),
)).toList(),
// _buildProfileImage(),
// _buildFullName(context),
// _buildStatContainer(context),
],
),
)
],
),
),
),
);
}
}
I have a list view with horizontal scroll and i have added CupertinoContextMenu to the image.
everything is works fine but the action buttons are not aligned center.
I have added the code. I tried with wrap scaffold too. same issue still.
I have to align the action buttons under the image center posisiton.
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Center(child: _invoiceImageSlider()),
);
// Image Slider List
Widget _invoiceImageSlider(){
return Container(
height: 250,
padding: EdgeInsets.fromLTRB(0, 0, 20, 0),
child: ListView(
// This next line does the trick.
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 160.0,
child: _invoiceContextMenu(),
),
Container(
width: 160.0,
child: _invoiceContextMenu(),
),
Container(
width: 160.0,
child: _invoiceContextMenu(),
),
Container(
width: 160.0,
child: _invoiceContextMenu(),
),
],
),
);
}
Widget _invoiceContextMenu(){
return Container(
child: CupertinoContextMenu(
child: Container(
child: _invoiceImage(),
),
previewBuilder: (BuildContext context, Animation<double> animation, Widget child) {
return FittedBox(
fit: BoxFit.cover,
child: ClipRRect(
borderRadius: BorderRadius.circular(64.0 * animation.value),
child: Image.asset('assets/invoices/'+_invoiceInfo.filename),
),
);
},
actions: <Widget>[
CupertinoContextMenuAction(
child: Row(
children: <Widget>[
Icon(
Feather.trash_2,
size: 25,
color: Colors.red,
),
SizedBox(width: 10),
Text("Delete")
]
),
onPressed: () {
Navigator.pop(context);
},
),
],
),
);
}
You can do so by centering the whole ContextMenu like this:
Align(
alignment: Alignment.center,
child: CupertinoContextMenu(),
)
Hope this helped. Cheers
I have a body of scaffold that structured like this :
body : Column(
children : [
Expanded(
child : SingleChildScrollView(
Container (
Column(
//content
)
)
)
),
BottomMenu()
]
)
And the problem is the content would not show up if i dont define the width and height for the Container inside SingleChildScrollView, but if i define the height then the height of my childscrollview wont work dynamically with the content, i want the height to fit the content inside of my container so i can scroll until the end of content. I am still new to this so any advice and suggestion will be appreciated. Thankyou
It is better to use Stack instead of the column as top Widget like this:
Stack(
children: <Widget>[
SingleChildScrollView(
Container (
Column(
//content
)
)
),
Align(
alignment: Alignment.bottomCenter,
child: BottomMenu(),
),
],
)
Does this help you?
Your layout isn't best practice, try:
return Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
return SingleChildScrollView(
child: Container(
width: constraints.maxWidth,
height: constraints.maxHeight,
child: Column(
children: [
//your content
],
),
),
);
}));
This makes a container which is the size of the screen, and it contains a column which will scroll with all the content.
I could not understand what exactly the issue is. But I could give some idea.
Try something like this,
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
color: Colors.blue,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.9,
child: SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: ListView(
children: [
Row(
children: [
Container(
margin: const EdgeInsets.only(bottom: 10.0),
height: 100.0,
width: 100.0,
color: Colors.red,
),
],
),
....
],
),
),
),
),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.1,
child: BottomMenu(),
),
],
),
);
}
Hope that solves your issue.
I am tring to create ui as below image. but button hide behind the list. Also faces issue button not click when used Positioned widget for button.Please suggest how to create below UI using Stack widget with ListView & Floating button.
UI
Container(
color: Colors.grey,
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Column(
children: <Widget>[
Container(
height: 250.0,
width: MediaQuery.of(context).size.width,
child: Image.asset(
"images/1.jpg",
fit: BoxFit.cover,
),
)
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
height: 220.0,
),
Container(
padding: EdgeInsets.only(right: 15.0),
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.favorite),
),
),
],
),
Column(
children: <Widget>[
Container(
height: 250.0,
),
Container(
height: MediaQuery.of(context).size.height - 250.0,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text("Title $index"),
leading: Icon(Icons.home),
),
);
},
itemCount: 15,
),
),
],
)
],
),
],
),
);
As per documentation (https://docs.flutter.io/flutter/widgets/Stack-class.html):
The stack paints its children in order with the first child being at the bottom
So your Stack children's order is wrong. Your current order is:
Header
Button
List
But it should be:
Header
List
Button
Otherwise list is overlapping button.