flutter image placeholder (FadeInImage) without setting fixed size? - flutter

How can I use something like FadeInImage to setup and hold the layout of a page before images have downloaded? As expected, just using Image.network causes the page to jump around once the images load and become visible. I don't have set image sizes (i allow them to resize based on screen/etc) and want to avoid setting a fixed height. The images load and show fine using FadeInImage however the screen still jumps a lot.
#override
Widget build(BuildContext context) {
return
Scaffold(
appBar: AppBar(
title: Text('Welcome!'),
),
drawer: sideDrawer(),
body: new SingleChildScrollView(
padding: const EdgeInsets.all(8.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(height: 28),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(width: 64),
Flexible( // tried Expanded too
child:
FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: 'https://www.xyzserver.com/images/dummyimage.png',
fit: BoxFit.scaleDown,
),
),
SizedBox(width: 64),
],
),
SizedBox(height: 28),
Text("stuff below the image"),
],
),
)
);
}
When using "Expanded" the image row/area is very tall vertically (the text "stuff below the image" is at the bottom of the page so the page jumps up when the image loads. When using "Flexible" the image row/area is somewhat smaller and the page jumps down when the image loads.
In the image I'm playing around with now, it's a horizontal image that is larger than the available screen space, so it will get scaled down. I guess I was thinking that since flutter can calculate the max width of what's available to the expanded/flexible, it should be able to calculate the height, but as I write this I'm thinking that's impossible since it doesn't know the height/width ratio so it can't predict the height.
How can I set this up so that images can be resized and show correctly and the page doesn't jump around? I can't imagine using fixed height/width settings is the way to go. Maybe my approach to images is all wrong and I should always use a set height/width although that can be rather difficult when people are allowed to upload their own images/etc.
Thanks!

Check this one
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Uint8List? imageData;
Future<Uint8List> dosometinhdd() async {
return (await rootBundle.load('assets/images/a.png')).buffer.asUint8List();
}
#override
void initState() {
dosometinhdd().then((value) {
setState(() {
imageData = value;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Welcome!'),
),
body: new SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height * 0.8,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
imageData != null
? Expanded(
child: FadeInImage.memoryNetwork(
placeholder: imageData!,
image:
'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/1200px-Image_created_with_a_mobile_phone.png',
fit: BoxFit.scaleDown,
),
)
: Container(),
Text("stuff below the image"),
],
),
),
));
}

Related

Flutter Card child content height is larger than its parent

I'm trying to use a GridView to handle displays for multiple Card, each Card contains of an Image. Unfortunately it turns out that the Image is taking a larger height than its parent (see attached picture for the details).
I'm pretty new to Flutter layout so any ideas why this is happening and how I can resolve this? I want the layout to be something like this:
Display 2 cards on each line.
The Card width or height should not be fixed.
The Image height should be scaled according to its width.
class SquadSelectionScreen extends StatelessWidget {
final List<Team> teams;
const SquadSelectionScreen({super.key, required this.teams});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Squads'),
),
body: GridView.count(
crossAxisSpacing: 10,
crossAxisCount: 2,
padding: const EdgeInsets.all(16),
children: teams
.map(
(team) => SquadView(team: team),
)
.toList(),
),
);
}
}
class SquadView extends StatelessWidget {
final Team team;
const SquadView({super.key, required this.team});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
context.push('/squads/${team.code}');
},
child: Card(
elevation: 1,
child: Column(
children: [
Image(
image: NetworkImage(team.imageUrl),
),
const SizedBox(
height: 8,
),
Center(
child: Text(team.name),
),
],
),
),
);
}
}
Using GridView.count has a very visible drawback, namely the size of the aspect ratio of the grid will always be one (1:1 or Square) and can't be changed.
So if you look at the code above, you can't set an image with the same aspect ratio because the text will sink.
The first suggestion for me if you still want to use GridView.count is
Wrapping your Image with AspectRatio that has value higher than one (example set Ratio to 4/3, 5/3, 16/9, or landscape looks). Note: 4/3 = is higher than 1, 16/9 = is higher than 1, etc..
Then wrap the Text Widget with Expanded()
Example code:
class SquadView extends StatelessWidget {
final Team team;
const SquadView({super.key, required this.team});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Card(
elevation: 1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
AspectRatio(
aspectRatio: 4/3, // you can set the value to 16/9 or anything that result is higher than one
child: Image(
image: NetworkImage(team.imageUrl),
fit: BoxFit.cover, // set How the image looks to Fit
),
),
const SizedBox(
height: 8,
),
Expanded(
child: Center(
child: Text(team.name, overflow: TextOverflow.ellipsis),
),
),
],
),
),
),
);
}
}
I suggest you try GridView.builder or another GridView. You can look at the documentation here
or this third package this will be good for to try flutter_staggered_grid_view. The flutter_staggered_grid_view is more flexible to create GridView with various size.

How do I align my image to the bottom of my page in flutter?

I'm trying to set the last image on the bottom of the page. I tried the sized box between this one and the previous image but it changes depending on the device and sometimes it overflows some pixels.
Here is the code:
import 'package:flutter/material.dart';
// ignore: use_key_in_widget_constructors
class LoginPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.amber,
child: Column(
children: <Widget>[
Image.asset("imagens/btop.png"),
SizedBox(
width: 200,
height: 200,
child: Image.asset("imagens/logo.png"),
),
// ignore: prefer_const_constructors
SizedBox(
height: 40,
),
Image.asset("imagens/bbot.png")
],
),
));
}
}
Just use below Widget before your Image widget.
Spacer()
I would use your already existing Column() widget, like this:
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [],
),
Or use Align() in a Stack() or just a Spacer()... there are so many ways to do this, which are all dependent on what you want to do next.
Check out this cheat sheet: https://medium.com/flutter-community/flutter-layout-cheat-sheet-5363348d037e about aligning your widgets and play around with them!
use this :
mainAxisAlignment: MainAxisAlignment.spaceBetween,
inside the Column or in this you having issue then use nested columns

Scroll Function In Flutter Web

I'm still new to Flutter Web. I have 3 lines in my flutter web, the first line is the welcome message, the second line is a product and the last is contact, to see those lines user needs to do a scroll on my web. But how can I wrap my code using the Scroll function in flutter web? this is my code.
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
body: Column(
children: [
Container(
// Code Line 1
height: size.height,
width: size.width,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/container.jpg"),
fit: BoxFit.fitWidth),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CusAppBar(),
Spacer(),
Body(),
Spacer(
flex: 1,
),
],
),
),
Container(
// Code Line 2 Here
),
Container(
// Code Line 3 Here
)
],
),
);
}
}
My background is react, usually we just use tag ScrollView outside the container so the user can scroll the page. But how I can implement it on flutter web?
Thank you.
Try to add your fist Column inside SingleChildScrollView like below hope it help you:
body: SingleChildScrollView(
child:Column(
children:[
//Declare Your Widgets Here
],
),
),

RenderListWheelViewport object was given an infinite size during layout

I am using ListWheelScrollView Widget to give a wheeling effect to my list item but getting the error as mentioned. I just want to show Stacked Items with some image and texts in individual list item and give a 3D Wheeling effect to them.
Below is my code ->
class ExploreWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() => _ExploreState();
}
class _ExploreState extends State<ExploreWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: null,
body: Column(
children: <Widget>[
_header(),
_exploreList()
],
)
);
}
Widget _header(){
return SizedBox(
height: 200,
width: 800,
);
}
Widget _exploreList(){
return ListWheelScrollView.useDelegate(
itemExtent: 75,
childDelegate: ListWheelChildBuilderDelegate(
builder:(context,index){
return Container(
height: 500,
width: 800,
child: Stack(
children: <Widget>[
Image(image: AssetImage(
_products[index].image
)),
Text(_products[index].name,style: Style.sectionTitleWhite,),
Text('70% off',style: Style.cardListTitleWhite,),
],
),
);
}
),
);
}
}
The error was occuring due to the way _exploreList() widget is implemented. This widget is wrapped inside Column which doesn't scroll in itself. Moreover, you are returning a ScrollView that has an infinite size. Hence it was throwing the said error. To resolve this issue, wrap _exploreList() widget inside Flexible which takes only minimum available space to render and scroll. Working sample code below:
body: Column(
children: <Widget>[
_header(),
Flexible(
child: _exploreList()
)
],
)
Now you should be able to use WheelScrollView properly.

How can I make a fadein "decoration image" effect in Flutter

I want to build a widget that displays an image as a background behind some content. I know I can do this with a DecorationImage the problem is that I want the image to fade in as it might not be available right away.
So I want it to look like this after the image has faded in.
class DecorationExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fitWidth,
image: NetworkImage(
'https://images.pexels.com/photos/414612/pexels-photo-414612.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500'),
),
),
child: Column(
// Center the content dead center.
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
//Expand the column to take up the availble width
Container(width: double.infinity),
Text('Can be'),
Text('any'),
Text('size'),
Text('Depending on the number of rows')
],
),
);
}
}
My first instinct is to use a stack. The problem is that I need the stack to constrain itself to the height of the column which may vary depending on the content.
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';
class StackedImageTest extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
width: double.infinity,
child: _fadeInImage(),
),
_content(),
],
);
}
_content() => Column(
// Center the content dead center.
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
//Expand the column to take up the availble width
Container(width: double.infinity),
Text('Can be'),
Text('any'),
Text('height'),
Text('Depending on the number of rows')
],
);
_fadeInImage() => FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
fit: BoxFit.fitWidth,
image: 'https://images.pexels.com/photos/414612/pexels-photo-414612.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
);
}
To run the example include this dependency in your pubspec.yaml file:
transparent_image: ^1.0.0
So basically how can I achieve the same effect as with a decoration image(DecorationExample) but make it so that the image fades nicely into view(like in the StackedImageTest widget)?
Pretty simple as it turns out😅
Wrapping the first layer in the stack with a Positioned.fill() seems to do the trick
class FadeInDecorationContainer extends StatelessWidget {
final Widget child;
final String imgUrl;
const FadeInDecorationContainer({Key key, this.child, this.imgUrl}) : super(key: key);
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Positioned.fill(child: _fadeInImage()),
child,
],
);
}
_fadeInImage() => FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
fit: BoxFit.fitWidth,
image: imgUrl,
);
}
To run the example include this dependency in your pubspec.yaml file:
transparent_image: ^1.0.0