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,
),
),
Related
Hi i have a problem with a stream of images in flutter, when i do a Navigator.push() and then Navigator.pop() the images of the stream gets reload.
My Class is a Stateful Widget with AutomaticKeepAliveClientMixin
When images gets donwloaded
After a Navigator.push() and then Navigator.pop()
I use riverpod for the stream and Firebase Storage.
Expanded(
child: watch(userEventsFamilyStream(user.uid)).maybeWhen(
data: (events) {
if (events.isEmpty) {
return EmptyGrid(
onTap: () => context
.read(menuNotifier)
.currentIndex = 1);
}
return Stack(
children: [
GridView.count(
crossAxisCount: 3,
children: [
...events.map((event) {
return EventItem(
uid: event.uid,
imgUrl: event.imgUrl,
onTap: () async {
final result =
await buildOptions(context);
_handleResult(
context, result, actions, event);
},
);
}).toList()
],
),
if (state.isSubmitting)
Container(
decoration: const BoxDecoration(
color: Colors.black54),
width: MediaQuery.of(context).size.width,
child: const Center(
child: CircularProgressIndicator())),
],
);
},
orElse: () =>
const Center(child: CircularProgressIndicator())),
),
I also use cached_network_image package
Hero(
tag: '${uid}profile',
child: FadeInImage(
placeholder: const AssetImage('assets/img/transparent.png'),
image: CachedNetworkImageProvider(imgUrl),
fit: BoxFit.cover,
),
),
if you want to keep the state of the page alive, you may use AutomaticKeepAliveClientMixin
class Foo extends StatefulWidget {
#override
FooState createState() {
return new FooState();
}
}
class FooState extends State<Foo> with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
return Container();
}
#override
bool get wantKeepAlive => true;
}
I solved: the problem was the size of the images, even cached if the image is too big it takes some time to get load.
Hello Any One Flutter Expert here ?? plz help meee...what i want to make is Like Facebook photo viewer when user slides images and check is this like or not same i want in my code...
i made my code in that i come from listing page and when i tap on listing i can see full screen image.. and i Can slide(Scroll) images...
BUTTT when i comes first time on this screen which i code it show me some bugs on screen for 3,4 seconds...after that i can see the image plz help mee and show my error
Future<PhotoDetail> pagedetail() async {
sharedPreferences = await SharedPreferences.getInstance();
Map data = {
"AccessToken": sharedPreferences.getString("AccessToken"),
"CustomerId": sharedPreferences.getInt("CustomerId"),
"ImageId": indexx == null ? widget.images[widget.currentindex].photoId : indexx
};
print(data);
final http.Response response = await http.post(
Constants.CUSTOMER_WEBSERVICE_URL + "/photo/detail",
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data),
);
var jsonResponse = json.decode(response.body);
if (response.statusCode == 200) {
print("Response status : ${response.statusCode}");
print("Response status : ${response.body}");
isLike = jsonResponse["IsLike"]; //here i saving value when api is run
print("iSLiked Value:" +isLike.toString()); // value is printing here
return PhotoDetail.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load data');
}
}
Future<PhotoDetail> _photoDetail;
#override
void initState() {
_photoDetail = pagedetail();
setState(() {
pagedetail(); //here is my api run when page is load
});
super.initState();
}
void pageChange(int index){ //this method is when i scroll page
setState(() {
pagedetail(); // api is call again and again
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
body: Stack(
children: <Widget>[
Container(
child:
Center(
child: PhotoViewGallery.builder(
itemCount: widget.images.length,
builder: (BuildContext context , int index) {
return PhotoViewGalleryPageOptions(
imageProvider:
NetworkImage(widget.images[index].photoPreviewImagePath),
maxScale: PhotoViewComputedScale.covered * 1.8,
minScale: PhotoViewComputedScale.contained * 1.0,
);
},
pageController: _pageController,
enableRotation: false,
scrollDirection: Axis.horizontal,
onPageChanged: pageChange,
loadingBuilder: (BuildContext context , ImageChunkEvent event){
return Center(child: CircularProgressIndicator(),);
},
)
)
),
Positioned(
bottom: 10,
left: 30,
right: 30,
child: (_photoDetail == null) ? Text("error")
: FutureBuilder<PhotoDetail>(
future: _photoDetail,
// ignore: missing_return
builder: (context , snapshot){
int like = snapshot.data.isLike;
int Slection = snapshot.data.selectedCount;
print("like ?????:" +like.toString());
print("Selection ????? :" + Slection.toString());
if (snapshot.hasData){
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
InkWell(
child: InkWell(
Likes();
Fluttertoast.showToast(
msg: "Liked",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Color(0xfff58634),
textColor: Colors.white,
fontSize: 16.0
);
},
child: Icon(Icons.thumb_up,size: 20,color: like == 1 ? Color(0xfff58634) : Colors.white),
),
),
InkWell(
child: Icon(Icons.comment,size: 20,color: Colors.white),
),
InkWell(
onTap: (){
_onShare();
},
child: Icon(Icons.share,size: 20,color: Colors.white,),
),
InkWell(
onTap: (){},
child: Icon(Icons.photo_album,size: 20,color: Slection == 0 ? Colors.white : Color(0xfff58634)),
),
InkWell(
onTap: (){
setState(() {
viewwholike();
});
},
child: Icon(Icons.card_giftcard,size: 20,color:
Colors.white,),
),
]
);
}
else {
Text("error");
}
},
),
),
],
),
);
}
ERROR::════════ Exception caught by widgets library
═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building
FutureBuilder<PhotoDetail>(dirty, state:
_FutureBuilderState<PhotoDetail>#ef81b):
The getter 'isLike' was called on null.
Receiver: null
Tried calling: isLike
The relevant error-causing widget was:
FutureBuilder<PhotoDetail>
file:///C:/Users/Hello%20Devloper/AndroidStudioProjects/
September/PhotoGranth-
App/lib/CampaignSinglePhotos.dart:400:15
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 _CampaignSinglePhotosState.build.<anonymous closure>
(package:photogranth2020/CampaignSinglePhotos.dart:404:42)
#2 _FutureBuilderState.build
(package:flutter/src/widgets/async.dart:732:55)
#3 StatefulElement.build
(package:flutter/src/widgets/framework.dart:4619:28)
#4 ComponentElement.performRebuild
(package:flutter/src/widgets/framework.dart:4502:15)
Flutter tells you that data is not ready when you test snapshot.data.isLike.
You should test always at the beginning if snapshot.hasData, only after that you can make all you want.
Otherwise, if snapshot.hasData is false, simply return CircularProgressIndicator() .
I am using multi_image_picker 4.6.1 in my application but I faced little problem. How to organize images on specific place on the page and put cancel button on each selected image so user can cancel or remove selected image one by one like in picture here. Thanks in advance
here is the code i am using
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:multi_image_picker/multi_image_picker.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Asset> images = List<Asset>();
String _error = 'No Error Dectected';
#override
void initState() {
super.initState();
}
Widget buildGridView() {
return GridView.count(
crossAxisCount: 3,
children: List.generate(images.length, (index) {
Asset asset = images[index];
return AssetThumb(
asset: asset,
width: 300,
height: 300,
);
}),
);
}
Future<void> loadAssets() async {
List<Asset> resultList = List<Asset>();
String error = 'No Error Dectected';
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Example App",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
} on Exception catch (e) {
error = e.toString();
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
images = resultList;
_error = error;
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: <Widget>[
Center(child: Text('Error: $_error')),
RaisedButton(
child: Text("Pick images"),
onPressed: loadAssets,
),
Expanded(
child: buildGridView(),
)
],
),
),
);
}
}
Another way to fix using Stack
Stack(
children: <Widget>[
AssetThumb(
asset: asset,
width: 300,
height: 300,
),
Positioned(
right: -2,
top: -9,
child: IconButton(
icon: Icon(
Icons.cancel,
color: Colors.black.withOpacity(0.5),
size: 18,
),
onPressed: () => setState(() {
images.removeAt(index);
})))
],
);
You can try using Stack https://www.youtube.com/watch?v=liEGSeD3Zt8&vl=en
return Stack(
children: <Widget>[
AssetThumb(
asset: asset,
width: 300,
height: 300,
),
Positioned(
top: 0,
right: 0,
child: GestureDetector(
onTap: (){
print('delete image from List');
setState((){
print('set new state of images');
})
},
child: Icon(
Icons.delete,
),
),
),
],
);
How to save network data in cash and then implement it have any resource or example, I use flutter_cashe_manager but I can't implement it in my code
there I call the API API return data and save it in cash, whene i call this future method its returns the list from the cache JSON file.. this is the code where return the data list from the cache.
TopicHab _topicHab;
Future<List<Topic>> fetchTopicList(String api) async {
try {
// var file = await DefaultCacheManager().getSingleFile(url+api);
var file = await DefaultCacheManager().getSingleFile(url+api);
print('files ${file.readAsStringSync()}');
print('files ${file.path}');
// var tempDir = await getTemporaryDirectory();
// String tempPath = tempDir.path;
// print('path ${tempPath}');
_topicHab = TopicHab.fromJson(jsonDecode(file.readAsStringSync()));
print('Topic Length ${_topicHab.cats.length}');
return _topicHab.cats;
} catch (e) {
return List<Topic>();
}
}
their whare the snapshot.haseData is false but its use streamside first time its work but next time it does not work. I can't find what the proper problems
drawer: Drawer(
child: Container(
color: drawerBackgroundColors,
child: StreamBuilder(
stream: newsBloc.allTopic,
builder:
(BuildContext context, AsyncSnapshot<List<Topic>> snapshot) {
print('newsBloc.allTopic ${newsBloc.allTopic}' );
print('snapshot data ${snapshot.hasData}');
if (snapshot.hasData) {
print('snapshot topic ${snapshot.data.length}');
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: BoxDecoration(
color: childMenuBackgroundColor,
border: Border(
bottom: BorderSide(
color: Colors.white,
)
),
),
padding: EdgeInsets.all(2),
height: 50,
child: ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TopicsNewsScreen(
parentTopic: true,
topicId: snapshot.data[index].topicId,
topicName: snapshot
.data[index].topicName
.toUpperCase())));
},
title: Text(
snapshot.data[index].topicName,
style: childMenuStyle,
))
);
},
);
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
),
),
The package used is Hive
Another way of caching is by using hive a No-SQL database it is faster to retrieve documents and is easy to use. And it retrieves data faster
For more details check:https://github.com/shashiben/Anime-details to know how to cache using hive from rest api
I want to add a simple image over an image from the gallery/camera. The behavior should be like it.
Open the application, choose a photo or make one with the floating buttons, then show the image and over put our logo on the bottom left. All it is working now.
Then I would like to save it both images in a single one, but I don't know how this process is called or how to achieve it.
import 'package:share/share.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Picker Demo',
home: MyHomePage(title: 'Image Picker Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File _imageFile;
dynamic _pickImageError;
String _retrieveDataError;
void _onImageButtonPressed(ImageSource source) async {
try {
_imageFile = await ImagePicker.pickImage(source: source);
} catch (e) {
_pickImageError = e;
}
setState(() {});
}
Widget _previewImage() {
final Text retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_imageFile != null) {
print('La imagen ha sido puesta en la pantalla?');
return Image.file(_imageFile);
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await ImagePicker.retrieveLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
setState(() {
_imageFile = response.file;
});
} else {
_retrieveDataError = response.exception.code;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Stack(children: <Widget>[
Container(
color: Colors.amber,
child: Platform.isAndroid
? FutureBuilder<void>(
future: retrieveLostData(),
builder:
(BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return _previewImage();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
: (_previewImage())), //
Positioned(
bottom: 16,
left: 16,
width: 100,
height: 100,
child: Image.network(
'http://father-home.ru/wp-content/uploads/2018/05/cropped-logo8.png'))
]))),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: () {
_onImageButtonPressed(ImageSource.gallery);
},
heroTag: 'image0',
tooltip: 'Pick Image from gallery',
child: const Icon(Icons.photo_library),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
_onImageButtonPressed(ImageSource.camera);
},
heroTag: 'image1',
tooltip: 'Take a Photo',
child: const Icon(Icons.camera_alt),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
_onShare();
},
tooltip: 'Share',
child: const Icon(Icons.share),
),
),
],
),
);
}
void _onShare(){
//TODO: save the two images into one and share
}
Text _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError);
_retrieveDataError = null;
return result;
}
return null;
}
}
the widget with this code looks like it:
You can use RepaintBoundary widget to export a specific widget to image.
I believe that you will need to work with Bitmap.
Load 2 bitmaps, one is the background, one is your logo.
Apply transformation as you like.
Save output bitmap to file.
Take a look at: https://pub.dev/packages/bitmap