Positioned Widget in Column Causes Card to Overflow - dart

I am currently learning flutter and have come across an issue where the card is not staying within the boundaries of Column, but is not causing an overflow. My goal is to have the card positioned at the bottom and with Text positioned above the card.
Here is my code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height,
child:
Image.asset("assets/testimage.jpg", fit: BoxFit.cover)),
Positioned(
bottom: 10.0,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
child: Text(
"A description would be going here, this is just placeholder text.",
style: TextStyle(fontSize: 30),
),
),
)
],
),
],
),
),
);
}
}
and an image example of the problem and desired outcome
Problem
Desired Outcome

You need to define - right: 1.0, left: 1.0, also along with bottom in Positioned. widget.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height,
child: Image.network("https://placeimg.com/640/480/any",
fit: BoxFit.cover)),
Positioned(
bottom: 1.0,
right: 1.0,
left: 1.0,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"A description would be going here, this is just placeholder text.",
style: TextStyle(fontSize: 30),
),
),
),
)
],
),
],
),
);
}
Output:

Related

How do I add SingleChildScrollView to a column

I'm developing an app and was following a sample from this link and ran into a problem where it says bottom overflowed by xx pixels as shown below:
Now, I encountered this before and solved it by adding SingleChildScrollView as shown below:
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Academy',
theme: new ThemeData(
primaryColor: Color.fromRGBO(58, 66, 86, 1.0)
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: new Container(
child: SingleChildScrollView(
child: LoginScreen(),
)
),
),
);
}
How do I do it when I'm not using a container but a column instead ? As that is what I'm using in the image above (column at the bottom of code, where the author returns the scaffold):
class DetailPage extends StatelessWidget {
final Lesson lesson;
DetailPage({Key key, this.lesson}) : super(key: key);
#override
Widget build(BuildContext context) {
final levelIndicator = Container(
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: lesson.indicatorValue,
valueColor: AlwaysStoppedAnimation(Colors.green)),
),
);
final coursePrice = Container(
padding: const EdgeInsets.all(7.0),
decoration: new BoxDecoration(
border: new Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(5.0)),
child: new Text(
"\$" + lesson.price.toString(),
style: TextStyle(color: Colors.white),
),
);
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 120.0),
Icon(
Icons.directions_car,
color: Colors.white,
size: 40.0,
),
Container(
width: 90.0,
child: new Divider(color: Colors.green),
),
SizedBox(height: 10.0),
Text(
lesson.title,
style: TextStyle(color: Colors.white, fontSize: 45.0),
),
SizedBox(height: 30.0),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(flex: 1, child: levelIndicator),
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
lesson.level,
style: TextStyle(color: Colors.white),
))),
Expanded(flex: 1, child: coursePrice)
],
),
],
);
final topContent = Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10.0),
height: MediaQuery.of(context).size.height * 0.5,
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("assets/images/drones1.jpg"),
fit: BoxFit.cover,
),
)),
Container(
height: MediaQuery.of(context).size.height * 0.5,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
child: Center(
child: topContentText,
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContentText = Text(
lesson.content,
style: TextStyle(fontSize: 18.0),
);
final readButton = Container(
padding: EdgeInsets.symmetric(vertical: 16.0),
width: MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () => {},
color: Color.fromRGBO(58, 66, 86, 1.0),
child:
Text("TAKE THIS LESSON", style: TextStyle(color: Colors.white)),
));
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(40.0),
child: Center(
child: Column(
children: <Widget>[bottomContentText, readButton],
),
),
);
return Scaffold(
body: Column( //here is the column
children: <Widget>[topContent, bottomContent],
),
);
}
}
I tried these but it does not work, giving me the same result as before:
return Scaffold(
body: Container(child: SingleChildScrollView(child:Column(children: <Widget>[topContent, bottomContent],),),),
);
return Scaffold(
body: Column(
children: <Widget>[Expanded(child: Column(children: <Widget>[topContent, bottomContent],))],
),
);
return Scaffold(
body: SingleChildScrollView(child: Container(child:Column(children: <Widget>[topContent, bottomContent],),),),
);
My outcome when I tried this as suggested:
return Scaffold(
body: Column( //here is the column
children: <Widget>[Expanded(child: SingleChildScrollView(child: Text("Test"))), Text("Data")],
),
);
I solved it by adding the SingleChildScrollView to the following in topContent:
Container(
height: MediaQuery.of(context).size.height * 0.5,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
child: SingleChildScrollView(
child: Center(
child: topContentText,
),
),
),

How to implement boxes that fill the screen & I dont see my drawer

I'm trying to implement a UI design, something like this:
And that's what I've achieved so far:
I got stuck in the stage of filling the screen with boxes, I tried to implement this in multiple ways(expanded, containers etc), but the result didn't satisfy me.
How do i implement this?
And I also have another problem, when i create the drawer it work(i can scroll the screen to the right and the drawer navigation screen appears), But i can't see the drawer icon.
By the way, if you have suggestions for improving the code or things I could write better i'll be glad to hear that
My code:
class Sample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(),
body: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 2,
width: double.infinity,
color: Color.fromRGBO(50, 50, 205, 1),
),
Opacity(
child: Image.network(
'https://cdn.pixabay.com/photo/2015/04/23/21/36/auto-736794__340.jpg',
//half of the screen
height: MediaQuery.of(context).size.height / 2,
fit: BoxFit.cover,
),
opacity: 0.3,
),
SafeArea(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 58.0),
child: Text(
'Parking App',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
),
],
),
),
],
),
],
),
);
}
}
There might be better ways to achieve this, but here's the solution with rows and columns:
import 'package:flutter/material.dart';
class SamplePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
body: Column(
children: <Widget>[
Image.network(
"http://i63.tinypic.com/16p2xu.jpg",
fit: BoxFit.cover,
height: screenHeight / 2,
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.account_balance),
SizedBox(height: 10),
Text("My Stats"),
],
),
),
Expanded(
child: Container(
color: Colors.indigo,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Icon(Icons.accessibility, color: Colors.white),
SizedBox(height: 10),
Center(
child: Text(
"Component",
style: TextStyle(color: Colors.white),
),
)
],
),
),
),
],
),
),
Expanded(
child: Container(
color: Colors.cyanAccent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.access_alarm),
SizedBox(height: 20),
Text("Workout"),
],
),
),
),
],
),
),
],
),
);
}
}
Result:
you can achieve similar layout using stack. i demonstrated as below.
Note: make sure that you are using full screen with content otherwise black screen will be there.
class Sample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Column(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 2,
width: double.infinity,
decoration: BoxDecoration(
color: Color.fromRGBO(50, 50, 205, 0.3),
image: DecorationImage(
image: NetworkImage(
'https://cdn.pixabay.com/photo/2015/04/23/21/36/auto-736794__340.jpg',
),
fit: BoxFit.cover,
),
),
),
],
),
Scaffold(
backgroundColor: Colors.transparent,
drawer: Drawer(),
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
title: new Text("Demo"),
centerTitle: true,
),
body: Column(
children: <Widget>[
Expanded(
child: Center(
child: new Container(
decoration: BoxDecoration(
color: Colors.red
),
child: new Text("book"),
),
),
)
],
),
),
],
);
}
}

Horizontal ListView.builder overflow width bound when scroll

I am trying to use ListView.builder to display a horizontal list in a Stack but am encountering this weird bug when scrolling ListView if I set itemCount: 10. If I set itemCount: 20 the ListView scrolls like normal.
I have tested in the emulator (Galaxy Nexus 720x1280 android 5.0) and on a real device (Nokia 7 plus, android 9.0). How can I fix this?
class BugPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: <Widget>[
Positioned(
left: 20.0,
right: 20.0,
height: 60.0,
bottom: 70.0,
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10, // Overflow when scroll.
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 3.0,
),
child: Container(
width: 40.0,
height: 40.0,
color: Colors.red,
child: Center(child: Text("$index")),
),
);
},
),
),
SizedBox(width: 10.0),
FloatingActionButton(
backgroundColor: Colors.blue,
onPressed: () {},
child: new Icon(
Icons.add,
color: Colors.black,
),
),
],
),
),
],
),
),
);
}
}
Expected output:
Actual output:
And a video of the problem
I tried your code and run with bigger intemcount too without problems, but i have an advice, change the
SizedBox(width: 10.0)
for a padding around the button
Padding(
padding: const EdgeInsets.only(left: 10),
child: FloatingActionButton(
backgroundColor: Colors.blue,
onPressed: () {},
child: new Icon(
Icons.add,
color: Colors.black,
),
)
)
It seems like this bug appears in old flutter version after I updated to newest version everything is ok.

how to set CupertinoSegmentedControl height?

I am trying to use CupertinoSegmentedControl from the flutter Cupertino library in the AppBar using the bottom attribute to achieve the following design (height = 32)
so I tried the following :
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 2,
backgroundColor: Colors.white,
centerTitle: true,
title: Text(this.widget.title, style: TextStyle(color: Colors.black)),
bottom: PreferredSize(
child: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 12),
child: Row(
children: <Widget>[
SizedBox(width: 24),
Expanded(
child: CupertinoSegmentedControl(
children: this.widget.tabs,
groupValue: this._selectedTab,
onValueChanged: (value) {
this.setState(() => this._selectedTab = value);
this._tabController.animateTo(value);
}
),
),
SizedBox(width: 24)
],
),
),
preferredSize: Size(double.infinity, 48)
)
),
body: new TabBarView(
controller: this._tabController,
children: this.widget.views,
));
}
Is something like that similar to the layout that you want? (Removing the green color of course ^_^)
Play around with the Container and PreferredSize heights to adjust the height to fit your needs.
Scaffold(
appBar: AppBar(
elevation: 2,
backgroundColor: Colors.white,
centerTitle: true,
title:
Text(this.widget.title, style: TextStyle(color: Colors.black)),
bottom: PreferredSize(
child: Row(
children: [
Expanded(
child: Container(
height: 48,
color: Colors.lightGreenAccent,
child: CupertinoSegmentedControl(
children: children,
groupValue: this._selectedTab,
onValueChanged: (value) {
this.setState(() => this._selectedTab = value);
}),
),
)
],
),
preferredSize: Size(double.infinity, 48))),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('hello')
]
)
)
);
UPDATE:
As kazimad pointed out, if you want to increase the segmented control height and not only add padding to it insiede the app bar, you can add a Padding widget to your tabs, like that:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 2,
backgroundColor: Colors.white,
centerTitle: true,
title:
Text(this.widget.title, style: TextStyle(color: Colors.black)),
bottom: PreferredSize(
child: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 12),
child: Row(
children: <Widget>[
SizedBox(width: 24),
Expanded(
child: CupertinoSegmentedControl(
children: const <int, Widget>{
0: Padding(
padding: EdgeInsets.all(8.0),
child: Text('Midnight')),
1: Padding(
padding: EdgeInsets.all(8.0),
child: Text('Viridian')),
2: Padding(
padding: EdgeInsets.all(8.0),
child: Text('Cerulean'))
},
groupValue: this._selectedTab,
onValueChanged: (value) {
// TODO: - fix it
}),
),
SizedBox(width: 24)
],
),
),
preferredSize: Size(double.infinity, 48))),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Text('hello')])));
}
just add Padding widget, or margin property to Container and wrap your Widgets in your "tabs" collection (in you case it is this.widget.tabs) with it
in my case
CupertinoSegmentedControl<int>(
children: segmentTextWidgets,
...
),
final Map<int, Widget> segmentTextWidgets = <int, Widget>{
0: Container(
margin: const EdgeInsets.symmetric(vertical: 16),
child: Text("Tab 1 title"),
),
1: Container(
margin: const EdgeInsets.symmetric(vertical: 16),
child: Text("Tab 2 title"),
),
};

A problem in using ClipRRect() in Flutter

I have used ClipRRect for rounded corners in the UI. The ClipRRect wraps topContent and bottomContent are a stack and a Column respectively. But, the bottom corners are not round. What may be the reason behind this?
The cardModel class is used to store the image path in this case.
class FeaturedCard extends StatelessWidget {
final FeaturedCardModel cardModel;
final double parallaxPercent;
FeaturedCard({
this.cardModel,
this.parallaxPercent = 0.0, //default value
});
#override
Widget build(BuildContext context) {
final topContent = Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(
left: 10.0,
),
height: MediaQuery.of(context).size.height * 0.3,
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(cardModel.imgUrl),
fit: BoxFit.fill,
),
)),
],
);
final bottomContentText = Text(
'This is the sample text',
style: TextStyle(fontSize: 18.0),
);
final bottomContent = Container(
height: MediaQuery.of(context).size.height * 0.5,
width: MediaQuery.of(context).size.width,
color: Colors.white,
padding: EdgeInsets.all(40.0),
child: Center(
child:
bottomContentText,
),
);
return ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Column(
children: <Widget>[
topContent,
bottomContent,
],
),
);
}
}
If you go to Flutter Inspector and do "Toggle Debug Paint" you will see that the clipping occurs in the blue area below.
You can fix it by giving a size to your clipper.
return SizedBox(
height: MediaQuery.of(context).size.height * 0.8,
child: ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Column(
children: <Widget>[
topContent,
//bottomContent,
],
),
),
);
The column that is the child of ClipRRect is taking as much space as it can get. so the border radius is applied to the bottom of the screen.
to solve that you just need to set mainAxisSize property of Column to MainAxisSize.min:
return ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
topContent,
bottomContent,
],
),
);

Resources