Flutter ListView in Container Lazy Rendering and performance - performance

I have a long list of items that are being updated frequently. The list is rendered using ListView.builder wrapped in a container to apply borders etc.
My problems is, that when the ListView is located in a container, all items are rendered including elements outside the screen. As the list is redrawn very often, it affects performance severely.
I've created two examples to illustrate the problem. To keep it simple, the examples are stateless, in real life the list is stateful.
Example 1 - ListView is root widget. Notice in console that only visible cards are build.
https://dartpad.dev/ac436b786ae48383c107a64bb3db8070
Example 2 - ListView is wrapped in container. Notice all cards are build.
https://dartpad.dev/109f1f97085c1726c0826f6ea8b731ec
How do I make a scrollable container with a list of items, that only renders visible items?
The source of Example 2 here:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SingleChildScrollView(
child: Container(
color: Colors.green,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 700,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.44),
spreadRadius: 0,
blurRadius: 15,
offset:
Offset(0, 1), // changes position of shadow
),
]),
margin: EdgeInsets.all(24.0),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: 20,
itemBuilder: (context, index) {
var text = 'Card $index';
print('Building card $text');
return Card(
child: Container(
height: 130,
child: Center(
child: Text(text),
)));
})
]))),
],
))));
}
}

You should give a height limit to the listView wrapped in container.
Just like this:
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SingleChildScrollView(
child: Container(
color: Colors.green,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 700,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.44),
spreadRadius: 0,
blurRadius: 15,
offset:
Offset(0, 1),
),
]),
margin: EdgeInsets.all(24.0),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox( // add a SizedBox and set a specific height
height: 1000,
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: 20,
itemBuilder: (context, index) {
var text = 'Card $index';
print('testtest Building card $text');
return Card(
child: Container(
height: 130,
child: Center(
child: Text(text),
)));
}),
)
]))),
],
))));
}
}

Related

Flutter :- Align a icon to the right bottom of a container

I tried a column with an aligned icon but it didn't display correctly
If anyone has any idea to help. It would be greatly appreciated. Thank you
This is my code that i tried
List<Widget> temp = [];
listAirline.map((airline) {
listAirlineName.map((item) {
if (airline.name == item) {
temp.add(
Column(
children: <Widget>[
Container(
height: 20,
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.all(Radius.elliptical(100.0, 60.0)),
),
child: Image.asset(
"images/Airlines/" + airline.id + ".jpg",
fit: BoxFit.fitWidth,
),
),
Align(
alignment: Alignment.bottomRight,
child: Icon(
Icons.remove_circle,
color: Colors.white,
),
)
],
),
);
}
}).toList();
}).toList();
return temp;
}```
You need to use the Stack widget for it, i have done similar task with the use of the Stack widget,please check thee below solution
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomeScreen();
}
}
class _HomeScreen extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: Container(
height: 100.0,
child: Align(
alignment: Alignment.topCenter,
child: Stack(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20.0),
height: MediaQuery.of(context).size.width*0.15,
width: MediaQuery.of(context).size.width*0.4,
child: Container(
margin: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.all(Radius.elliptical(20.0, 20.0)),
),
),
)
,
Positioned(
right: 5.0,
bottom: 0.0,
child:
Icon(
Icons.remove_circle,
color: Colors.red,
),
)
],
),
)));
}
}
And output of the above code is as follow

Images load by themselves, but not as a randomized list. - Flutter

and thank you in advance for any assistance.
So, I have images load properly when I use them within a container in other areas of the code, but I also want some of those images to display randomly within the AppBar.
Given that they do load in other locations within the code, I don't suspect a Pubyaml error.
I'm still fairly new to flutter, and lists in general. So I wouldn't be surprised if I messed up something with the list itself, or the way it's called.
It gives me this error:
Syncing files to device iPhone...
Reloaded 8 of 502 libraries in 411ms.
════════ Exception caught by image resource service ════════════════════════════════════════════════
The following assertion was thrown resolving an image codec:
Unable to load asset: Image(image: AssetImage(bundle: null, name: "images/Mem2.JPG"), frameBuilder: null, loadingBuilder: null, alignment: center, this.excludeFromSemantics: false, filterQuality: low)
When the exception was thrown, this was the stack:
#0 PlatformAssetBundle.load (package:flutter/src/services/asset_bundle.dart:221:7)
<asynchronous suspension>
#1 AssetBundleImageProvider._loadAsync (package:flutter/src/painting/image_provider.dart:484:44)
#2 AssetBundleImageProvider.load (package:flutter/src/painting/image_provider.dart:469:14)
#3 ImageProvider.resolve.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:flutter/src/painting/image_provider.dart:327:17)
...
Image provider: AssetImage(bundle: null, name: "Image(image: AssetImage(bundle: null, name: "images/Mem2.JPG"), frameBuilder: null, loadingBuilder: null, alignment: center, this.excludeFromSemantics: false, filterQuality: low)")
Image key: AssetBundleImageKey(bundle: PlatformAssetBundle#c99db(), name: "Image(image: AssetImage(bundle: null, name: "images/Mem2.JPG"), frameBuilder: null, loadingBuilder: null, alignment: center, this.excludeFromSemantics: false, filterQuality: low)", scale: 1.0)
════════════════════════════════════════════════════════════════════════════════════════════════════
Here's the code:
class ContactProfilePage extends StatefulWidget {
#override
_ContactProfilePageState createState() => _ContactProfilePageState();
}
class _ContactProfilePageState extends State<ContactProfilePage> {
List<Attr> attr = [
Attr(name: ''),
];
dynamic randAppBarImg = [
"images/Mem2.JPG",
"images/Mem3.JPG",
"images/Mem4.JPG",
"images/Mem6.jpg",
"images/memory - 1.jpeg",
"images/memory - 2.jpeg",
"images/memory - 3.jpeg",
"images/memory - 4.jpeg",
"images/memory - 5.jpeg",
"images/memory - 6.jpeg",
];
Random rnd;
Image img() {
int min = 0;
int max = randAppBarImg.length - 1;
rnd = Random();
int r = min + rnd.nextInt(max - min);
String image_name = randAppBarImg[r].toString();
return Image.asset(image_name);
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.lightBlueAccent,
child: Icon(Icons.add),
onPressed: () {
//Modal sheet brings up the whole bottom pane when the plus button is pressed.
showModalBottomSheet(
context: context,
builder: (context) => AddAttrScreen(
(newAttrTitle) {
setState(() {
//adds the Attr to the list anytime the user presses "Add"
attr.add(Attr(name: newAttrTitle));
});
Navigator.pop(context);
//Hides the floating add Attr screen after pressing "Add"
},
),
);
//TODO Change it so the categories don't have to be selected every time. Instead, have the add button WITHIN each category.
// This floating button should instead create a new category.
},
),
drawer: DrawerMain(),
body: NestedScrollView(
//This allows for the top bar to collapse, while retaining the image.
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
expandedHeight: 200.0,
floating: true,
snap: true,
pinned: true,
flexibleSpace: Stack(
children: <Widget>[
Positioned.fill(
child: Image.asset(
img().toString(),
fit: BoxFit.cover,
))
],
),
),
];
},
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(15.0),
child: CircleAvatar(
maxRadius: 50.0,
backgroundImage: AssetImage("images/fox.jpeg")),
),
Container(
//TODO ADD ON PRESSED FUNCTION TO SOCIAL ICONS
margin: EdgeInsets.all(15.0),
child: Icon(
FontAwesomeIcons.facebook,
size: 40.0,
color: Color(0xFF306060),
),
),
Container(
margin: EdgeInsets.all(15.0),
child: Icon(
FontAwesomeIcons.instagram,
size: 40.0,
color: Color(0xFF306060),
),
),
],
),
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
'Armando Pacheco Ortiz',
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
color: Color(0xFF306060)),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
'Freelance App Developer from Puerto Rico',
style: TextStyle(
fontSize: 20.0,
fontStyle: FontStyle.italic,
color: Color(0xFF306060)),
),
SizedBox(
child: Divider(),
),
],
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
children: <Widget>[
Text('Memories',
style: TextStyle(
fontSize: 20.0,
fontStyle: FontStyle.italic,
color: Color(0xFF306060),
fontWeight: FontWeight.bold))
],
),
),
//Horizontal scrolling images.
//TODO These need to update based on uploads, perhaps use something like google's face detection to auto add?
Padding(
padding: const EdgeInsets.all(15.0),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
height: 310,
width: 200,
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: (Image.asset(
'images/Mem6.jpg',
fit: BoxFit.cover,
)),
),
),
SizedBox(
width: 20,
),
Container(
height: 310,
width: 200,
//ClipRRect allows for it to have the border radius. Container is painted behind the image.
//For that reason, adding a border radius to the container doesn't work.
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: (Image.asset(
'images/Mem2.JPG',
fit: BoxFit.cover,
)),
),
),
SizedBox(
width: 20,
),
Container(
height: 310,
width: 200,
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: (Image.asset(
'images/memory - 4.jpeg',
fit: BoxFit.cover,
)),
),
),
I pasted the code as far down as the first image, to show how I have it set up in the other locations.
I'm not sure if the issue is with random images within the appBar, or maybe some code I'm missing.
Hopefully, someone can shed some light on this!
Many thanks.
UPDATE:
So that helped a ton and definitely got things running! But I did notice two new problems cropping up.
I had to rename all the images from: "memory - 6" to "Mem6", and that finally allowed them to show up.
Otherwise, sometimes it would revert back to the default teal color, and not display anything, besides an error about not being able to load the asset again. I imagine it's just a naming error I was unknowingly causing?
Scrolling down will cause the Appbar to "refresh" again, and randomize the pictures with the slightest scrolling until you stop. If I scroll back up, it'll do it again. It doesn't create an error, but it does crash the app eventually from so much refreshing I guess.
How would I get around this? Is there an override, or should I simply create the widget with some Finals, or stateless/stateful widgets? I'm still learning the lingo and all that, so my apologies for the ignorance.
You can copy paste run full code below
Your img() has bug, you return an Image.asset and wrap in Image.asset again cause duplicate
Image.asset(
img().toString(),
fit: BoxFit.cover,
))
code snippet just return String of image_name will work
and do not include space in image name
String img() {
int min = 0;
int max = randAppBarImg.length - 1;
rnd = Random();
int r = min + rnd.nextInt(max - min);
String image_name = randAppBarImg[r].toString();
//return Image.asset(image_name);
return image_name;
}
working demo
full code
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ContactProfilePage(),
);
}
}
class Attr {
String name;
Attr({this.name});
}
class ContactProfilePage extends StatefulWidget {
#override
_ContactProfilePageState createState() => _ContactProfilePageState();
}
class _ContactProfilePageState extends State<ContactProfilePage> {
List<Attr> attr = [
Attr(name: ''),
];
dynamic randAppBarImg = [
"images/Mem2.JPG",
"images/Mem3.JPG",
/*"images/Mem4.JPG",
"images/Mem6.jpg",
"images/memory-1.jpeg",
"images/memory-2.jpeg",
"images/memory-3.jpeg",
"images/memory-4.jpeg",
"images/memory-5.jpeg",
"images/memory-6.jpeg",*/
];
Random rnd;
String img() {
int min = 0;
int max = randAppBarImg.length - 1;
rnd = Random();
int r = min + rnd.nextInt(max - min);
String image_name = randAppBarImg[r].toString();
//return Image.asset(image_name);
return image_name;
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.lightBlueAccent,
child: Icon(Icons.add),
onPressed: () {
//Modal sheet brings up the whole bottom pane when the plus button is pressed.
/* showModalBottomSheet(
context: context,
builder: (context) => AddAttrScreen(
(newAttrTitle) {
setState(() {
//adds the Attr to the list anytime the user presses "Add"
attr.add(Attr(name: newAttrTitle));
});
Navigator.pop(context);
//Hides the floating add Attr screen after pressing "Add"
},
),
);*/
//TODO Change it so the categories don't have to be selected every time. Instead, have the add button WITHIN each category.
// This floating button should instead create a new category.
},
),
//drawer: DrawerMain(),
body: NestedScrollView(
//This allows for the top bar to collapse, while retaining the image.
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
expandedHeight: 200.0,
floating: true,
snap: true,
pinned: true,
/*flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text("",
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
)),
background: Image.asset(
"images/Mem2.JPG",
fit: BoxFit.cover,
)),*/
flexibleSpace: Stack(
children: <Widget>[
Positioned.fill(
child: Image.asset(
img().toString(),
fit: BoxFit.cover,
))
],
),
),
];
},
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(15.0),
child: CircleAvatar(
maxRadius: 50.0,
backgroundImage: AssetImage("images/fox.jpeg")),
),
Container(
//TODO ADD ON PRESSED FUNCTION TO SOCIAL ICONS
margin: EdgeInsets.all(15.0),
child: Icon(
FontAwesomeIcons.facebook,
size: 40.0,
color: Color(0xFF306060),
),
),
Container(
margin: EdgeInsets.all(15.0),
child: Icon(
FontAwesomeIcons.instagram,
size: 40.0,
color: Color(0xFF306060),
),
),
],
),
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
'Armando Pacheco Ortiz',
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
color: Color(0xFF306060)),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
'Freelance App Developer from Puerto Rico',
style: TextStyle(
fontSize: 20.0,
fontStyle: FontStyle.italic,
color: Color(0xFF306060)),
),
SizedBox(
child: Divider(),
),
],
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
children: <Widget>[
Text('Memories',
style: TextStyle(
fontSize: 20.0,
fontStyle: FontStyle.italic,
color: Color(0xFF306060),
fontWeight: FontWeight.bold))
],
),
),
//Horizontal scrolling images.
//TODO These need to update based on uploads, perhaps use something like google's face detection to auto add?
Padding(
padding: const EdgeInsets.all(15.0),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
height: 310,
width: 200,
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: (Image.asset(
'images/Mem6.jpg',
fit: BoxFit.cover,
)),
),
),
SizedBox(
width: 20,
),
Container(
height: 310,
width: 200,
//ClipRRect allows for it to have the border radius. Container is painted behind the image.
//For that reason, adding a border radius to the container doesn't work.
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Image.asset(
'images/Mem2.JPG',
fit: BoxFit.cover,
),
),
),
SizedBox(
width: 20,
),
Container(
height: 310,
width: 200,
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: (Image.asset(
'images/memory-4.jpeg',
fit: BoxFit.cover,
)),
),
),
])))
]))));
}
}

How can I make TextField's suffix/suffixIcon height resize?

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: Scaffold(
body: Column(
children: [
Container(
color: Colors.orange,
child: TextField(
decoration: InputDecoration(
suffix: IconButton(
icon: Icon(Icons.check_circle),
onPressed: () {
print('222');
}),
),
),
),
],
),
),
),
);
}
}
How can I force the check_circle icon to automatically resize to match the height of the actual TextField, i.e., wrt its cursor height?
Use suffixIcon instead.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: Scaffold(
body: Column(
children: [
Container(
color: Colors.orange,
child: TextField(
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(Icons.check_circle),
onPressed: () {
print('222');
}),
),
),
),
],
),
),
),
);
}
}
Very good question...
The basics, is to reset all the paddings in the TextField, and not using a IconButton (as all Material components have predefined and internals paddings that you can't modify).
Seems like suffix gets baseline aligned with the text, preventing the material ink interaction, while suffixIcons get properly centered in the text area, BUT propagates the Ink to the TextField.
So, so far I couldn't find a way of doing it properly, maybe there's a widget/logic that I'm missing.
Check screenshot at the bottom that shows why the suffix will not be able to align with the text, as it sits within the baseline itself, and the caret generates a bigger height.....
in the first 2 textfields, the GREY boxes are suffix, and yellow, suffixIcon (which centers properly).
Solution 1: (in screenshotm is red background with 2 checkboxes)
If you can (design-wise), make a row, and put the TextField and the icon:
var inputBorderDecoration = OutlineInputBorder(
borderRadius: BorderRadius.zero,
borderSide: BorderSide(width: 1, color: Colors.black));
double textHeight = 40;
// define a width if you want, or let the constrains of the parent define it.
double inputWidth = double.infinity;
return Center(
child: Container(
width: inputWidth,
height: textHeight,
color: Colors.green.withOpacity(.2),
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Flexible(
child: TextField(
controller: TextEditingController(text: 'hello world'),
style: TextStyle(fontSize: textHeight),
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
enabledBorder: inputBorderDecoration,
focusedBorder: inputBorderDecoration,
filled: true,
fillColor: Colors.red.withOpacity(.5),
),
),
),
FittedBox(
child: InkWell(
onTap: () => print("touch button"),
child: Icon(Icons.check_circle),
),
),
],
)),
);
Solution 2: (in screenshot, last textfield, green box with white icon)
Wrap the icon decoration, is the better UI approach, but the TextField will .still receive touch events.
var inputBorderDecoration = OutlineInputBorder(
borderRadius: BorderRadius.zero,
borderSide: BorderSide(width: 1, color: Colors.black));
double fontSize = 24;
return GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
color: Colors.green.shade50,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 300,
height: fontSize,
color: Colors.orange,
child: TextField(
style: TextStyle(fontSize: fontSize, color: Colors.white),
decoration: InputDecoration(
fillColor: Colors.purple.withOpacity(.5),
filled: true,
border: inputBorderDecoration,
focusedBorder: inputBorderDecoration,
enabledBorder: inputBorderDecoration,
contentPadding: EdgeInsets.zero,
suffixIcon: GestureDetector(
onTap: () => print('on tap'),
child: Container(
color: Colors.green,
child: FittedBox(
alignment: Alignment.center,
fit: BoxFit.fitHeight,
child: IconTheme(
data: IconThemeData(),
child: Icon(
Icons.check_circle,
color: Colors.white,
),
),
),
),
),
),
),
),
],
),
),
),
);
Solution 3:
Build the decorations yourself using EditableText
Used Stack
Stack(
children: [
TextField(),
Positioned.fill(
right: 10,
child: Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () {
searchController.clear();
},
child: Icon(Icons.clear))))
],
),

Why are Icon-Buttons not centered?

I'm working on a Flutter application and I can't figure out why my icon-buttons are not centered in the middle of the page.
I wrapped my code in a Center()
This is my page :
https://imgur.com/a/YlCW3Xu
This is my code:
import "package:flutter/material.dart";
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class LogInScreen extends StatefulWidget {
#override
_LogInScreenState createState() => new _LogInScreenState();
}
class _LogInScreenState extends State<LogInScreen> {
String _email, _password;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Center(
child: ListView(
children: <Widget>[
Column(children: <Widget>[
new Container(
padding: (EdgeInsets.only(top: 50)),
child: Text(
"Sign In",
style: TextStyle(
fontSize: 40,
),
),
),
new Container(
padding: (EdgeInsets.only(top: 50, left: 35, right: 35)),
child: Column(children: <Widget>[
new Form(
child: new Column(children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 20),
child: new RaisedButton(
onPressed: () {},
color: Colors.blue,
textColor: Colors.white,
child: const Text('Login'),
),
),
])),
])),
new Container(
padding: EdgeInsets.only(top: 40),
child: Column(
children: <Widget>[
new Text("Or login with"),
],
),
),
]),
new Center(
child: new Row(
children: <Widget>[
new IconButton(
icon: Icon(FontAwesomeIcons.facebookF),
color: Colors.blue,
),
new IconButton(
icon: Icon(FontAwesomeIcons.google),
color: Colors.blue,
),
],
)),
],
)),
);
}
}
I removed the texts field so the code would fit.
I hope you can help me,
Thank you for your help !
Set the padding for IconButton to 0, like so:
IconButton(
padding: EdgeInsets.zero,
...
)
None of the listed solution will work. The Only solution for me is to put IconButton inside SizedBox.
SizedBox(
width: double.infinity,
child: IconButton(
icon: FaIcon(FontAwesomeIcons.moneyBillWave),
iconSize: 80,
onPressed: () {},
),
),
A few changes :
Add shrinkWrap true to your ListView
ListView(
shrinkWrap: true,
...
Add mainAxisAlignment MainAxisAlignment.center to your Row
new Center(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new IconButton(
...
Basically Center() widget only center the row itself not the widgets within the row.
To align children in your row use mainAxisAlignment: MainAxisAlignment.centerfor horizontal alignment and crossAxisAlignment: CrossAxisAlignment.center for Vertical alignment see more here
so for your code it would be:
` new Center(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center
children: <Widget>[
new IconButton(
icon: Icon(FontAwesomeIcons.facebookF),
color: Colors.blue,
),
new IconButton(
icon: Icon(FontAwesomeIcons.google),
color: Colors.blue,
),
],
)),`
You don't need Center the icon because the problem was the Icon it self. Maybe the icon design contained padding or margin. My problem is on back button:
Container(
color: Colors.lightGreen,
child: Icon(
Icons.arrow_back_ios,
color: Colors.black,
size: 15,
),
),
When i change to Icons.arrow_back_ios_new, it back to normal:
Container(
color: Colors.lightGreen,
child: Icon(
Icons.arrow_back_ios_new,
color: Colors.black,
size: 15,
),
),
You need to find an icon that contained no padding/margin.

How to set minimum height of SliverAppBar within NestedScrollView in Flutter

I'd like to use SliverAppBar within NestedScrollView in an ordinary Scaffold app. I also would like to have some minimum height of the app bar when user scrolls down.
I can't figure out how to use either PreferredSize widget nor any other solution found online e.g. this.
Here is my current simplified solution:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue, fontFamily: 'Oswald'),
home: SliverHome(),
);
}
}
class SliverHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: testHome(),
);
}
Widget testHome() {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar( // this is where I would like to set some minimum constraint
expandedHeight: 300,
floating: false,
pinned: true,
flexibleSpace: Container(
padding: EdgeInsets.all(10),
height: 340,
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: 40,
),
Container(
height: 60,
),
Expanded(child: Container()),
Text('TEST'),
],
),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('https://picsum.photos/400/400'),
fit: BoxFit.cover)),
),
)
];
},
body: Container(),
),
floatingActionButton: FloatingActionButton(
onPressed: () => {},
tooltip: '+',
child: Icon(Icons.accessibility_new),
),
);
}
}
I'd like to stop shrinking of the app bar somewhere near 60 dp
This is Actually an requested Feature - https://github.com/flutter/flutter/issues/21298
A work Around is to use Bottom
SliverAppBar(
// this is where I would like to set some minimum constraint
expandedHeight: 300,
floating: false,
pinned: true,
bottom: PreferredSize( // Add this code
preferredSize: Size.fromHeight(60.0), // Add this code
child: Text(''), // Add this code
), // Add this code
flexibleSpace: Container(
padding: EdgeInsets.all(10),
height: 340,
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: 40,
),
Container(
height: 60,
),
Expanded(child: Container()),
Text('TEST'),
],
),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('https://picsum.photos/400/400'),
fit: BoxFit.cover)),
),
)
Simply use collapsedHeight and specify your minimum height.
SliverAppBar(
// Display a placeholder widget to visualize the shrinking size.
flexibleSpace: Placeholder(),
expandedHeight: 300,
collapsedHeight: 60,
);
I don't know since exactly when, but as of now, you can also use the collapsedHeight property, documented as below:
https://api.flutter.dev/flutter/material/SliverAppBar/collapsedHeight.html
Currently I am on flutter 1.20.1 and I have this property available.
Your code also works fine after decreasing the size from container .
SliverAppBar( // this is where I would like to set some minimum constraint
expandedHeight: 300,
floating: false,
pinned: true,
flexibleSpace: Container(
padding: EdgeInsets.all(10),
height: 340,
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: 10, //decreas the size
),
Container(
height: 10, //decrease the size
),
Expanded(child: Container()),
Text('TEST'),
],
),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('https://picsum.photos/400/400'),
fit: BoxFit.cover)),
),
)
I know im late to this thread but to set height of the SliverAppBar, Implement Toolbarheight and you will able to change it.
SLiverAppbar(
toolbarHeight: WhateverHeightYouWant,
)

Resources