when i try to pull profile image from firestore daatabse, It show following error on profile page
'package:flutter/src/painting
_network_image_io.dart':
Failed assertion:line22
pos14:'url!=null':is
not true.
See also:
https://flutter.dev/docs/testing/errors
although it gives this error if i press ctrl+s it loads the profile page. This is my code.
String profilePicUrl;
#override
void initState() {
super.initState();
FirebaseAuth.instance.currentUser().then((user){
profilePicUrl=user.photoUrl;
}).catchError((e){
print(e);
});
}
and then i put profilpicUrl inside of networkImage, as follows
Container(
width: 150.0,
height: 150.0,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(profilePicUrl),
fit: BoxFit.cover,
),
borderRadius: BorderRadius.all(Radius.circular(75.0)),
boxShadow: [
BoxShadow(
blurRadius:7.0,
color:Colors.black
)
]
),
),
Every time i run the App i have to press ctrl+s to prevent the error and load the profile page
The image is not loading in time, first the initState is getting called and the build method is getting called before the image is received. Therefore, you can use FutureBuilder:
Container(
width: 150.0,
height: 150.0,
child: FutureBuilder(
builder: (context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Image.network(profilePicUrl, fit: BoxFit.cover);
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
future: FirebaseAuth.instance.currentUser(),
),
),
Related
I am new to flutter so please go easy on me I am practicing grid view I stuck up on what functionality should be used to take the specific image from grid items to the new page so i write the description about that image.
here is my code,
GridView.count(
crossAxisCount: 2,
children: images
.map((e) => Container(
child: Container(
margin: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(10)),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[900],
borderRadius: BorderRadius.circular(10)),
margin: EdgeInsets.all(8),
padding: EdgeInsets.all(8),
child: GestureDetector(
onTap: () {
},
child: Image(
image: AssetImage(e),
fit: BoxFit.fill,
),
),
),
),
))
.toList(),
crossAxisSpacing: 8,
mainAxisSpacing: 8,
padding: EdgeInsets.all(8),
),
From the snippet shared I get that you want to use the image on the new page after clicking on the item in grid view.
so in the next page widget's constructor declare something like this
//for stateful
class YourWidgetName extends StatefulWidget{
final String imagePath;
YourWidgetName({this.imagePath});
#override
_YourWidgetName createState() => _YourWidgetName();
}
class _LoginState extends State<Login> {
#override
Widget build(BuildContext context) {
//you can access imagepath as **widget.imagePath** passed
return Scafold();
}
}
//for stateless
class YourWidgetName extends StatefulWidget{
final String imagePath;
YourWidgetName({this.imagePath});
#override
Widget build(BuildContext context) {
//you can access imagepath as **imagePath** passed
return Scafold();
}
}
and in onTap function go for:
onTap: () =>
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
YourWidgetName(
imagePath: e)
)
)
In my flutter app, after the splash screen animation is finished, it pushes to the HomeRoute.
The HomeRoute has a backgropundImage which is intended to cover the whole screen:
HomeRoute.dart:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/mainBgndsmall.png"),
fit: BoxFit.cover)),
child: SafeArea(child: _buildBody())),
);
}
When the route is pushed, there is a white flicker before the backgroundImage is showed.
Is that a normal behavior or am I doing something wrong when trying to put an image as a background?
Image size is about 500KB or 600KB aprox. PNG image.
The image has not loaded yet that is why the container loads before the image comes up
you can fix it by using a future builder which will display a circular progress indictor until the image is loaded and ready to be rendered
You can use precacheImage in your didChangeDependencies method to increase the chances of your image being loaded prior to the widget being displayed, preventing the white flicker.
#override
void didChangeDependencies() {
super.didChangeDependencies();
precacheImage(const AssetImage("assets/images/mainBgndsmall.png"), context);
}
You may need to convert your widget to a StatefulWidget first in order to pass a BuildContext.
It happens because the image is being loaded.
Alternatively, you can use FutureBuilder Widget to handle images as they load
here example
...
///future type variable to keep value from future method
late Future<String> futureData;
///future method to fetch some data
Future<String> getData(){
///give some duration before return value
await Future.delayed(Duration(seconds: 1));
//some code if you have some code
// ....
///return string
return "oke";
}
#override
didChangeDependencies(){
super.didChangeDependencies();
futureData = getData();
}
#override
Widget build(BuildContext context){
Future.delayed(Duration(seconds: 1));
return Scaffold(
body: FutureBuilder<String>(
future: futureData,
builder:(context, snapshot) {
///if loading is done
if(snapshot.connectionState == ConnectionState.done){
// if future success
if(snapshot.hasData){
///return widget what you want to show
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/mainBgndsmall.png"),
fit: BoxFit.cover)),
child: SafeArea(
child: _buildBody()
)
);
}else{
// if future failed return some widget
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: Text("Image can't load"),
)
);
}
}
///return progress loading
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: CircularProgressIndicator(),
)
);
},
),
);
}
As of now it is considered as flutter framework bug. You can check that here.
Also it is in Github open issue.
You can do one thing, You can use cached_network_image. While loading your image show your own container or whatever you want.
I am trying to design a splash screen. There is a gif that shows in a splash screen. There is no problem of showing the gif.
The problem is that the gif restarts from first frame when the page rebuilds. In my use case, rebuild is expected since a provider listens a firebase user.
My question is that, how can i ensure the gif starts in next build at specific frame from where it left off in previous build.
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
import 'package:provider_architecture/provider_architecture.dart';
import 'package:myproject/core/viewmodels/startup_view_model.dart';
class StartUpView extends StatelessWidget {
#override
Widget build(BuildContext context) {
FirebaseUser user = Provider.of<FirebaseUser>(context);
ScreenUtil.init(context, width: 411, height: 683, allowFontScaling: true);
return ViewModelProvider<StartUpViewModel>.withConsumer(
viewModel: StartUpViewModel(),
builder: (context, model, child) {
model.handleStartUpLogic(user);
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Image.asset('assets/images/lock.gif', height: 100.h)
],
),
),
);
},
);
}
}
That's interesting. My problem is the complete opposite of yours.
I want my gif to start from the beginning each time I load the gif, but it always starts at the frame that it left off last time.
return SafeArea(
child: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.black,
title: Text(
getImageName(),
),
centerTitle: true,
),
body: Center(
child: Column(
children: <Widget>[
Expanded(
child: Image (
height: height * 0.75,
width: width * 0.75,
image: AssetImage(getGuideImagePath()),
)
),
However, for your problem, this implementation may help you.
https://www.youtube.com/watch?v=xZ9vdVkI4Vc&feature=youtu.be
https://github.com/aliyigitbireroglu/flutter-image-sequence-animator/tree/master/image_sequence_animator
I am trying to have a background to my application that either the user has chosen previously, or to use a default image if no file is found.
The code is very simple:
decoration: BoxDecoration(
color: Colors.blueAccent,
image: DecorationImage(
image: File(customImageFile).existsSync() ? FileImage(File(customImageFile)) : backgroundImage,
fit: BoxFit.fill,
),
),
The application crashes on the conditional line, saying that (path): Must not be null. I have tried many ways to get around this, but what I am specifically saying there is "if the file path is null, don't use it. Use this image I made earlier for you". But then it gets upset anyway.
Is there another way I can achieve the intended result here?
Edit:
As requested by #Vikas, more complete sample of code involved:
ImageProvider backgroundImage;
String themeLoader = 'blueTheme';
String customImageFile;
// Declaration
void initState() {
_loadThemeSettings();
super.initState();
}
// Initialisation
_loadThemeSettings() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
themeLoader = prefs.getString('themeColour' ?? 'blueTheme');
customImageFile = prefs.getString('customImageFile' ?? 'empty')
if (customImageFile != null) {
if(File(customImageFile).existsSync()) {
prefs.setString('customImageFile', customImageFile);
} else {
print('Path not valid');
}
} else {
print('customImageFile is NULL');
}
if (themeLoader != null) {
switch (themeLoader) {
case 'blueTheme':
{
colorBloc.changeColor('blueTheme');
setState(() {
backgroundImage = ExactAssetImage('lib/images/bg_blue_new.jpg');
buttonTheme = AppState.blueTheme;
}
}
break;
} else {
print('Theme loader was NULL');
}
}
}
}
// Loading previously selected themes at run time. There are several colours here in the case statement, but they are all identical and you get the idea.
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => _exitApp(context),
child: Scaffold(
body: SafeArea(
child: BlocProvider<ColorBloc>(
bloc: colorBloc,
child: Container(
child: Stack(
children: [
Container(
decoration: BoxDecoration(
color: Colors.blueAccent,
image: DecorationImage(
image: (customImageFile != null && File(customImageFile).existsSync()) ? FileImage(File(customImageFile)) : backgroundImage,
fit: BoxFit.fill,
),
),
// that's where it sits, everything else works fine. The rest of the build method is not relevant to this issue, and is working, but here it is anyway:
child: SafeArea(
child: Stack(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
themesVisible == true
? SizedBox()
: buttonRow(),
SizedBox(
height: 20,
),
],
),
Padding(
padding: EdgeInsets.all(15),
child: topMenuRow(),
),
],
),
),
),
BlocProvider<CustomToggleBloc>(
bloc: customToggleBloc,
child: Center(
child: Container(
child: themesVisible == true ? singlePlayerThemes(singlePlayerCallbacks: callBacks) : scoreText(),
),
),
),//bloc
],
),
),
),
),
),
);
}
I am new to Flutter. I try to load network images using image.network widget. it's working fine but sometimes it takes time to load. I added tap listener to image.network during tap I need to check image is fully loaded or not based on the result I need to redirect the page. how to check image is loaded or not?
Code:
new Image.network('http://via.placeholder.com/350x150')
Any help will be appreciated, thank you in advance
You may use the loadingBuilder which is inbuilt feature from flutter for Image.Network
I did it as below:
Image.network(imageURL,fit: BoxFit.cover,
loadingBuilder:(BuildContext context, Widget child,ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null ?
loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
),
);
},
),
for this kind of issues it's good to use the cached_network_image
so you can provide a placeholder when the image is loading and an error widget in case a resource fails to load
String url = "http://via.placeholder.com/350x150";
CachedNetworkImage(
imageUrl: url,
placeholder: (context,url) => CircularProgressIndicator(),
errorWidget: (context,url,error) => new Icon(Icons.error),
),
for ones who do not need to cache the image can use meet_network_image package,
The package basic usage :
MeetNetworkImage(
imageUrl:
"https://random.dog/3f62f2c1-e0cb-4077-8cd9-1ca76bfe98d5.jpg",
loadingBuilder: (context) => Center(
child: CircularProgressIndicator(),
),
errorBuilder: (context, e) => Center(
child: Text('Error appear!'),
),
)
In addition, you can do that by yourself with using a FutureBuilder,
We need to get data with http call that way, we need to import http before import you also need to add pubspec.yaml and run the command flutter packages get
import 'package:http/http.dart' as http;
FutureBuilder(
// Paste your image URL inside the htt.get method as a parameter
future: http.get(
"https://random.dog/3f62f2c1-e0cb-4077-8cd9-1ca76bfe98d5.jpg"),
builder: (BuildContext context, AsyncSnapshot<http.Response> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return CircularProgressIndicator();
case ConnectionState.done:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
// when we get the data from the http call, we give the bodyBytes to Image.memory for showing the image
return Image.memory(snapshot.data.bodyBytes);
}
return null; // unreachable
},
);
This way it will start loading, then it will show the loading of the image loading and then the image. Best option if you don't want to use external libs.
Image.network(
imgUrl,
height: 300,
fit: BoxFit.contain,
frameBuilder: (_, image, loadingBuilder, __) {
if (loadingBuilder == null) {
return const SizedBox(
height: 300,
child: Center(child: CircularProgressIndicator()),
);
}
return image;
},
loadingBuilder: (BuildContext context, Widget image, ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return image;
return SizedBox(
height: 300,
child: Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
),
),
);
},
errorBuilder: (_, __, ___) => Image.asset(
AppImages.withoutPicture,
height: 300,
fit: BoxFit.fitHeight,
),
)
thank you for your comment thats help to resolve the situation that how to know if the image is loaded or not hope that help
I use a StatefulWidget
need a editing depend on your AffichScreen
situation :
-i have an url that i enter
-if url is correct affich the image if not affich an icon
-if empty affich a Text()
-precacheImage check if the url is correct if not give an error and change _loadingimage(bool) to false to affich the icon eror
-i use a NetworkImage to check with precacheImage and before affich use a Image.network
bool _loadingimage;
ImageProvider _image;
Image _imagescreen;
#override
void initState() {
_loadingimage = true;
_imageUrlfocusNode.addListener(_updateImageUrl);
super.initState();
}
#override
void dispose() {
_imageUrlfocusNode.removeListener(_updateImageUrl);
_quantityfocusNode.dispose();
_imageUrlConroller.dispose();
_imageUrlfocusNode.dispose();
super.dispose();
}
void _updateImageUrl() {
setState(() {
_image = NetworkImage(_imageUrlConroller.text);
});
if (!_imageUrlfocusNode.hasFocus) {
if (_imageUrlConroller.text.isNotEmpty) {
setState(() {
loadimage();
});
}
}
}
void loadimage() {
_loadingimage = true;
precacheImage(_image, context, onError: (e, stackTrace) {
// log.fine('Image ${widget.url} failed to load with error $e.');
print('error $e');
setState(() {
_loadingimage = false;
print(_loadingimage);
});
});
if (_loadingimage == true) {
_imagescreen = Image.network(
_imageUrlConroller.text,
fit: BoxFit.fill,
);
}
}
Container(
width: 100,
height: 100,
margin: EdgeInsets.only(top: 13, right: 11),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
),
child:_imageUrlConroller.text.isEmpty
? Text('enter an url')
: !_loadingimage
? Container(
child: Icon(Icons.add_a_photo),
)
: Container(
child: _imagescreen,
),
),