I'm using a Stack to Positioned one widget on top of an Image.asset widget, but the problem I have is that my whole Stack widget is not scrollable to see the whole content. I wrapped the Stack widget with a SingleChildScrollView but the problem still persists. If I wrap the Stack widget with a Containter and give the height: MediaQuery.of(context).size.height, it's scrollable but I can't still see the whole content of the page. Where is my mistake, that's what I'm wondering? With what widget should I wrap Stack or is there a better way for my problem? In short, I'm stacking a Column on top of an Image and I need the whole Stack widget to be scrollable so I can see the whole content of the Stack widget. Here is the code:
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: SafeArea(
child: SingleChildScrollView(
child: Stack(
overflow: Overflow.visible,
children: [
Image.asset(
'lib/modules/common/images/logo.png',
width: double.infinity,
height: 196.0,
),
Positioned(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
top: 136.0,
child: Column(
children: [
Container(), // some content inside the container
Container(), // // some content inside the container
],
),
),
],
),
),
),
);
}
Thanks in advance for the help!
if you mean to have a image on back and scrollable content at fron check this answer, if not let me know and share a prototype/image that you want.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: SafeArea(
child: SingleChildScrollView(
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 3,
child: Stack(
fit: StackFit.loose,
children: [
Align(
alignment: Alignment.topCenter,
child: Image.asset(
'assets/image.jpg',
width: double.infinity,
height: 196.0,
),
),
Positioned(
top: 136.0,
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisSize: MainAxisSize.min,
children: List.generate(
2,
(index) => Container(
height: 100,
width: double.infinity,
color: index % 2 == 0
? Colors.amberAccent
: Colors.cyanAccent,
), // some content inside the container
// some content inside the container
),
),
),
),
],
),
),
),
),
);
}
Related
In my layout I have two Widgets in a row, a text and a button.
How can I achieve something like below, where only the Text is centered, and the icon is simply next to it?
---------------------------
Text *
---------------------------
Using Row would center all the contents and would output something like
---------------------------
Text *
---------------------------
Tried: Row(children:[widget1, widget2], mainAxisAlignment: MainAxisAlignment.center);
But this centers both items, causing the text to look off-centered.
You can use CompositedTransformTarget and CompositedTransformFollower as mentioned on comment section by pskink.
class AppPT extends StatelessWidget {
const AppPT({super.key});
#override
Widget build(BuildContext context) {
final LayerLink _layerLink = LayerLink();
return Scaffold(
body: Column(
children: [
Stack(
children: [
Align(
child: CompositedTransformTarget(
link: _layerLink,
child: Container(
color: Colors.red,
width: 100,
height: 60,
alignment: Alignment.center,
child: Text("btn"),
),
),
),
CompositedTransformFollower(
link: _layerLink,
targetAnchor: Alignment.centerRight,
followerAnchor: Alignment.centerLeft,
child: Container(
color: Colors.cyanAccent,
width: 12,
height: 12,
alignment: Alignment.center,
child: Text("*"),
),
),
],
)
],
),
);
}
}
There are few tricks I can think of,
You can use Stack widget with Position.
including another widget on right by applying opacity(invisible) on current snippet.
using transform will be handle if you know the width of the widget.
Transform.translate(
offset: Offset(20 / 2, 0), //20 is the * box size
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
color: Colors.red,
width: 100,
height: 60,
alignment: Alignment.center,
child: Text("btn"),
),
Container(
color: Colors.green,
width: 20,
height: 20,
child: Center(child: Text("*")),
),
],
),
),
Place text and second widget inside row then put the row inside container with alignment center and use SizedBox for spacing between widget instead of Padding Widget.
Container(
color: Colors.green,
alignment: Alignment.center,
height: 100,
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Text("Text"),
SizedBox(width: 10),
Text("*"),
],
),
);
i try to fill background of picture use mediaquery to fill picture. ios work fine but android its doesn't work i use media query to fill picture and then got this
can i make another way to fill it ?
here is code
#override
Widget build(BuildContext context) {
double size = MediaQuery.of(context).size.width;
return Scaffold(
body: Form(
key: formKey,
child: SingleChildScrollView(
child: Stack(
children: <Widget>[
buildBackgroud(context),
GestureDetector(
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
behavior: HitTestBehavior.opaque,
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: size * 0.3,
),
buildTopic('General Information'),
buildTextBoxEmail(size),
buildTextBoxUserName(size),
buildTextBoxPassword(size),
buildButton(size, context),
Row(
children: [
IconButton(onPressed: (){}, icon: Icon(Icons.add_photo_alternate))
],
)
],
),
),
)
],
),
),
));
}
background method is
SvgPicture buildBackgroud(BuildContext context) {
return SvgPicture.asset(
'assets/images/bg.svg',
alignment: Alignment.center,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
fit: BoxFit.fill,
);
}
You can try this one, wrapping SvgPicture.asset() into SizedBox and giving full screen height and width into it in your buildBackground function.
SvgPicture buildBackgroud(BuildContext context) {
return SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
SvgPicture.asset(
'assets/images/bg.svg',
alignment: Alignment.center,
fit: BoxFit.cover,
)
);
}
I am trying to achieve scroll in Flutter Web where I have few containers which are stacked and I use SingleChildScrollView to scroll the widget. However, when I scroll the first container everything working fine but the second one which is a child of the second container responds to the scroll without completing the initial one. And also is there a way to make a sticky header for the second container. How can I make the 3rd container(orange) to scroll after the 2nd(blue) one is finished scrolling? Here is what I am trying to achieve:
https://yobithemes.com/demo/html/freda/dark-video-index.html
And here what I got so far:
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
IntroScreen(),
SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height - 100,
),
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.blue,
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
),
Container(
padding: EdgeInsets.only(top: 100),
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.orange,
),
],
),
),
),
],
),
),
),
],
),
);
}
}
You can achieve it by using sliver.
SliverToBoxAdapter fill the transparent area with screen height - app bar height.
SliverAppBar: make it sticky by setting floating and pin to true
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
IntroScreen(),
CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Container(
height: MediaQuery.of(context).size.height - 50,
),
),
SliverAppBar(
// toolbarHeight: 50,
floating: true,
pinned: true,
title: Container(
child: Center(child: Text('Header')),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => Container(
height: MediaQuery.of(context).size.height-50,
color: Colors.primaries[index % Colors.primaries.length],
),
),
),
],
),
],
),
);
}
}
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 want to achieve an effect similar to this one:
Here's what I have: (Blue container is hidden below the appBar)
And this is my current code:
Widget build(BuildContext context) {
return Scaffold(
appBar: GradesAppBar(
title: "Grades",
gradientBegin: Colors.red[200],
gradientEnd: Colors.red,
),
body: Stack(
fit: StackFit.expand,
overflow: Overflow.visible,
children: <Widget>[
Positioned(
top: -20,
left: MediaQuery.of(context).size.width / 2 - 150,
child: Container(
color: Colors.blue,
width: 300,
height: 60,
),
),
],
),
);
}
The GradesAppBar is a Container with boxShadow, borderRadius and gradient decoration.
When you're using stack to achieve this UI approach you should remove the AppBar and make it like this :-
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
alignment: Alignment.center,
fit: StackFit.expand,
overflow: Overflow.visible,
children: <Widget>[
GradesAppBar(
title: "Grades",
gradientBegin: Colors.red[200],
gradientEnd: Colors.red,
),
Positioned(
top: -20,
left: MediaQuery.of(context).size.width / 2 - 150,
child: Container(
color: Colors.blue,
width: 300,
height: 60,
),
),
],
),
);
}
The most important thing; if your GradesAppBar extends PreferredSizeWidget I think you should replace it with Container and give it some cool decorations as you want :")