How to use ListView and stop element from scrolling? - flutter

I have a screen with a ListView that holds an SVG, Stack and TextFields. When the keyboard is opened, I get the usual Overflow error so I'm using a ListView to combat it since I'm using a Column anyway.
I want my SVG image to stay fixed at the top while the rest scrolls underneath it, anyway to give the image a fixed position?
child: Scaffold(
body: SafeArea(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
width: double.infinity,
child: ListView(
children: [
const SizedBox(
height: 50,
),
SvgPicture.asset( //Should stay fixed while rest scroll
'assets/example.svg',
color: primaryColor,
height: 80.0,
),
const SizedBox(height: 50),
Center(
child: Stack(
children: [
_image != null
? InkWell(
onTap: selectImage,
child: CircleAvatar(
radius: 48,
backgroundImage: MemoryImage(_image!),
),
)
: InkWell(
onTap: selectImage,
child: const CircleAvatar(
radius: 48,
backgroundImage: AssetImage('assets/user.png'),
),
),
Positioned(
bottom: -10,
left: 50,
child: IconButton(
onPressed: selectImage,
icon: const Icon(Icons.add_a_photo_outlined),
),
),
],
),
),
const SizedBox(height: 50),
TextFieldInput(...),
TextFieldInput(...),
TextFieldInput(...),
TextFieldInput(...)...
I've tried taking the SVG out of the Column and changing the ListView into a Column with a SingleChildScrollView parent and I still get Render Overflow. Code follows:
child: Scaffold(
body: SafeArea(
child: Column(
children: [
SvgPicture.asset(
'assets/example.svg',
color: primaryColor,
height: 80.0,
),
SingleChildScrollView(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
width: double.infinity,
child: Column(
children: [
const SizedBox(height: 50),
Center(
child: Stack(
children: [
_image != null
? InkWell(
onTap: selectImage,
child: CircleAvatar(
radius: 48,
backgroundImage: MemoryImage(_image!),
),
)
: InkWell(
onTap: selectImage,
child: const CircleAvatar(
radius: 48,
backgroundImage:
AssetImage('assets/user.png'),
),
),
Positioned(
bottom: -10,
left: 50,
child: IconButton(
onPressed: selectImage,
icon: const Icon(Icons.add_a_photo_outlined),
),
),
],
),
),
const SizedBox(height: 50),
TextFieldInput(..),
TextFieldInput(..),
TextFieldInput(..)...
What would be the correct approach to this?

Wrap your SingleChildScrollView in a Expanded widget, like this:
child: Scaffold(
body: SafeArea(
child: Column(
children: [
SvgPicture.asset(
'assets/example.svg',
color: primaryColor,
height: 80.0,
),
Expanded( //<--- add this
child: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
width: double.infinity,
child: Column(
children: [
const SizedBox(height: 50),
Center(
child: Stack(
children: [
_image != null
? InkWell(
onTap: selectImage,
child: CircleAvatar(
radius: 48,
backgroundImage: MemoryImage(_image!),
),
)
: InkWell(
onTap: selectImage,
child: const CircleAvatar(
radius: 48,
backgroundImage:
AssetImage('assets/user.png'),
),
),
Positioned(
bottom: -10,
left: 50,
child: IconButton(
onPressed: selectImage,
icon: const Icon(Icons.add_a_photo_outlined),
),
),
],
),
),
const SizedBox(height: 50),
TextFieldInput(..),
TextFieldInput(..),
TextFieldInput(..)...

Column by default has screen height size that is why you get render flow error when screen size increases because you're not making topmost column scrollable.
there are 2 possible solution you can do
Wrap your singleChildScrollView inside Expanded. It will adjust and scroll your all items inside remaining space after image.
Make your topmost column scrollable by wrapping inside SingleChildScrollView. It will solve render flow error issue but your screen whole screen will scroll as well.

Related

Move button to the bottom

I am trying to move the button to the bottom of the screen but in vain. I basically have 2 textEditingControllers and a button but the latter keeps sticking with the textEditingController. Any advice, please?
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
physics: const ScrollPhysics(),
child: Column(
children: [
return Card(
elevation: 5,
clipBehavior: Clip.antiAlias,
margin: const EdgeInsets.all(0),
child: Container(
padding: const EdgeInsets.all(15),
child: Row(
children: [
Column(
),
Expanded(
child: Column(
children: [
LocationField(
isDestination: false,
textEditingController: sourceController),
LocationField(
isDestination: true,
textEditingController: destinationController),
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: const EdgeInsets.all(5),
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
child: const Text('Bottom Button '), // trying to move to the bottom
),
),
)
],
);
}
Where am I going wrong?
If you are in Scaffold and want to have some Button in a fixed position on the screen you can use floatingActionButton Property.
Example:
Scaffold(
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
floatingActionButton: Container(
height: 50,
margin: const EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () {},
child: const Center(
child: Text('Hello'),
),
),
),
);
Of course floatingActionButton property is mainy used for FloatingActionButton but it's good to know that you can put there any widget (other types of buttons, Rows, Columns and others). For positioning this widget you can use 'floatingActionButtonLocation' Scaffold property.
Try below code
Column(
children: <Widget>[
Card(
elevation: 5,
clipBehavior: Clip.antiAlias,
margin: const EdgeInsets.all(0),
child: Container(
padding: const EdgeInsets.all(15),
child: Row(
children: [
Expanded(
child: Column(
children: [
Container(
width: 100,
height: 50,
color: Colors.red,
),
Container(
height: 50,
width: 100,
color: Colors.black,
),
],
),
),
],
),
),
),
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: const EdgeInsets.all(5),
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
child: const Text(
'Bottom Button '), // trying to move to the bottom
),
),
),
),
],
),
Result->
You can achieve it by making small changes in your code it self. you have to change the tree of your code as below.
Scaffold -> Body -> Column
Column First Child Should be wrapped with Expanded and then SinglechildScrollView then Column and remaining Widgets
And the Second Widget should be your Button.
This will make the Button to move to the end of the screen. I hope thats what you are trying to do.
But this way makes the Button visible on the screen all the time where as remaining widgets will be scrolling.

Issue with Row in Bottom App Bar that I'm not understanding

so I'm trying to implement a somewhat custom bottom navigation bar. I am trying to center my icons and after further investigation it is indeed working "correctly" in a way but the issue is that the bottom half of the bottom app bar gets completely ignored.
No matter what I do, the bottom half gets ignored. If I increase the size, it only makes it bigger at the top which is not what I want. How can I get the row to respect the entire bottom app bar?
Here's my code:
bottomNavigationBar: Padding(
padding: const EdgeInsets.only(left: 30, bottom: 33.0, right: 30.0),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(30.0),
),
child: BottomAppBar(
color: Color(0xFF222222),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 60.0,
child: SvgPicture.asset(
'assets/images/home.svg',
),
),
Container(
height: 60.0,
child: SvgPicture.asset(
'assets/images/discover.svg',
),
),
Container(
height: 60.0,
child: SvgPicture.asset(
'assets/images/heart.svg',
),
),
Container(
height: 60.0,
child: SvgPicture.asset(
'assets/images/user.svg',
),
),
],
),
),
),
),
Solution was to wrap BottomAppBar with SafeArea. Shoutout to Flutter discord for help on this :)
bottomNavigationBar: SafeArea(
child: Padding(
padding: const EdgeInsets.only(left: 30.0, right: 30.0),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(30.0),
),
child: BottomAppBar(
color: Color(0xFF222222),
child: Container(
height: 88.0,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(
children: [
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
'assets/images/home.svg',
),
),
Positioned(
left: 23.0,
bottom: 0,
child: Image.asset('assets/images/Ellipse5.png'),
),
],
),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
'assets/images/discover.svg',
),
),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
'assets/images/heart.svg',
),
),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(
'assets/images/user.svg',
),
),
],
),
),
),
),
),
),
),

What is the best flutter widget to use to achieve this kinda layout?

This is the UI I want to implement, I only started playing with flutter last week so I am not as fluent. I was wondering what is the best way to achieve this layout.
This is what I get with a stack and column:
This is the code:
Column(
children: <Widget>[
Expanded(
child: Container(
constraints: BoxConstraints.expand(height: 150),
color: Colors.blue,
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Positioned(
bottom: -40,
left: MediaQuery.of(context).size.width * 0.4,
// alignment: Alignment.bottomCenter,
child: Container(
constraints: BoxConstraints.expand(height: 80, width: 80),
color: Colors.green,
),
),
],
),
),
flex: 3,
),
Expanded(
child: Container(
margin: EdgeInsets.all(15.0),
color: Colors.red,
),
flex: 7,
)
],
);
I made something like the image you provided with dummy image and some icon you can change icons if you want,use media query size instead of fixed padding tops
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
child: Column(
children: [
Stack(children: [
Container(
child: FittedBox(
fit: BoxFit.fill,
child: Image.network('https://picsum.photos/300?image=10')),
height: 150,
width: double.infinity,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Padding(
padding: const EdgeInsets.only(top: 75),
child: MaterialButton(
onPressed: () {},
elevation: 2.0,
color: Colors.red,
child: Icon(
Icons.message,
size: 27.0,
),
padding: EdgeInsets.all(20),
shape: CircleBorder(),
),
),
Padding(
padding: const EdgeInsets.only(top: 75),
child: Column(children: [
CircleAvatar(
radius: 55.0,
backgroundImage:
NetworkImage('https://i.pravatar.cc/150?img=54'),
backgroundColor: Colors.transparent,
),
Text("David Beckham"),
Text("Model/SuperStar")
]),
),
Padding(
padding: const EdgeInsets.only(top: 75),
child: MaterialButton(
onPressed: () {},
elevation: 2.0,
color: Colors.blue,
child: Icon(
Icons.add,
size: 27.0,
),
padding: EdgeInsets.all(20),
shape: CircleBorder(),
),
),
],
),
]),
Container(height: 100, color: Colors.red),
Container(height: 100, color: Colors.green),
Container(height: 100, color: Colors.yellow),
Container(height: 100, color: Colors.blue),
],
)));
}
}

How to make a bottom bar with border radius using Card and add elevation to it in Flutter?

In my Flutter project, I have created a bottom bar using Container.
Here's the code given for that-
Scaffold(
body: Column(
children: <Widget>[
Container(
color: Colors.blue,
height: 300,
),
Expanded(
child: ListView(
shrinkWrap: true,
children: <Widget>[
getCarousel(),
Column(
children: <Widget>[
Container(
height: 240,
color: Colors.yellow,
),
Container(
color: Colors.teal,
height: 300,
),
],
),
Container(
height: 350,
width: double.infinity,
color: Colors.red,
child: ListView.builder(
scrollDirection: Axis.horizontal,
padding: new EdgeInsets.only(bottom: 72.0),
itemCount: itemList.length,
itemBuilder: (BuildContext context, int position) {
return new Column(
children: <Widget>[
Expanded(
child: new Container(
width: 160,
height: 320,
color: Colors.yellow[100],
),
),
new Divider()
],
);
},
),
),
],
),
),
Container(
height: 60,
width: double.maxFinite,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey),
borderRadius:
BorderRadius.vertical(top: Radius.circular(20.0))),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
showBottomIcons(Icons.home, "Home", "/HomeScreen"),
showBottomIcons(
Icons.category, "Category", "/CategoryScreen"),
showBottomIcons(Icons.shopping_cart, "Cart", "/CartScreen"),
showBottomIcons(Icons.person, "Account", "/AccountScreen"),
],
),
)
],
),
)
The Output of the screen looks like that-
Now, I want to switch the Container to Card. But I got some problems-
Card is taking some by default padding and the border radius at two top corners are not working.
As the top two corners are rounded, the background is getting white(As you can see in image). I want that space red colored.
I need some elevation with border radius like below image using card-
& 3. You don't actually need card widget for this. You can add shadow on your container itself.
You have to use stack to achieve this.
As I am hoping you are using the same code as my previous answer of your another question. I have updated the answer with stack layout & your requirements
Container(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned.fill(
child: Container(
color: Colors.blue,
alignment: Alignment.center,
child: Text("Hello"),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 50,
width: double.maxFinite,
decoration: BoxDecoration(
boxShadow: [
new BoxShadow(
color: Colors.black,
blurRadius: 2.0,
),
],
color: Colors.yellow,
borderRadius:
BorderRadius.vertical(top: Radius.circular(20.0))),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_forward),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.arrow_downward),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.arrow_left),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () {},
),
],
),
),
)
],
),
)
editing steps for your code
I will try to explain the changes.
You have multiple items in your Column. Move everything except Container which you used as bottom bar (the last child of column) to another Column widget.
Put this last container child inside Align widget like my code
Put the newly created Column in Positioned.fill widget.
Change column of scaffold to Stack
Set this stack's fit property as StackFit.expand
The body of you Scaffold should look like this.
Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned.fill(
child: Column(
children: <Widget>[
.... // Your page body childs
]
),
),
Align(
alignment: Alignment.bottomCenter,
child: ... // Your bottom bar container
)
]
)
To know more about stack visit here

Center Align Two Widgets in a Stack

Coming from Android development, what is the equivalent of 'android:layout_gravity="center_vertical"' in Flutter?
I have two boxes wrapped in a Stack that I would like to center align vertically. However, the size of the largest item is not fixed so I am unable to use any fixed values. This presents some difficulty as I have no way of positioning one child in relation to the other child. In Android, all you have to do is set 'layout_gravity' to 'center_vertical' on the child items.
This is what I have so far. The icon's position is fixed which is not good.
class CardItem extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new SizedBox(
width: double.infinity,
child: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(72.0, 6.0, 12.0, 6.0),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: 150.0,
),
child: Material(
elevation: 8.0,
borderRadius: BorderRadius.circular(12.0),
color: Colors.white,
child: InkWell(
onTap: () => {},
child: Padding(
padding: EdgeInsets.fromLTRB(76.0, 24.0, 6.0, 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text('Computer',
style: Theme.of(context).textTheme.headline),
Text('电脑',
style: Theme.of(context).textTheme.subhead.apply(fontWeightDelta: -2)
),
],
),
),
),
),
)
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(12.0, 0.0, 0.0, 0.0),
child: SizedBox.fromSize(
size: Size.fromRadius(60.0),
child: Material(
elevation: 12.0,
shape: CircleBorder(),
child: Image.asset('image.png'),
),
),
),
),
],
)
);
}
}
Wrap it in an Align widget...
Align(
alignment: Alignment.center,
child: Positioned(
top: 10,
child: Text('hi'),
),
),