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'),
)
],
),
),
),
),
What I want to achieve
I want to have the very first widget of a ScrollView initially centered. But if the scrollview gets scrolled, the scrollview should be has the same width as the parent and the centered widget should be the selected one.
Approach
My first idea was to use the initialScrollOffset property. but this seems to be without any effect.
#override
Widget build(BuildContext context) {
return ListView(
scrollDirection: Axis.horizontal,
children: _buildCarouselItems(),
itemExtent: FrettirConstants.cardWidth,
controller: new ScrollController(
debugLabel: "Carousel",
initialScrollOffset: -200,
keepScrollOffset: true
),
);
}
Sketch
This may sound like a bad practice to achieve it, but you can add an empty Container with the 3/4 width of other carousel widgets to the first position.
In my dummy code each carousel widget has length 160, and empty Container must have 3/4 of other widgets. This way first carousel widget is fully visible while second one has 3/4 visibility.
Container(
width: 160.0 * 3 / 4,
color: Colors.transparent,
),
Container(
margin: EdgeInsets.only(
right: 10.0
),
width: 160.0,
color: Colors.red,
),
Container(
margin: EdgeInsets.symmetric(
horizontal: 10.0
),
width: 160.0,
color: Colors.blue,
),
I need to rotate a text inside a card. What I would like to obtain is this:
But I don't know how can i do this with flutter. The problem I am facing is that the text view exceeds the card.
Here is what I have so far:
Widget cardDetails(String title, String imgPath) {
return Material(
elevation: 8.0,
borderRadius: BorderRadius.circular(15.0),
child: Container(
height: 135.0,
width: 135.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0), color: Colors.white),
child: Stack(
alignment: Alignment.topLeft,
children: <Widget>[
Transform.rotate(
angle: -pi / 4,
child: Container(
height: 15.0,
width: 55.0,
alignment: Alignment.topCenter,
color: const Color(0xFFFFd77B),
child: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 12.0,
),
),
),
),
],
),
),
);
}
And here it's how it looks like:
Thanks in advance
The simplest way to make a banner is to use the Banner widget. However, it still paints outside the bounds of the item you're using, and unfortunately is not nearly as configurable as it could be (and doesn't handle things like longer text).
To fix the painting outside the bounds, all you need to do is add a ClipRect right under your card widget, and that should fix the overflow with the Banner widget or for what you're doing with the rotated box.
Depending on how configurable you need the banner to be, you could re-implement the Banner widget - using TextPainter you could figure out the length of the text and resize automatically based on it if need be (and to remove the dropshadow...)
Code:
CustomScrollView(
slivers: <Widget>[
SliverAppBar(
expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(
title: Container(color: Colors.red, child: Text("Flexible title")),
background: Image.asset("assets/chocolate.jpg", fit: BoxFit.cover),
),
),
SliverList(delegate: SliverChildListDelegate(_buildChildren())),
],
);
Why there is a default padding in the title. I used Container to bring contrast so that the margin can be visible easily. Even I tried using centerTitle: false and it didn't change anything.
You can now use the titlePadding attribute like so:
flexibleSpace: FlexibleSpaceBar(
title: Text('Home'),
titlePadding: EdgeInsetsDirectional.only(
start: 0.0,
bottom: 16.0,
),
),
In _FlexibleSpaceBarState in method build:
Container(
padding: EdgeInsetsDirectional.only(
start: effectiveCenterTitle ? 0.0 : 72.0,
bottom: 16.0
)
So, there is no way to remove this bottom padding except customization
For testing I've changed one string in source code to bottom: 0.0 and this padding disappeared.
not centered, EdgeInsetsDirectional.only(start 0, bottom: 16) otherwise.
final EdgeInsetsGeometry titlePadding;
Is it possible to fix an object in the screen that stays fixed regardless of scrolling?
Something similar to CSS position fixed.
You can absolutely position a child of a Stack widget using the Positioned widget.
The minimal example below places the red box above the list view, by placing the child in a Positioned widget after the ListView in the Stack's children.
List<String> todos = [...];
return new Stack(
children: <Widget>[
new ListView(
children: todos
.map((todo) => new ListTile(title: new Text(todo)))
.toList(),
),
new Positioned(
left: 30.0,
top: 30.0,
child: new Container(
width: 100.0,
height: 80.0,
decoration: new BoxDecoration(color: Colors.red),
child: new Text('hello'),
)
),
],
);
And here it is inside of a Scaffold body. If you add more items you'll find that the list scrolls without moving the red box.
You could use Positioned widget in a Stack Widget with AspectRatio widget and use the % distance like the below code.
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; //get the screen size
List<String> todos = [...];
//the below if to get the aspect ratio of the screen i am using the app only in landscape
//if you need to use it in portrait you should add the sizes below
if((size.width / size.height) > 1.76){
aspect = 16 / 9;
}else if((size.width / size.height) < 1.77 && (size.width / size.height) >= 1.6){
aspect = 16 / 10;
}else{
aspect = 4 /3;
}
return new Scaffold(
body: new Center(
//layoutBuilder i can use the constraints to get the width and height of the screen
child: new LayoutBuilder(builder: (context, constraints) {
return new AspectRatio(
aspectRatio: aspect,
child: new Column(
children: <Widget>[
new ListView(
children: todos
.map((todo) => new ListTile(title: new Text(todo)))
.toList(),
),
new Positioned(
//constraints.biggest.height to get the height
// * .05 to put the position top: 5%
top: constraints.biggest.height * .05,
left: constraints.biggest.width * .30,
child: new Container(
width: 100.0,
height: 80.0,
decoration: new BoxDecoration(color: Colors.red),
child: new Text('hello'),
),
),
],
),
),
}),
),
);
}
}
Hope it will help you....
I prefer this solution:
Stack(
children: [
Column(
children: [
Container(...),
Container(...),
]
),
Positioned(top:50, child: Card(...))
]
)
Widget build(BuildContext context) {
return Column(
children: [
Container(
// covers 20% of total height
height: 200,
child: Stack(
children: [
Container(
height: 300,
decoration: BoxDecoration(
color: Colors.red,
),
),
Positioned(
bottom: 0,
left: 0,
width: 100,
height: 100,
child: Container(
height: 54,
decoration: BoxDecoration(
color: Colors.blue,
),
),
)
],
),
),
],
);
}
Adding a width and height to your Positioned widget will make it appear if you want to use top/left/bottom/right