Await the loading of background Image in Container - flutter

I'm sorry if this question sounds a bit weird.
I have an issue with how long it takes to load a backgroundImage in a controller. I am using a Container's backgroundImage property as a background for my Scaffold. But during the loading of that particular page, it shows a black background until the image is loaded.
Is there a way I can wait for the image to be loaded before I navigate to the said page?
Below is my Code sample of the page in question:
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(imgSubscriptionBGPNG),
fit: BoxFit.fitHeight,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column()
),
);

Whew! It wasn't that difficult to solve after all, thanks to #Mr Random for his noble suggestion.
I did precache the image on the previous screen and passed it as an argument to the next page. That worked for me.
Here are the code snippets:
In the State class of the first screen:
final bgImage = AssetImage(imgSubscriptionBGPNG);
#override
void didChangeDependencies() {
precacheImage(bgImage, context);
super.didChangeDependencies();
}
And in the build function:
BtnButton(
onPressed: () {
Navigator.push(context,CupertinoPageRoute(
builder: (context)
=> SubscriptionScreen(bgImage: bgImage)));}),

Related

inkwell onTap is not working inside container

i'm trying to make a gallery app. i want a picture to open individually when tapped. but when I tap on a picture inkwell animation occurs but the new page doesn't open. i have defined second page in routes
Here is the code of landing page
class _ImageViewState extends State<ImageView> {
#override
Widget build(BuildContext context) {
return Container(
child: PhotoView(
maxScale: 600.0,
minScale: 200.0,
imageProvider: AssetImage("assets/mountain1.jpg",),
)
);
}
}
and this is the code where I'm calling the above class
child: InkWell(
onTap: () => {const ImageView()},
child: Image.asset('assets/mountain1.jpg', fit: BoxFit.fill,)),
Inside
OnTap method
you can only add functionality things, you can't load widget like that. if you try to load.
Or please provide more information here.
this is how you can open new page
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ImageView()),
);

ScaffoldMessenger.of(context).showSnackBar() doesn't work when called directly inside a widget build function

While looking for examples for using flutter SnackBar with ScaffoldMessenger, I only found usages with onPressed function:
Widget build(BuildContext context) {
return Container(
child: ElevatedButton(
child: ...,
onPressed: () => _showToast(context),
));
}
void _showToast(BuildContext context) {
final scaffold = ScaffoldMessenger.of(context);
scaffold.showSnackBar(
SnackBar(content: const Text('Added to favorite')),
);
}
}
but non of the examples explain why one have to use it with onPressed only,
so I tried it my self and used in directly inside the build function:
Widget build(BuildContext context) {
_showToast(context); <---
return Container(
child: ElevatedButton(
...,
));
}
but than I got this error:
and I am not sure why this it happening.
I ended up giving Scaffold a key and using the GlobalKey<ScaffoldState> approach, but I really want to understand why using ScaffoldMessenger.of(context).showSnackBar() without a callback\onPressed didn't work
while ScaffoldMessenger.of(context) we need to give some time to be rendered properly(for full Scaffold). we can know the time from addPostFrameCallback. Also if you try to show the middle of widgets, the 1st portion will render but rest widgets will face this issue.
here is the soulution on build method.
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
_showToast(context);
});
to understand the concept properly we can do something like this.
Scaffold(
body: Container(
height: 100,
color: Colors.cyanAccent,
child: Column(
children: [
Text("This text will render "),
Builder(builder: (context) {
_showToast(context);
///but you will be able to see Message
return Text("it will cause error");
}),
Text("This text will not render "),
],
),
),
);
Try to add or declare your snackbar inside Future.deleayd
Future.delayed(Duration.zero, () async {
yourSnackBarFunction();
});
In Flutter build function is called by the framework itself whenever a widget needs to be rebuilt. It can occur many times!
On the other hand, you usually want to display a toast / snackbar when you want to inform your user about something. So you can display a snackbar from onPressed and many other places, but the build function itself is only for building a widget, and not responding directly to user actions.

Every time I open my preview screen or return back to it then the images in it takes 1-2 seconds to load image again

I am having a game preview screen where I have a stateless widget for scaffold and all and then a secondary stateless widget to show preview for each game. But when I open this preview page then all 3 of my preview images take sometime to load the image and when I tap the preview I can play the game and after returning from the game it again rebuild/ loads the preview images.
class Games extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Games",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 25.0),),
),
body: SingleChildScrollView(
child: Column(
children: [
GamePreviewScreen(index: 0,),
GamePreviewScreen(index: 1,),
GamePreviewScreen(index: 2,),
],
),
),
);
}
}
Stateless widget for preview:-
class GamePreviewScreen extends StatelessWidget {
final int index;
String imagePath='';
GamePreviewScreen({this.index,});
String getPath()
{
if(index==0)
return 'images/EgyptGame/preview.png';
else if(index==1)
return 'images/EgyptGame/preview.png';
else
return 'images/EgyptGame/preview.png';
}
openGame(BuildContext context)
{
if(index==0)
Navigator.push(context, MaterialPageRoute(builder: (context)=>HomePageForGame2()));
else if(index==1)
Navigator.push(context, MaterialPageRoute(builder: (context)=>HomePageForGame2()));
else
Navigator.push(context, MaterialPageRoute(builder: (context)=>HomePageForGame2()));
}
#override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: (){openGame(context);},
child: Container(
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(color: Colors.cyan[200],width: 5),
),
child: Image.asset(getPath(),fit: BoxFit.fill,),
),
);
}
}
Have a look on your image size, dimensions and save it in jpg format it will load pretty fast.
Either convert your widgets to StatefulWidget or add a GlobalKey to Scaffold in Games page and GestureDetector of GamePreviewScreen
You can use a caching structure.
In addition, when using debug mode, a slower and more tiring experience is offered. This problem may disappear if you run your application in release mode.
Try flutter run --release in the terminal maybe you are running your app in the debug mode. It's way slower if you run the app in this mode because it has some features

Is there any solution to make my Flare Button work properly? Flutter

Basically, I have a button that I made in Flare and it should make an animation then I tap it! It works well but the animation starts everytime I tap anywhere within my app and not only the button.
Is there any way I can make animation only when I click in the Button Area? I`m using GestureDetector to handle tapping.
https://i.stack.imgur.com/ZBjmz.jpg
My code:
import 'package:flutter/material.dart';
import 'package:flare_flutter/flare_actor.dart';
import 'package:vibrate/vibrate.dart';
void main() => runApp(MaterialApp(
home: InvalidButton(),
));
class InvalidButton extends StatefulWidget {
#override
_InvalidButtonState createState() => _InvalidButtonState();
}
class _InvalidButtonState extends State<InvalidButton> {
var _type = FeedbackType.heavy;
final FlareControls controls = FlareControls();
void _playAnimation(){
controls.play('invalid');
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink[50],
body: Container(
child: GestureDetector(
onTap: () {
setState(() {
_playAnimation();
Vibrate.feedback(_type);
});
},
child: FlareActor(
'assets/invalid_button.flr',
animation: 'invalid',
alignment: Alignment.center,
fit: BoxFit.contain,
controller: controls,
),
),
),
);
}
}
I`m a newbie so will be glad to any help!
Do you have space around the button in the Rive editor ? If so, go in design mode, click Artboard and then "fit contents". That should remove the extra space. Then, wrap your FlareActor with a SizedBox and set its size, like so :
SizedBox(
width: 100,
height: 100,
child: FlareActor(),
)
That should do it.

How to stop GIF loop in flutter?

How to stop gif loop after 1 time? It is animating forever.
Image(
color: Colors.red,
image: new AssetImage(Icn.splash),
width: 150.0,
),
Solution
- Go to https://ezgif.com/loop-count
- Upload gif
- Set loop count 1 (0 - infinity)
- Change loop count and download gif
I hope this flutter package will help;
A flutter plugin to control gif animation: https://pub.dev/packages/gif_ani
Two steps:
Edit the gif loop count from 0(infinite) to 1 using any online gif editing tool like https://onlinegiftools.com/change-gif-loop-count and/or https://ezgif.com/loop-count and download the edited gif. This would ensure that the gif is played only once.
Manually evict the image cache to ensure the gif is played again when the user navigates away and/or uses the back button and revisits the page assuming the goal is to play the gif every time the user visits the page but just once.
Sample code:
import 'package:flutter/material.dart';
class OneTimeGifLoader extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _OneTimeGifLoaderState();
}
}
class _OneTimeGifLoaderState extends State<OneTimeGifLoader> {
late AssetImage myAssetImage;
#override
void initState() {
super.initState();
myAssetImage = const AssetImage("assets/path/to/my/image.gif");
}
#override
void dispose() {
super.dispose();
myAssetImage.evict(); //Evict image cache
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("One time gif loader"),
),
body: Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
image: myAssetImage,
fit: BoxFit.contain,
),
color: Colors.white,
),
),
),
);
}
}
this code:
Image.asset("assets/tasky_logo.gif",
gaplessPlayback: false, fit: BoxFit.fill)