How to use FractionallySizedBox in Column with Scroll? - flutter

I have a simple layout in my flutter app:
Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(centerTitle: true, title: Text('test')),
body: SingleChildScrollView(
child: Column(
children: [
Expanded(
flex: 7,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
FractionallySizedBox(
widthFactor: 0.55,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextField(),
),
),
SizedBox(
height: 15,
),
],
),
),
Expanded(
child: Column(
children: [
Text('some text'),
FractionallySizedBox(
widthFactor: 0.55,
child: RaisedButton(
child: Text('Hello'),
),
),
],
))
],
),
),
);
It works but without SingleChildScrollView. With SingleChildScrollView I have error:
RenderBox was not laid out: RenderRepaintBoundary#0b8c5 relayoutBoundary=up1 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1785 pos 12: 'hasSize'
I need the field and the button to occupy the same width - for this I use FractionallySizedBox.
Also I need to split the screen proportionally (in height) - for this I use Expanded with Flex.
But I also need scrolling when the keyboard appears. If I use SingleChildScrollView it gives an error. Perhaps this is not the best way - I would be grateful for any advice.
I have used several options but I get this error. How can this be fixed?

You can copy paste run full code below
Step 1: Use LayoutBuilder wrap SingleChildScrollView and ConstrainedBox
Step 2: RaisedButton use Expanded
You can see working demo below
code snippet
body: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: constraints.copyWith(
maxHeight: constraints.maxHeight,
),
child: Column(
...
Expanded(
flex: 3,
child: RaisedButton(
onPressed: () {
print("hi");
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
//resizeToAvoidBottomInset: true,
appBar: AppBar(centerTitle: true, title: Text('test')),
body: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: constraints.copyWith(
maxHeight: constraints.maxHeight,
),
child: Column(
children: [
Expanded(
flex: 7,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
FractionallySizedBox(
widthFactor: 0.55,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextField(),
),
),
SizedBox(
height: 15,
),
],
),
),
Expanded(
child: Column(
children: [
Text('some text'),
Expanded(
flex: 3,
child: RaisedButton(
onPressed: () {
print("hi");
},
child: Text('Hello'),
),
),
],
))
],
),
),
);
}));
}
}

Related

Not being able to add vertical line in flutter

I have the following layout
Form(
onChanged: _updateFormProgress,
child: Row(
children: [
Expanded(
flex: 3,
child: Column(
children: [
....
],
),
),
Expanded(
flex: 2,
child: Column(
children: [
...
],
),
)
],
),
);
I need a vertical separator line beteen the two Expanded
I tried:
Form(
onChanged: _updateFormProgress,
child: Row(
children: [
Expanded(
flex: 3,
child: Column(
children: [
....
],
),
),
Container(
child: VerticalDivider(
color: Colors.red,
width: 1,
)
),
Expanded(
flex: 2,
child: Column(
children: [
...
],
),
)
],
),
);
And it compiles but I can't see the line. I also tried other options like wrapping the Expanded in a Container and make a border but have different issues with that
I changed code like tree you provide, and change it to work.
Please wrap 'Row' with 'IntrinsicHeight'.
I attached full code I tested.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Padding(
padding: EdgeInsets.all(10),
child: Center(
child: Column(
children: [
Container(
child: Form(
onChanged: () {},
child: IntrinsicHeight(
child: Row(
children: [
Expanded(
flex: 3,
child: Column(
children: [
Container(child: Text('a')),
Container(child: Text('a')),
Container(child: Text('a')),
],
),
),
Container(
child: VerticalDivider(
color: Colors.red,
width: 1,
),
),
Expanded(
flex: 2,
child: Column(
children: [
Container(child: Text('a')),
Container(child: Text('a')),
Container(child: Text('a')),
],
),
)
],
),
),
),
),
],
),
),
),
);
}
}

Flutter showing hasSize error when wrap container in column

I am getting an error when I wrap my container in the column widget. I need 2 containers in a column but when I wrap it in column widget it's showing this error
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1694 pos 12: 'hasSize'
Showing this in Column line error
Here is my code
class _PlaceListState extends State<PlaceList> {
final List _places = [
{'name': 'Hunza', 'where': 'Gilgit Baltistan'},
{'name': 'Skardu' ,'where': 'Gilgit Baltistan'},
{'name': 'Murree', 'where': 'Gilgit Baltistan'},
];
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
Container(
margin: EdgeInsets.only(left: 40),
width: MediaQuery.of(context).size.width * 0.5,
child: ListView.builder(
itemCount: _places.length,
itemBuilder: (ctx, int index) {
return Container(
padding: EdgeInsets.only(top: 50),
child: Column(
children: <Widget>[
Text(_places[index]['name'], style: TextStyle(fontSize: 20),),
Container(
padding: EdgeInsets.only(top: 20),
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Card(
elevation: 40.0,
child: Container(
width: 200,
child: Image(image: AssetImage('assets/images/500place.jpg')),
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 7),
child: Row(
children: <Widget>[
Icon(Icons.favorite_border, size: 20),
Spacer(),
Text(
_places[index]['where'],
),
],
)
),
],
),
);
}),
)
],);
}
}
The screen output i use Navigation rale so that's why I set the width and its working fine without Column widget
You can copy paste run full code below
Step 1: Provide height when use PlaceList() , you can use Expanded(child: PlaceList())
Step 2: add shrinkWrap: true for ListView
Step 3: Use Expaneded flex to provide height for Container() 1 and 2
Column(
children: <Widget>[
Expanded(
flex: 3,
...
Expanded(
flex: 1,
child: Center(child: Container(child: Text("Second Container"))))
working demo
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(child: PlaceList()),
],
),
),
);
}
}
class PlaceList extends StatefulWidget {
#override
_PlaceListState createState() => _PlaceListState();
}
class _PlaceListState extends State<PlaceList> {
final List _places = [
{'name': 'Hunza', 'where': 'Gilgit Baltistan'},
{'name': 'Skardu', 'where': 'Gilgit Baltistan'},
{'name': 'Murree', 'where': 'Gilgit Baltistan'},
{'name': 'abc', 'where': 'def'},
];
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
flex: 3,
child: Container(
margin: EdgeInsets.only(left: 40),
width: MediaQuery.of(context).size.width * 0.5,
child: ListView.builder(
shrinkWrap: true,
itemCount: _places.length,
itemBuilder: (ctx, int index) {
return Container(
padding: EdgeInsets.only(top: 50),
child: Column(
children: <Widget>[
Text(
_places[index]['name'],
style: TextStyle(fontSize: 20),
),
Container(
padding: EdgeInsets.only(top: 20),
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Card(
elevation: 40.0,
child: Container(
width: 200,
child: Image(
image: AssetImage(
'assets/images/500place.jpg')),
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 7),
child: Row(
children: <Widget>[
Icon(Icons.favorite_border, size: 20),
Spacer(),
Text(
_places[index]['where'],
),
],
)),
],
),
);
}),
),
),
Expanded(
flex: 1,
child: Center(child: Container(child: Text("Second Container"))))
],
);
}
}
try adding height: // define height in double to your container
Add the shrinkWrap property to your ListView as seen below:
child: ListView.builder(
itemCount: _places.length,
shrinkWrap: true,
itemBuilder: (ctx, int index) {
return Container(...
Setting the shrinkWrap to true would result in the list wrapping its content and be as big as its children permits
You could also add a height to your Container
return Container(
height: 90,
...
)

implementing nested ListView inside SingleChildScrollView

in this sample code i want to put nested ListView inside SingleChildScrollView, but i get this error:
RenderBox was not laid out: RenderRepaintBoundary#8de00 relayoutBoundary=up1 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1694 pos 12: 'hasSize'
my code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: Scaffold(
appBar: AppBar(
title: Text("Scrollview Demo"),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: 50.0,
color: Colors.green,
child: Center(
child: Text('message'),
),
),
Expanded(
child: ListView.builder(
itemCount: 30,
itemBuilder: (context, index) {
return ListTile(title: Text("Index : $index"));
},
),
),
],
),
),
),
);
}
}
In ListView you can set
shrinkWrap: true
so that ListView only occupies the space it needed.
To disable the scrolling on ListView so it uses that of SingleChildScrollView you can set the
physics: NeverScrollableScrollPhysics().
You need to remove the Expanded which set the child to take the available screen in case of here is infinite.
Here:
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
height: 50.0,
color: Colors.green,
child: Center(
child: Text('message'),
),
),
Flexible(
child: ListView.builder(
itemCount: 30,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(title: Text("Index : $index"));
},
),
),
],
),
)
Instead of using SingleChildScrollView then use Column as the child just use ListView.
return Scaffold(
body: ListView(
children: <Widget>[
Container(
height: 104,
child: Card(
clipBehavior: Clip.antiAliasWithSaveLayer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[],
),
),
),
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
),
],
),
);
Ones I was in the same situation and did like that:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: Scaffold(
appBar: AppBar(
title: Text("Scrollview Demo"),
),
body: ListView.builder(
itemCount: 30 + 1,
itemBuilder: (context, index) {
if (index == 0) {
return Container(
height: 50.0,
color: Colors.green,
child: Center(
child: Text('message'),
),
);
}
return ListTile(title: Text('Index : ${index -1}'));
},
),
),
);
}
}

Can't find correct layout option for how to use ListView in a custom Widget

I am trying to extract re-use a simple widget that is then referenced in parent widget. The custom widget simply uses a row to layout a textField and a button, and below this I Want to have a listview showing items. I then embed in the customwidget in parent, but it continually throws Error. I have not figured out how to get the custom widget working where I can use ListView or column layout inside. Below is the 2 simplified widgets that demo the issue.
Here is the parent widget, which is where I call the custom widget PlayListControl()
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My Playlists'),
),
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
textDirection: TextDirection.ltr,
children: <Widget>[
Container(
alignment: Alignment.center,
margin: EdgeInsets.all(20),
child: Text('Test'),
),
PlayListControl(),
],
),
),
drawer: SideDrawer(),
);
}
}
And here is the playlistcontrol widget.
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 200,
child: TextField(),
),
ButtonTheme(
minWidth: 30,
child: RaisedButton(
textColor: Colors.white,
child: Text('add'),
onPressed: () {},
)),
],
),
),
Expanded(
child: ListView(
children: <Widget>[
Text('Widget 1'),
Text('Widget 2'),
],
),
)
],
),
);
}
}
No matter what I try, it always complains about layout issue related to height. I would have thought wrapping the ListView in Expanded would solve the issue, but it doesn't. Only if I use a container and specify height do I not get the errors, but I want to use whatever available space there is.
How can I get this playlistcontrol() widget to properly render inside a parent control?
you forgot to wrap the first container of PlayListControl in Expanded widget..
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text('My Playlists'),
),
body: Container(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
textDirection: TextDirection.ltr,
children: <Widget>[
Container(
alignment: Alignment.center,
margin: EdgeInsets.all(20),
child: Text('Test'),
),
PlayListControl(),
],
),
),
));
}
}
class PlayListControl extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 200,
child: TextField(),
),
ButtonTheme(
minWidth: 30,
child: RaisedButton(
textColor: Colors.white,
child: Text('add'),
onPressed: () {},
)),
],
),
),
Expanded(
child: ListView(
children: <Widget>[
Text('Widget 1'),
Text('Widget 2'),
],
),
)
],
),
),
);
}
}

Flutter Layout: VerticalDividers not shown

I have a simple layout that consists of one Column with few children. Some of these are Rows which contain children either. I've added Dividers between the children of the Column and VerticalDividers between the children of the Rows. The (horizontal) Dividers are shown fine. However the VerticalDividers are not shown in the app.
I have already tried wrapping the Rows children in some other layout widget like Container, but nothing seems to work.
Screenshot
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test App'),
),
body: Column(
children: <Widget>[
Expanded(
child: Center(
child: Text('Hello World'),
),
),
Divider(height: 1),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(40.0),
child: Text('Row 1.1'),
),
VerticalDivider(width: 1),
Padding(
padding: const EdgeInsets.all(40.0),
child: Text('Row 1.2'),
),
],
),
Divider(height: 1),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(40.0),
child: Text('Row 2.1'),
),
VerticalDivider(width: 1),
Padding(
padding: const EdgeInsets.all(40.0),
child: Text('Row 2.2'),
),
],
)
],
),
);
}
}
just wrap Rows with IntrinsicHeight widget
your example will looks like
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test App'),
),
body: Column(
children: <Widget>[
Expanded(
child: Center(
child: Text('Hello World'),
),
),
Divider(height: 1),
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(40.0),
child: Text('Row 1.1'),
),
VerticalDivider(width: 1),
Padding(
padding: const EdgeInsets.all(40.0),
child: Text('Row 1.2'),
),
],
),
),
Divider(height: 1),
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(40.0),
child: Text('Row 2.1'),
),
VerticalDivider(width: 1),
Padding(
padding: const EdgeInsets.all(40.0),
child: Text('Row 2.2'),
),
],
),
)
],
),
);
}
}
Try this:
Container(
height: 20,
child: VerticalDivider(
width: 20
color: Colors.black,
),
),
It worked for me.