How to solve stack widget problem in flutter pageview? - flutter

Im developing a quotes app as a beginner in flutter.I had used a stack widget to use both image and text in the center of my screen.And added "pageview widget" to have multiple page in my app.But the problem im facing is,whenever im trying to swipe the page,image get swiped but the text stayed the same.I mean the fist page "Text", still showing in the middle of 2nd page.Moreover i cant drag to the next page while touching the letter,its only being done via touching above or under the letter.I just wants to have a simple multipage app with text and image. How can i solve this Problem?
class OverviewScreen extends StatefulWidget {
const OverviewScreen({key, Key,}) : super(key: key);
#override
_OverviewScreenState createState() => _OverviewScreenState();
}
class _OverviewScreenState extends State<OverviewScreen> {
PageController pageController =PageController(initialPage: 0);
#override
Widget build(BuildContext context) {
return MaterialApp(
home:Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
title: Text("Hu R Rehman",
style: TextStyle(fontFamily: "MonteCarlo"),),
centerTitle: true,
leading: Icon(Icons.menu),
shape:RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(bottom: Radius.circular(16))
),
backgroundColor: Colors.transparent,
elevation: 0,
),
body:Center(
child: Stack(
alignment: Alignment.center,
children: [
PageView(
controller: pageController,
children: [
Image(
image:AssetImage('Image/soc1.jpg'),
fit:BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
p1()
],
),
const Text('Text'
,style: TextStyle(fontSize: 31.0,
fontFamily:"MonteCarlo",
color: Colors.white,
fontWeight: FontWeight.w700 )
),
],
),
)
),
);
}
}
Here p1() is the second page
class p1 extends StatefulWidget {
#override
_p1State createState() => _p1State();
}
class _p1State extends State<p1> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
),
);
}
}

If you take a look at widget tree, There are two widgets PageView and Text placed as Stack Children, and according to widget priority render Text widget will be at the top. Also, it is independent from PageView, and there will be no effect on this Text widget by changing Pageview.
let say you wish to part it on 1st child of PageView, you can move it there by wrapping with stack like this
body: Center(
child: Stack(
alignment: Alignment.center,
children: [
PageView(
controller: pageController,
children: [
Stack(
alignment: Alignment.center,
children: [
Image(
image: AssetImage('Image/soc1.jpg'),
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
const Text(
'Text',
style: TextStyle(
fontSize: 31.0,
fontFamily: "MonteCarlo",
color: Colors.white,
fontWeight: FontWeight.w700,
),
),
],
),
p1()
],
),
],
),
)
Does it solve your issue?

Try putting Stack inside PageView children.
PageView(controller: pageController, children: [
Stack(
alignment: Alignment.center,
children: [
Image(
image: AssetImage('Image/soc1.jpg'),
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
const Text('Text',
style: TextStyle(
fontSize: 31.0,
fontFamily: "MonteCarlo",
color: Colors.white,
fontWeight: FontWeight.w700)),
],
),
p1(),
],
);

Related

ElevatedButton Position Changing method

I have an Elevated Button which is on of the bottom of the Page and I am a beginner sorry for this silly doubts but i can't figure out how to change the position of the button I dont know how to try positioned widget too. Kindly help me
I tried positioned widget but couldn't do well can anyone help me with this. here is my full code.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index)=> const OnBoardContent(
image: 'assets/splash-1.png',
description: "All under one roof with different approach"),
),
),
SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),
],
)
),
);
}
}
class OnBoardContent extends StatelessWidget {
const OnBoardContent({
Key? key,
required this.image,
required this.description,
}) : super(key: key);
final String image, description;
#override
Widget build(BuildContext context) {
return Column(
children: [
const SizedBox(
height: 160,
),
const Text("Naz-Kearn",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
)),
const Text("A simplify learning App",
style: TextStyle(
fontWeight: FontWeight.normal
),
),
Image.asset(image),
const SizedBox(
height: 50,
),
Text(description,
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.normal),
),
],
);
}
}
Output of the above code
You need your widgets in a stack if you want to use Positioned widget on them :
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack( //wrapped the whole column with a stack so that all the other widgets doesn't get disturbed
children: [
Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index)=> const OnBoardContent(
image: 'assets/splash-1.png',
description: "All under one roof with different approach"),
),
),
],
),
Positioned(
top: MediaQuery.of(context).size.height*0.7, //change the 0.7 part to any number you like
child: SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),
),
],
)
),
);
}
}
class OnBoardContent extends StatelessWidget {
const OnBoardContent({
Key? key,
required this.image,
required this.description,
}) : super(key: key);
final String image, description;
#override
Widget build(BuildContext context) {
return Column(
children: [
const SizedBox(
height: 160,
),
const Text("Naz-Kearn",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
)),
const Text("A simplify learning App",
style: TextStyle(
fontWeight: FontWeight.normal
),
),
Image.asset(image),
const SizedBox(
height: 50,
),
Text(description,
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.normal),
),
],
);
}
}
try this code, you can use alignment property of the Stack widget to center everything.
SafeArea(
child: Stack(
alignment: Alignment.center, //do this
children: [
You can wrap your button with Padding widget which helps you to add padding as you like
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index)=> const OnBoardContent(
image: 'assets/splash-1.png',
description: "All under one roof with different approach"),
),
),
Padding(
padding: EdgeInsets.all(8),
child: SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),),
],
)
),
);
}
Firstly please mention what precisely the issue you are facing. If you have a problem with the get started button, what is the expected place for the get started button in the design?
Based on the code given, I'm hoping that the get started button should be at the bottom of the screen with some space below. You have already placed the button at the bottom, but you are not able to give space below.
There are some possible ways, you can use it with the get started button component.
Instead of this,
SizedBox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: (){},
child: const Text("Tap to get started"),
),
),
Option 1
Use container with margin
Container(
height: 30,
width: 200,
margin: EdgeInsets.only(
bottom: 50,
),
child: ElevatedButton(
onPressed: () {},
child: const Text("Tap to get started"),
),
),
Option 2
Wrap existing SizedBox with padding widget
Padding(
padding: EdgeInsets.only(bottom: 50.0),
child: Sizedbox(
height: 30,
width: 200,
child: ElevatedButton(
onPressed: () {},
child: const Text("Tap to get started"),
),
),
),
Even with some more ways to move the button wherever you need, you can try your own with the following widgets Expanded(), Spacer(), SizedBox(), Positioned() and etc.

Text widget always stays on top and doesn't disappear as I scroll

My text widget "More" always stays on top even though I scroll down, I'm not finding the root of this issue,
I've tried wrapping it in a SingleChildScrollView widget but still nothing has changed, are there any arguments for the Text widget that allows it to scroll as the user scrolls that I don't know of? Or is it something else entirely?
Code:
class MorePage extends StatefulWidget {
#override
_MorePageState createState() => _MorePageState();
}
class _MorePageState extends State<MorePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: white,
body: Stack(
// YESSSS
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center, children: [
SizedBox(height: 45.0),
Padding(
padding: const EdgeInsets.symmetric(horizontal: kDefaultPaddin),
child: SizedBox(
height: 25,
child: Text(
"MORE",
style: TextStyle(
color: black,
fontFamily: "Raleway",
fontWeight: FontWeight.w700,
fontSize: 25),
textAlign: TextAlign.center,
),
),),
]),
Container(
// YESSSS
child: getBody(),
),
],
),
);
}
You are using Stack(), Stack will overlay children on top of others.
while using Stack wrap with fixed-Sized Widget, It can be just Container(), also while using Stack, use Aligning widgets as child => Center, Align, Positioned, else use stack fit property,
to know more about Stack Visit https://api.flutter.dev/flutter/widgets/Stack-class.html
import 'package:flutter/material.dart';
class MorePage extends StatefulWidget {
#override
_MorePageState createState() => _MorePageState();
}
class _MorePageState extends State<MorePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Container(
child: Stack(
// YESSSS
children: <Widget>[
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
SizedBox(height: 45.0),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 22),
child: SizedBox(
height: 25,
child: Text(
"MORE",
style: TextStyle(
color: Colors.black,
fontFamily: "Raleway",
fontWeight: FontWeight.w700,
fontSize: 25),
textAlign: TextAlign.center,
),
),
),
]),
Center(
child: Container(
color: Colors.amber,
// YESSSS
height: 1333,
child: Text("Body")
// getBody(),
),
),
],
),
),
),
);
}
}

Flutter: line spacing affecting first line, problem with Positioned widget as a solution

I need to modify the line spacing. Unfortunately, the height parameter of TextStyle affects the first line as well what you can see here:
class Screen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
appBar: AppBar(backgroundColor: Colors.blue.withOpacity(0.5)),
body: Container(
color: Colors.yellow,
child: Container(
color: Colors.red,
child: Text(
'first line\nsecond line',
style: TextStyle(height: 2.5, fontSize: 20),
),
),
),
);
}
}
I immediately thought of a solution: Stack with Positioned widget, with negative top value. Let's do it in two steps, first embed it in Stack.
class Screen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
appBar: AppBar(backgroundColor: Colors.blue.withOpacity(0.5)),
body: Container(
color: Colors.yellow,
child: Stack(
children: <Widget>[
Container(
color: Colors.red,
child: Text(
'first line\nsecond line',
style: TextStyle(height: 2.5, fontSize: 20),
),
),
],
),
),
);
}
}
Output looks exactly like before:
Second step: wrap it with Positioned widget.
class Screen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
appBar: AppBar(backgroundColor: Colors.blue.withOpacity(0.5)),
body: Container(
color: Colors.yellow,
child: Stack(
// fit: StackFit.loose,
children: <Widget>[
Positioned( // .fill
top: -20,
// bottom: 0,
// left: 50,
// right: 0,
child: Container(
color: Colors.red,
child: Text(
'first line\nsecond line',
style: TextStyle(height: 2.5, fontSize: 20),
),
),
),
],
),
),
);
}
}
This is almost what I wanted. However, if you pay attention to the colors, what was before blue, is now yellow. Adding Positioned widget makes Stack to be expanded rather than fit the content - that prevents me from using it in more complex layouts - e.g. ListView. Flutter outputs warning RenderStack object was given an infinite size during layout.
I noticed that Positioned widget does it as soon as you add any of top/left/bottom/right - before it fits the content. I tried to experiment with Stack's fit property, of Positioned with .fill initializer, but I didn't succeed.

Create device height background element

I am very new to flutter so please be fair.
I would like to create the following.
Layout
Background which is always the entire screen-size (includes multiple stacked images)
Content (adapts to the the normal app ui behaviours -> ui element like keyboard)
I can't seem to figure out how to create this background element which should not resize when the keyboard is pulled out.
I have this and I hope someone could give me a hand.
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
var insetHeight = MediaQuery.of(context).viewInsets.bottom;
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Stack(
children: <Widget>[
Stack(
children: <Widget>[
Positioned(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height + insetHeight,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/background.png"),
fit: BoxFit.cover,
alignment: Alignment.bottomCenter,
),
)
),
),
],
),
SizedBox(
width: 370,
child: SingleChildScrollView(
physics: PageScrollPhysics(), // dont really need this
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: Text("Login to",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "Opensans",
fontSize: 30,
letterSpacing: .6,
color: Colors.black45,
fontWeight: FontWeight.normal
)
),
),
Card(
child: Padding(padding: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 0), child: LoginForm()),
)
],
),
)
)
],
),
);
}
}
I have tried to use the MediaQuery.of(context).viewInsets.bottom; but it's always returning 0.
I am not sure how to solve this.
The Scaffold rebuilds its body when keyboard is visible.
So move your background widget outside the Scaffold.
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
SizedBox.expand(
child: Image.asset(
"assets/images/background.png",
fit: BoxFit.cover,
),
),
Scaffold(
backgroundColor: Colors.transparent, //Should be transparent
body: Center(
child: TextField(),
),
),
],
);
}
}
For background, Try following:
Create a variable Size _screensize in _MyHomePageState.
Override initState in _MyHomePageState and do following:
#override
void initState() {
super.initState();
_screenSize ??= MediaQuery.of(context).size;`
}
Use this _screenSize as width and height for Positioned as below:
Positioned(
width: _screenSize.width,
height: _screenSize.height,
),
Add other normal widgets as usual.
Summary for background:
step 1: creating a private reference for size to use.
step 2: updating the private size variable only when it is null, which is only when the widget state is initialized the first time.
step 3: using private size as height and width for the background.

Overlay a card partially on an image

I am trying to partially overlay a Card on an image using Stack, just like this
So this is what I have tried
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: Container(
margin: const EdgeInsets.all(10.0),
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
ClipRRect(
child: Image.asset("assets/images/placeholder.jpg"),
borderRadius: new BorderRadius.circular(8.0),
), // image
new Positioned(
child: Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text('1625 Main Street',
style: TextStyle(fontWeight: FontWeight.w500)),
subtitle: Text('My City, CA 99984'),
leading: Icon(
Icons.restaurant_menu,
color: Colors.blue[500],
),
),
],
),
) //card
)
],
)),
);
}
However it displays the card at the bottom of the image but trying to overlap it partially over the image with the help of Stack's bottom, top arguments makes the card not display all together. How can I go about it?
I think the issue is that when you're making your stack, you're not allowing it to size itself properly. A stack sizes itself to any children which are not positioned - in your case, the ClipRRect. The ClipRRect looks like it is sized to its child image, which has a defined height. So the stack will also be this size I believe (you can turn on debug painting to see).
It looks like you want the image and white to be the background for your entire page, which means that you should be letting the stack expand to the size of the page. Wrapping your image in an alignment should do this.
The next part is that you've made your card positioned, but not defined any parameters. You want to define at the least the top, but probably also the left and right.
This works for me (although I'm not using all the same widgets, but it should apply anyways):
import 'package:flutter/material.dart';
main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Card over stack"),
),
body: Stack(
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child: Container(
decoration:
BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(10.0)), color: Colors.lightBlueAccent),
height: 100,
),
),
Positioned(
top: 60,
right: 10,
left: 10,
child: Card(
child: ListTile(
title: Text('1625 Main Street', style: TextStyle(fontWeight: FontWeight.w500)),
subtitle: Text('My City, CA 99984'),
leading: Icon(
Icons.restaurant_menu,
color: Colors.blue[500],
),
),
),
)
],
),
),
);
}
}