I am trying to make stack layout scrollable using SingleChildScrollView but it's not scrolling. Is SingleChildScrollView should be used here?
I think I have given enough description to make anyone understand my question. More text here to satisfy StackOverflow's requirement to ask a question. Sorry about this.
Here's example code.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
child: Center(
child: LayoutBuilder(
builder:
(BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
children: <Widget>[
Container(
// A fixed-height child.
color: Colors.white,
height: 120.0,
),
Expanded(
// A flexible child that will grow to fit the viewport but
// still be at least as big as necessary to fit its contents.
child: Container(
color: Colors.blue,
//height: 120.0,
child: Stack(
children: <Widget>[
Positioned(
top: 0,
left: 0,
right: 0,
child: Container(
color: Colors.red[100],
child: SizedBox(
height: 300,
),
),
),
Positioned(
top: 50,
left: 0,
right: 0,
child: Container(
color: Colors.red[200],
child: SizedBox(
height: 300,
),
),
),
Positioned(
top: 100,
left: 0,
right: 0,
child: Container(
color: Colors.red[300],
child: SizedBox(
height: 300,
),
),
),
Positioned(
top: 150,
left: 0,
right: 0,
child: Container(
color: Colors.green[100],
child: SizedBox(
height: 300,
),
),
),
Positioned(
top: 200,
left: 0,
right: 0,
child: Container(
color: Colors.green[200],
child: SizedBox(
height: 300,
),
),
),
Positioned(
top: 250,
left: 0,
right: 0,
child: Container(
color: Colors.green[300],
child: SizedBox(
height: 300,
),
),
),
Positioned(
top: 300,
left: 0,
right: 0,
child: Container(
color: Colors.yellow[100],
child: SizedBox(
height: 300,
),
),
),
Positioned(
top: 350,
left: 0,
right: 0,
child: Container(
color: Colors.yellow[200],
child: SizedBox(
height: 300,
),
),
),
Positioned(
top: 400,
left: 0,
right: 0,
child: Container(
color: Colors.yellow[300],
child: SizedBox(
height: 300,
),
),
),
],
),
),
),
],
),
),
),
);
},
),
),
),
),
);
}
It depends on what size should the StackView have. For example you can make one of Stack's children not positioned. This child will then affect the size of entire stack view.
SingleChildScrollView(
child: Stack(
children: <Widget>[
Container(
height: 5000,
),
Positioned(
top: 100,
left: 100,
width: 1000,
height: 1000,
child: Container(color: Colors.red),
)
],
),
)
Stack will get the constraints of the biggest child. But if you use Position the constraints of that child are not considered by stack. If you want dynamic height and width for the stack use Margin inside a container instead of position.
To explain more in detail
SingleChildScrollView(
child: Stack(
children: <Widget>[
Container(
height: 500,
),
Positioned(
top: 100,
left: 100,
child: Container(color: Colors.red, height: 1000, width: 1000),
)
],
),
)
In the above case stack will only take 500 as height. Your Container which has 1000 will not be considered.
SingleChildScrollView(
child: Stack(
children: <Widget>[
Container(
height: 500,
),
Container(margin: EdgeInsets.only(top: 100, left: 100, color: Colors.red, height: 1000, width: 1000),
],
),
)
In the above case the height of the container will be used for defining the height of stack. This will also allow for SingleChildScrollView to be scrollable.
Stack(
children: [
Container(
width: 100,
height: 100,
child: Material(
elevation: 8.0,
borderRadius: BorderRadius.circular(10),
child: Text("HELLO")),
),
//please use column and sized box instead of Positioned..
//Then SingleChildScrollView working
//inkwell ontap working perfect
Column(
children: [
SizedBox(height: 100),
Container(
width: 100,
height: 100,
color: Colors.white,
)
])
],
),**
The Stack takes the size of the widest height widget. To fix the problem, you have to calculate the maximum size that your Stack will take. You create an empty Container that has this size. Next you will add the other widgets in the Stack.
Exemple
SingleChildScrollView(
child: Column(
children: [
Stack(
children: [
Container(height: 200), // Max stack size
Container(
alignment: Alignment.topCenter,
height: 150,),
Positioned(
top: 110,
left: 30,
right: 30,
height: 80,
child: Material(
elevation: 8.0,
borderRadius: BorderRadius.circular(10),
child: Text("HELLO")
),
]),// Stack
Container(child: Text("After the stack")),
])// Column
),//SingleChildScrollView
You can put Expanded > SingleChildScrollView > Column
Expanded(
child: SingleChildScrollView(
child: Container(
color: Colors.red,
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Text('Red container should be scrollable'),
Container(
width: double.infinity,
height: 700.0,
padding: EdgeInsets.all(10.0),
color: Colors.white.withOpacity(0.7),
child: Text('I will have a column here'),
)
],
),
),
),
),
Related
I can't figure out how to make the FAB smaller inside the first Container in the list. It seems to want to occupy the complete container, no matter what I try. Ive even tried a container within a container. The complete Orange area is clickable. I tried SizedBox, same result. Here is the code.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final title = 'Horizontal List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
padding: EdgeInsets.all(30),
height: 200.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 160,
color: Colors.yellowAccent,
child: SizedBox(
height: 50,
width: 50,
child: FittedBox(
child: FloatingActionButton(
backgroundColor: Colors.deepOrange,
foregroundColor: Colors.indigo,
child: Icon(Icons.add, size: 20),
onPressed: () {},
),
),
),
),
Container(
width: 160.0,
color: Colors.red,
),
Container(
width: 160.0,
color: Colors.blue,
),
Container(
width: 160.0,
color: Colors.green,
),
Container(
width: 160.0,
color: Colors.yellow,
),
Container(
width: 160.0,
color: Colors.orange,
),
],
),
),
),
);
}
}
I have 2 samples. And Please refer Basic Widgets for more detail.
Use margin of Container. Please refer the code as below:
child: SizedBox(
height: 50,
width: 50,
child: Container(
margin: EdgeInsets.only(left:80.0, top:80.0, bottom: 10.0) ,
child: FloatingActionButton(
backgroundColor: Colors.deepOrange,
foregroundColor: Colors.indigo,
child: Icon(Icons.add),
onPressed: () {},
),
),
),
Use Row or Column. Please refer the code as below:
child: SizedBox(
height: 50,
width: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[ FloatingActionButton(
backgroundColor: Colors.deepOrange,
foregroundColor: Colors.indigo,
child: Icon(Icons.add),
onPressed: () {},
),
]),
),
I have a sidebar containing different items to open different screens. But i am only able to make image and textview clickable not whole item.
_myDrawer() => Drawer(
child: Column(
children: <Widget>[
Expanded(
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: _myDrawerHeader(),
decoration: BoxDecoration(
color: const Color(0xFF0ea0aa),
),
),
Container(
width: double.infinity,
child: GestureDetector(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return TermNCondition();
}));
},
child: Row(
children: <Widget>[
_drawerItem('images/ic_tc.png', 'Terms &
Conditions'),
_addDivider(Colors.grey)
],
))),
],
));
_drawerItem(String imagePath, String title) =>
Row(children: <Widget>[
Container(
padding: EdgeInsets.only(left: 12, right: 8, top: 10,
bottom: 10),
child: Image(
image: AssetImage(imagePath),
height: 22,
width: 22,
),
),
Container(
padding: EdgeInsets.only(left: 8, right: 8, top: 10, bottom:
10),
child: Text(
title,
style: _textStyle,
),
),
]);
_addDivider(Color color) => Padding(
padding: EdgeInsets.only(left: 12, right: 12),
child: Divider(
height: 1,
color: color,
),
);
Click on icon and text"Terms & Conditions" is working fine, but whole view is not clickable.enter image description here
You need to Wrap GestureDector with FittedBox. this widget helps you for scaling child to parent's size
_myDrawer() => Drawer(
child: Column(
children: <Widget>[
Expanded(
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: _myDrawerHeader(),
decoration: BoxDecoration(
color: const Color(0xFF0ea0aa),
),
),
Container(
width: double.infinity,
child: GestureDetector(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return TermNCondition();
}));
},
child: FittedBox( //
fit: BoxFit.cover // here is the magic
child:Row(
children: <Widget>[
_drawerItem('images/ic_tc.png', 'Terms &
Conditions'),
_addDivider(Colors.grey)
],
))
)),
],
));
_drawerItem(String imagePath, String title) =>
Row(children: <Widget>[
Container(
padding: EdgeInsets.only(left: 12, right: 8, top: 10,
bottom: 10),
child: Image(
image: AssetImage(imagePath),
height: 22,
width: 22,
),
),
Container(
padding: EdgeInsets.only(left: 8, right: 8, top: 10, bottom:
10),
child: Text(
title,
style: _textStyle,
),
),
]);
_addDivider(Color color) => Padding(
padding: EdgeInsets.only(left: 12, right: 12),
child: Divider(
height: 1,
color: color,
),
);
For more information about this Widget, please look for docs here
you just have to change the order of container and GesterDetector. I tried and it is working pretty well.
GestureDetector(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return TermNCondition();
}));
},
child: Container(
width: double.infinity,
child: Row(
children: <Widget>[
_drawerItem('images/ic_tc.png', 'Terms &
Conditions'),
_addDivider(Colors.grey)
],
),
),
),
How can I position widgets correctly?
I supposed the positioning should be by some template and not by the eye.
Lets say i want the white square will be in the top center of the black container, half inside the black container and half outside, How can i do this?
The code:
Positioned(
top: 80,
right: 30,
left: 30,
child: Container(
height: 200,
width: 400.0,
color: Colors.black,
child: Column(
children: <Widget>[],
),
),
),
Positioned(
top: 40,
child: Container(
height: 100.0,
width: 100.0,
color: Colors.white,
),
),
You can try like this
Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(
top: 80,
right: 30,
left: 30,
child: Container(
height: 200,
width: 400.0,
color: Colors.black,
child: Column(
children: <Widget>[],
),
),
),
Positioned(
top: 40,
child: Container(
height: 100.0,
width: 100.0,
color: Colors.white,
),
),
],
)
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: () => {}),
],
),
),
I need to stack widgets like this:
I wrote the code below. However the coins are coming one after another with some default padding. How can I get something like the image above?
Row(
children: <Widget>[
Icon(
Icons.monetization_on, size: 36.0,
color: const Color.fromRGBO(218, 165, 32, 1.0),
),
Icon(
Icons.monetization_on, size: 36.0,
color: const Color.fromRGBO(218, 165, 32, 1.0),
),
],
),
You can use a Stack with Positioned to achieve this:
class StackExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
body: new Container(
padding: const EdgeInsets.all(8.0),
height: 500.0,
width: 500.0,
// alignment: FractionalOffset.center,
child: new Stack(
//alignment:new Alignment(x, y)
children: <Widget>[
new Icon(Icons.monetization_on, size: 36.0, color: const Color.fromRGBO(218, 165, 32, 1.0)),
new Positioned(
left: 20.0,
child: new Icon(Icons.monetization_on, size: 36.0, color: const Color.fromRGBO(218, 165, 32, 1.0)),
),
new Positioned(
left:40.0,
child: new Icon(Icons.monetization_on, size: 36.0, color: const Color.fromRGBO(218, 165, 32, 1.0)),
)
],
),
),
)
;
}
}
And this how you get some nice shadow drop so the icon stands out more:
class StackExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
body: new Container(
padding: const EdgeInsets.all(8.0),
height: 500.0,
width: 500.0,
// alignment: FractionalOffset.center,
child: new Stack(
//alignment:new Alignment(x, y)
children: <Widget>[
new Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
boxShadow: [
new BoxShadow(
blurRadius: 5.0,
offset: const Offset(3.0, 0.0),
color: Colors.grey,
)
]
),
child: new Icon(Icons.monetization_on, size: 36.0, color: const Color.fromRGBO(218, 165, 32, 1.0))),
new Positioned(
left: 20.0,
child: new Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
boxShadow: [
new BoxShadow(
blurRadius: 5.0,
offset: const Offset(3.0, 0.0),
color: Colors.grey,
)
]
),
child: new Icon(Icons.monetization_on, size: 36.0, color: const Color.fromRGBO(218, 165, 32, 1.0))),
),
new Positioned(
left:40.0,
child: new Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
boxShadow: [
new BoxShadow(
blurRadius: 5.0,
offset: const Offset(3.0, 0.0),
color: Colors.grey,
)
]
)
,child: new Icon(Icons.monetization_on, size: 36.0, color: const Color.fromRGBO(218, 165, 32, 1.0))),
)
],
),
),
)
;
}
}
As of November 2019 I'd like to add a second solution:
Using package: https://pub.dev/packages/assorted_layout_widgets
var widget1 = ...;
var widget2 = ...;
RowSuper(
children: [widget1, widget2],
innerDistance: -20.0,
);
This will overlap row cells by 20 pixels.
The difference from this solution to the one using Stack is that Positioned widgets in a Stack don't occupy space. So you can't make the Stack the size of its contents, unless you know their sizes in advance. However, the RowSuper will have the size of all of its children widgets.
Note, there is also a ColumnSuper. Also note I am the author of this package.
I wanted something without dependencies and without hardcoded layout.
You could enhance by making overlap use a media query to overlap in terms of %.
Widget overlapped() {
final overlap = 10.0;
final items = [
CircleAvatar(child: Text('1'), backgroundColor: Colors.red),
CircleAvatar(child: Text('2'), backgroundColor: Colors.green),
CircleAvatar(child: Text('3'), backgroundColor: Colors.blue),
];
List<Widget> stackLayers = List<Widget>.generate(items.length, (index) {
return Padding(
padding: EdgeInsets.fromLTRB(index.toDouble() * overlap, 0, 0, 0),
child: items[index],
);
});
return Stack(children: stackLayers);
}
Here is my code on Profile Picture overlapped by camera image in flutter.
Output:
Click here to view output image
Container(
constraints: new BoxConstraints(
maxHeight: 200.0,
maxWidth: 200.0
),
padding: new EdgeInsets.only(left: 16.0, bottom: 8.0, right: 16.0),
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: new DecorationImage(
image: new AssetImage('assets/images/profile.png'),
fit: BoxFit.cover,
),
),
child: Stack(
children: [
new Positioned(
right: 0.0,
bottom: 3.0,
child: Container(
constraints: new BoxConstraints(
maxHeight: 50.0,
maxWidth: 50.0
),
decoration: new BoxDecoration(
boxShadow: [
BoxShadow(
color:Color(0xFFdedede),
offset: Offset(2,2)
),
],
color: Colors.white,
shape: BoxShape.circle,
),
child: GestureDetector(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.photo_camera,
size: 34,
color: Color(0xFF00cde7),
),
),
),
),
),
],
),
)
Wraping your elements with OverflowBox and giving the maxWidth value will achieve this effect.
The following can be used in a row or a listview
return SizedBox(
width: 35, //--> list children will be 35 in width
child: OverflowBox(
maxWidth: 50, // --> allowing the child to overflow will cause overlap between elements
child: Container(
width: 50,
child: Text((index + 1).toString()),
),
),
);
You could try my package (signed_spacing_flex). It's exactly the same as a normal Row (or Column and Flex). But it also lets you set negative spacing which causes its children to overlap. You can also set which children should be on top when they overlap.
In your case it would be something like:
SignedSpacingRow(
spacing: -12.0,
stackingOrder: StackingOrder.lastOnTop,
children: <Widget>[
Icon(
Icons.monetization_on, size: 36.0,
color: const Color.fromRGBO(218, 165, 32, 1.0),
),
Icon(
Icons.monetization_on, size: 36.0,
color: const Color.fromRGBO(218, 165, 32, 1.0),
),
],
),
It also works with expanded children if you need.
Reverse variant based on #Lee Higgins
const size = 32.0;
const overlap = size - 6.0;
final containers = [
Container(
decoration: BoxDecoration(
color: Colors.grey[300],
shape: BoxShape.circle,
),
width: size,
height: size,
),
Container(
decoration: BoxDecoration(
color: Colors.grey[400],
shape: BoxShape.circle,
),
width: size,
height: size,
),
];
List<Widget> stackLayers = List<Widget>.generate(containers.length, (index) {
return Padding(
padding: EdgeInsets.fromLTRB(0, 0, index * overlap, 0),
child: containers[index],
);
});
return Stack(alignment: AlignmentDirectional.topEnd, children: stackLayers);
Stack is very much confusing.
The best solution is to use enter link description here