Flutter Scrollable layout - flutter

I am making a flutter layout with several items in it. It is a column with several widgets among them a gridview containing several items. I would like to make the whole layout scrollable however even after wrapping the main widget in a singlechildscrollview it is not scrollable
This is the code
class _CustomerDataState extends State<CustomerData> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Customer Data'),
centerTitle: true,
),
body: _containers());
}
Widget _containers() {
return Container(
alignment: Alignment.center,
child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Card(elevation: 5.0, child: Text('Information')),
Card(
elevation: 5.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[Text('No: '), Text('....')],
),
),
Card(
elevation: 5.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Text('Stages: '), Text('....')],
),
),
GridView.count(
shrinkWrap: true,
crossAxisCount: 3,
childAspectRatio: 1.0,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: <Widget>[
Card(
elevation: 5.0,
child: Column(
children: <Widget>[
Icon(Icons.monetization_on),
Text('First Stage')
],
)),
],
),
Row(
children: <Widget>[
Card(
elevation: 8.0,
child: Text('Words here'),
),
Card(
elevation: 8.0,
child: Text('Words here'),
),
],
)
],
),
);
}
}
And is there a way I can center the icon and text in the card widget?

the ScrollController is the one responsible for scrolling behavior, yet your gridview is not using one, consider creating a ScrollController and assign it to the gridview
ScrollController _scrollControllerGridView` = ScrollController()
GridView.count(
shrinkWrap: true,
controller: _scrollControllerGridView,
crossAxisSpacing: 4.0,
...
and to center the card's text and icon
just add
mainAxisAlignment: MainAxisAlignment.center,
to the Column, like this:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.monetization_on),
Text('First Stage')
],
)

Related

I made customize horizontal stepper in flutter and it's not scrolled till the end

Does anyone know how to make my stepper scrollable in vertically, it actually could scroll but it doesn't scrolling till the end of the page length
The stepper:
MainScaffold(
title: appBarTitle,
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
width: width,
child: Column(
children: <Widget>[
const SizedBox(
height: 8,
),
Row(
children: _lineViews(),
),
const SizedBox(
height: 8,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: _titleViews(),
),
const SizedBox(
height: 20,
),
Expanded(
child: ListView(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: stepPanels())
],
),
),
const SizedBox(
height: 20,
),
],
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: _buttonControls(currentStep, context),
);
I put the stepper's content inside expanded listview, and I already add shrinkwrap & physics into it, when I call this customizable widget on another class, it can't be scrolled till the end of the page
Steps(
content: Obx(
() {
if (controller.loading.value) {
return const LoadingProgressIndicator();
} else {
return SizedBox(
height: MediaQuery.of(context).size.height,
child: ListView(
physics: const ClampingScrollPhysics(),
children: [
controller.loading.value
? const LoadingProgressIndicator()
: _doctorProfile(),
const SizedBox(height: 10.0),
const ClinicTypeToggle(),
const SizedBox(height: 100.0),
],
),
);
}
},
),
),
that is the content that I want to scroll

Column/SingleChildScrollView not scrolling

I'm learning flutter to make an app. Here I'm trying to make a page to show the full post. The problem is that the page isn't scrolling as a single unit.
class SinglePostPage extends StatefulWidget {
final Post? post;
const SinglePostPage({Key? key, this.post}) : super(key: key);
#override
State<SinglePostPage> createState() => _SinglePostPageState();
}
class _SinglePostPageState extends State<SinglePostPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: const EdgeInsets.only(top: 22.5),
padding: const EdgeInsets.fromLTRB(0, 5, 0, 6),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BackButton(),
Row(
children: [
InkWell(
onTap: () {
showDialog(...);
},
child: CircleAvatar(...),
Container(
padding: const EdgeInsets.only(left: 5.4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
showDialog(...);
},
child: Text(
widget.post!.author[0].profileName,
),
),
const SizedBox(height: 4),
Text(
showTimeAgo(widget.post!.postTime).toString(),
),
],
),
),
],
),
PopupMenuButton(
icon: const Icon(Icons.more_vert),
itemBuilder: (context) => [...],
),
Container(
margin: const EdgeInsets.fromLTRB(12, 9, 12, 3),
// when the text is longer than the screen height it showed RenderFlex overflowed error so I put constraints. how to show it full and make this scroll
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.54,
minHeight: 50),
child: SingleChildScrollView(
child: Text(
widget.post!.postText,
textAlign: TextAlign.start,
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (widget.post!.postMedia.isNotEmpty)
CarouselSlider.builder(...),
const SizedBox(height: 4.5),
if (widget.post!.postMedia.length > 1)
buildDotIndicator(widget.post!.postMedia),
],
),
],
),
),
Container(
// post reactions row
),
CommentBodyWidget(
postId: widget.post!.postId,
),
],
),
);
}
}
I looked up for other answers and tried wrapping it with SingleChildScrollView, but it didn't work , and ListView with shrinkWrap: true also gave 'Incorrect use of ParentDataWidget' error.
CommentBodyWidget has a listview builder. It's scrolling on its own but the widget above isn't scrolling along with it.
How can I show this whole page and scroll together without having to limit the long post in a constrained container? Please help.
You can wrap body Column with SingleChildScrollView and use shrinkWrap: true, and use physics: NeverScrollableScrollPhysics(),. This will solve the issue.
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
//...
ListView.builder(
itemCount: itemlength,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Text("item $index");
},
),
/// instead of listView
...List.generate(itemlength, (index) => Text("itemWidget"))
],
),
),
);
But I will encourage you to check CustomScrollView.
In order for the SingleChildScrollView to work, its parent's height should be defined.
You can achieve this by wrapping the SingleChildScrollView in a Container/SizedBox with defined height, or by wrapping it with the Expanded widget.
Pass SingleChildScrollView as body of your scaffold. Also shrinkwrap: true for the ListView is recommended so that it only takes up as much space as required, which will avoid unbounded height errors.
So instead of
...
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
...
Do this
...
Widget build(BuildContext context)
return Scaffold(
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(...
I recommend you to use CustomScrollView.
Try this:
CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column("""HERE PUT YOUR CODE""")
)]
),

Flutter, fill the entire screen

I am designing an application and I have realized that in different mobiles the screen occupies different dimensions, I would like the size to be proportional to the size of the mobile, so that it always occupies the entire screen without the need to scroll.
I'd like that the Screen A could be look like the Screen B no matter of the size of the device.
But I have no idea how to do that, this is my code. I also noticed that because of cards I can't scrolling even having a ListView this is not a problem once they get the same size, because then there wont be reason to scroll through
#override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
centerTitle: true,
title: Text('Gestion de flota'),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.exit_to_app,
),
onPressed: () async {
_signOut().whenComplete(() =>
navigatorKey.currentState.pushReplacementNamed('/login'));
},
)
],
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Form(
key: _formKey,
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
SizedBox(
height: 20,
),
GridView.count(
childAspectRatio: (10 / 4),
crossAxisCount: 2,
shrinkWrap: true,
children: [
_getHourStart(),
_getHourEnd(),
_getDateStart(),
_getDateEnd(),
],
),
],
),
SizedBox(height: 10),
Column(
children: <Widget>[
GridView.count(
childAspectRatio: (3 / 0.7),
crossAxisCount: 1,
shrinkWrap: true,
children: [
_getHourStart(),
],
),
],
),
SizedBox(height: 10),
GridView.count(
crossAxisCount: 2,
childAspectRatio: (3 / 2),
shrinkWrap: true,
children: [
Card(
child: _uploadPic(Foto.primera, picList[0]),
),
Card(
child: _uploadPic(Foto.segunda, picList[1]),
),
Card(
child: _uploadPic(Foto.tercera, picList[2]),
),
Card(
child: _uploadPic(Foto.cuarta, picList[3]),
),
],
),
SizedBox(height: 20),
InkWell(
onTap: () async { // more code... }
child: SubmitButton(context, 'Enviar datos'),
),
Container(
padding: EdgeInsets.symmetric(vertical: 10),
alignment: Alignment.centerRight,
),
SizedBox(height: height * .14),
],
),
),
),
);
}
}
you can use MediaQuery
you retrieve the size of mobile screen by:
final height = MediaQuery.of(context).size.height
final width = MediaQuery.of(context).size.width
One solution to this problem is to add Expanded to all the children in the Column widget.
Another and preferable one is :
make your Container height the height of your screen.
body: Container(
height:MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
next add the mainAxisAlignment property to both Column widgets.
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
]

Header image to show

I'm trying to get a header image to show on a page of an app but it's not showing up and the _header seems to be greyed out in my code. I'm missing something I guess that I'm unsure of. Edit: I need the header to show above the rows of content in the build.
Widget _header() {
return new Container(
child: new Row(
children:<Widget>[
new Column(
children: <Widget>[
Image.asset(
'assets/classes-Image.png',
),
],
),
],
),
);
}
Extra code below:
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: const Text('Learn How to Paint'),
backgroundColor: Color(0xFF202945),
),
body: new Container(
child: ListView(
shrinkWrap: true,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
children: <Widget>[
Row(
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(
left: 20.0,
),
),
Image.asset(
'assets/Profile-Photo.png',
),
new Padding(
padding: const EdgeInsets.only(
right: 20.0,
),
),
Text(
'Katherine G.',
),
],
),
],
),
```
You can achieve this by placing your header widget right before the Row widget.
The header is not showing because you didn't add it in the ListView.
I hope this solves your issue.
You need to be calling _header() from somewhere in your build function and give the result as a child to another widget. It being grayed out probably means you're not calling it.

Fill ListView tiles vertically by a container - Flutter

I have been trying to put a line indicator on the left most margin of the card in my flutter app. I've tried a lot of things but didn't work.
There's an exact question here, which is actually the same issue I've been trying to solve.
The problem with the accepted solution is that it restricts the height of the hardcoded value, which I don't want. Rather the color should automatically fill the height of the card.
The Problem
I've tried all the three solutions and none of them fit my use case.
Output from first solution
Here I've to hardcode the value to something larger so that all the text being displayed lies well inside it. That's something I feel is not a solution.
Card(
key: ObjectKey(noteList[index]),
elevation: 2.0,
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
width: 4,
color: Color(noteList[index].intcolor),
),
Flexible(
flex: 100,
child: ListTile(
~~~~~~~~~~~~~~~~~ SNIP ~~~~~~~~~~~~~~~~~~~~~~~~
chip goes outside
Output from Second solution
This doesn't show anything at all.
Card(
key: ObjectKey(noteList[index]),
elevation: 2.0,
child: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
constraints: BoxConstraints.expand(),
color: Color(noteList[index].intcolor),
),
),
Flexible(
flex: 100,
child: ListTile(
~~~~~~~~~~~~~~~~~ SNIP ~~~~~~~~~~~~~~~~~~~~~~~~
No output at all
Output from last solution
There's no color from the container.
There's no color from the container
Thanks a lot.
Update 1 ( Monday, 6 April 2020 8:16 pm GMT )
Added code and repo for easy replication.
Repo
main.dart
import 'package:flutter/material.dart';
void main() {
List<String> notes = [
"fluttermaster.com",
"Update Android Studio to 3.3",
"Something long Something long Something long Something long Something long Something long",
];
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Simple Note ListView"),
),
body: Container(
color: Colors.white10,
padding: EdgeInsets.all(16.0),
child: HomePage(notes)),
),
));
}
class HomePage extends StatelessWidget {
final List<String> notes;
HomePage(this.notes);
Widget build(BuildContext context) {
return ListView.builder(
itemCount: notes.length,
itemBuilder: (context, pos) {
return Padding(
padding: EdgeInsets.only(bottom: 16.0),
child: Card(
elevation: 2.0,
child: Row(
// key: _cardKey,
children: <Widget>[
Flexible(
flex: 1,
child: Container(
// -------------------- This here ----------------------------------------------
// FixMe : This shouldn't be hardcoded, rather it should fill the height of it's parent element, in this case card
// https://medium.com/#diegoveloper/flutter-widget-size-and-position-b0a9ffed9407
height: 71,
color: Colors.green,
// -------------------- This here ----------------------------------------------
),
),
Flexible(
flex: 100,
child: ListTile(
// For center alignment from vertical and horizontal : https://stackoverflow.com/a/51546279
// Since using CircleAvatar does this but it decreases size of icon too : https://github.com/flutter/flutter/issues/16061
leading: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(Icons.receipt),
],
),
title: Text(
notes[pos],
),
subtitle: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(notes[pos].substring(0, 10)),
// What is the best way to optionally include a widget in a list of children
// https://github.com/flutter/flutter/issues/3783#issuecomment-506019822
if ((pos % 2) == 0)
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade800,
child: Icon(Icons.timer),
),
label: Text('2FA'),
),
],
),
trailing: Padding(
padding: EdgeInsets.all(10),
child: Wrap(
spacing: 10,
direction: Axis.vertical,
alignment: WrapAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(
Icons.check,
color: Colors.grey,
),
onPressed: () {},
)
]),
),
onTap: () {},
),
),
],
),
));
},
);
}
}
Perhaps one way of doing it is to use Stack
ListView.builder(
itemCount: notes.length,
itemBuilder: (context, pos) {
return Padding(
padding: EdgeInsets.all(8),
child: Stack(
children: <Widget>[
Card(
margin: EdgeInsets.zero,
child: ListTile(
leading: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(Icons.receipt),
],
),
title: Text(
notes[pos],
),
subtitle: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(notes[pos].substring(0, 10)),
if ((pos % 2) == 0)
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade800,
child: Icon(Icons.timer),
),
label: Text('2FA'),
),
],
),
trailing: Padding(
padding: EdgeInsets.all(10),
child: Wrap(
spacing: 10,
direction: Axis.vertical,
alignment: WrapAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(
Icons.check,
color: Colors.grey,
),
onPressed: () {},
)
]),
),
onTap: () {},
),
),
Positioned(
top: 0,
bottom: 0,
child: Container(
width: 5,
color: Colors.green,
),
)
],
),
);
},
)
Output