How to transfer ID if user onTap image to other page from carousel_pro.
I get Image to carousel_pro from database mysql. I try to make user can click image and move to other page with id of image.
full my code:
void main() => runApp(MaterialApp(home: Demo()));
class Demo extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<Demo> {
String SelectIdCategory;
bool lodaing=true;
List data;
Future GetAllCategory()async{
var response=await http.get("https://****************.php"
, headers: {"Accept": "application/json"}
);
var jsoBody = response.body;
var jsoData =json.decode(jsoBody);
setState(() {
data= jsoData;
lodaing=false;
});
print('show all data $jsoData');
}
#override
void initState() {
// TODO: implement initState
super.initState();
GetAllCategory();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:lodaing? CircularProgressIndicator() :
GestureDetector(
child: Center(
child: SizedBox(
height: 150.0,
width: 300.0,
child: InkWell(
onTap: () {
},
child: Carousel(
// onImageTap:(index) { print(index.toString()); } ,
boxFit: BoxFit.cover,
autoplay: true,
dotSize: 4.0,
dotSpacing: 15.0,
dotColor: Colors.lightGreenAccent,
indicatorBgPadding: 5.0,
dotBgColor: Colors.purple.withOpacity(0.5),
borderRadius: true,
// onImageChange: (prev, next) {_selectedIndex = next;}, initialIndex: selectedItem,
images:
data .map(
(list) {
return Image.network(list['image']);
},
).toList(),
),
),
),
),
)
);
}
}
class ImageScreen extends StatefulWidget {
final String id;
ImageScreen(this.id);
#override
_MyImageScreen createState() => _MyImageScreen(id);
}
class _MyImageScreen extends State<ImageScreen> {
final String id;
_MyImageScreen(this.id);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ImageScreen'),
),
body: Center());
}
}
Here is the print result:
I/flutter (24335): show all data [{id: 1, name: one, image: https://*****************/image},
{id: 3, name: one, image: https://*****************/image}]
As you can see from print data I have two image and each image has a id different. That what I want to send to other page.
Does anyone know how to do this?
You should define a "skeleton" of your app.
Do you prefer to use global variables to store values at runtime? Do you want to send parameters through pages without let them in app ram?
If you want to send data thor pages your class for the new page should accept parameters.. so you can pass the id.
or you can set a global variable with the currentImageId then in the new page you can access that variable
To accept parameters in the new page you have to declare final variables then in the signature of the class you request them.. something like this
class DetailPage extends StatefulWidget {
final int yourId;
DetailPage(this.yourId);
}
Related
I'm totally new to Flutter/Dart, I've done all the layouts for my application, and now it's time to make my application's API calls. I'm trying to manage the forms as cleanly as possible.
I created a class that manages TextFields data (values and errors), if my API returns an error I would like the screen to update without having to call setState(() {}), is this possible?
In addition, many of my application's screens use values that the user enters in real time, if that happened I would have to call the setState(() {}) methodmany times.
Any idea how to do this with the excess calls to the setState(() {}) method?
I created a test project for demo, these are my files:
File path: /main.dart
import 'package:flutter/material.dart';
import 'login_form_data.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final LoginFormData _loginFormData = LoginFormData();
void _submitLoginForm() {
// Validate and then make a call to the login api
// If the api returns any erros inject then in the LoginFormData class
_loginFormData.setError('email', 'Invalid e-mail');
setState(() {}); // Don't want to call setState
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Test App'),
),
body: Padding(
padding: const EdgeInsets.all(30),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
decoration: InputDecoration(
errorText: _loginFormData.firstError('email'),
labelText: 'E-mail',
),
onChanged: (value) => _loginFormData.setValue('email', value),
),
TextField(
decoration: InputDecoration(
errorText: _loginFormData.firstError('password'),
labelText: 'Password',
),
obscureText: true,
onChanged: (value) =>
_loginFormData.setValue('password', value),
),
ElevatedButton(
onPressed: _submitLoginForm,
child: const Text('Login'),
)
],
),
),
),
);
}
}
File path: /login_form_data.dart
import 'form/form_data.dart';
import 'form/form_field.dart';
class LoginFormData extends FormData {
#override
Map<String, FormField> fields = {
'email': FormField(),
'password': FormField(),
'simple_account': FormField(
value: true,
),
};
LoginFormData();
}
File path: /form/form_data.dart
class FormData {
final Map<String, dynamic> fields = {};
dynamic getValue(
String key, {
String? defaultValue,
}) {
return fields[key]?.value ?? defaultValue;
}
void setValue(
String key,
String value,
) {
fields[key].value = value;
}
void setError(
String key,
String error,
) {
fields[key]?.errors.add(error);
}
dynamic firstError(
String key,
) {
return fields[key]?.errors.length > 0 ? fields[key]?.errors[0] : null;
}
FormData();
}
File path: /form/form_field.dart
class FormField {
dynamic value;
List errors = [];
FormField({
this.value,
});
}
You are essentially looking for a State Management solution.
There are multiple solutions (you can read about them here: https://docs.flutter.dev/development/data-and-backend/state-mgmt/options)
State Management allows you to declare when you want your widgets to change state instead of having to imperatively call a setState method.
Flutter recommends Provider as a beginner solution, and you can find many tutorials online.
With that being said, let me show you how to achieve this result with a very basic solution: Change Notifier
Quoting flutter documentation :
” A class that can be extended or mixed in that provides a change
notification API using VoidCallback for notifications.”
We are going to make FormData a Change notifier, and them we are going to make your app listen to changes on the instance, and rebuild itself based on them.
Step 1:
Based on the code you posted, I can tell that you will interact with LoginFormData based on the methods setValue and setError from the parent class FormData. So we are going to make FormData inherit ChangeNotifer, and make a call to notifyListeners() on these two methods.
class FormData extends ChangeNotifier {
final Map<String, dynamic> fields = {};
dynamic getValue(
String key, {
String? defaultValue,
}) {
return fields[key]?.value ?? defaultValue;
}
void setValue(
String key,
String value,
) {
fields[key].value = value;
notifyListeners();
}
void setError(
String key,
String error,
) {
fields[key]?.errors.add(error);
notifyListeners();
}
dynamic firstError(
String key,
) {
return fields[key]?.errors.length > 0 ? fields[key]?.errors[0] : null;
}
FormData();
}
Now, every time you call either setValue or setError, the instance of FormData will notify the listeners.
Step2:
Now we have to setup a widget in your app to listen to these changes. Since your app is still small, it’s easy to find a place to put this listener. But as your app grows, you will see that it gets harder to do this, and that’s where packages like Provider come in handy.
We are going to wrap your Padding widget that is the first on the body of your scaffold, with a AnimatedBuilder. Despite of the misleading name, animated builder is not limited to animations. It is a widget that receives any listenable object as a parameter, and rebuilds itself every time it gets notified, passing down the updated version of the listenable.
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final LoginFormData _loginFormData = LoginFormData();
void _submitLoginForm() {
// Validate and then make a call to the login api
// If the api returns any erros inject then in the LoginFormData class
_loginFormData.setError('email', 'Invalid e-mail');
//setState(() {}); No longer necessary
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Test App'),
),
body: AnimatedBuilder(
animation: _loginFormData,
builder: (context, child) {
return Padding(
padding: const EdgeInsets.all(30),
child: Center(
child: Column(
//... The rest of your widgets
),
),
);
}
),
);
}
}
I am trying to get user information from an API. For this, I created a user object. I want to call the function and store it in a user. But the problem is, that I cannot use await and wait till all the data is there.
So instead of async and await, I tried to use .then and fill userInfo with the data. But now the email value is not showing. It is showing 'loading...'.
If I use Future I cannot do user.email.
Is it better to use FutureBuilder? Or try and use Async and Await (the call takes 2.5 seconds)
Here is the code
class Addressbook extends StatefulWidget {
const Addressbook({Key? key}) : super(key: key);
#override
State<Addressbook> createState() => _AddressbookState();
}
class _AddressbookState extends State<Addressbook> {
User? userInfo;
Future<User> getUserInformation() async {
User user = await UserService().getUserById(12345);
return user;
}
#override
void initState() {
// TODO: implement initState
getUserInformation().then((response) {
userInfo = response;
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Mijn adresboek'),
centerTitle: true,
elevation: 0.5,
titleTextStyle: const TextStyle(
fontSize: 21,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
body: Text(userInfo?.email ?? "loading..."),
);
}
}
What do I want to archive?
I want to display user data on the screen. In this case I want to show the email.
What is the problem?
User is not filled with data on init (probably because it is still loading to get the data).
My question
How can I solve this problem? Is async await a solution or should I use FutureBuilder? Can you give me a working sample?
Thanks for helping!
You can use futurebuilder or you can use in initstate to fetch api
#override
void initState() {
// TODO: implement initState
Future.delayed(Duration(seconds: 10), () {
setState(() {
userinfo = "response";
});
// userinfo = "response";
});
super.initState();
}
Inside the widget
Text(userinfo != null ? userinfo.toString() : "loading..."),
SAmple Code
import 'package:flutter/material.dart';
//import 'package:pucon/home.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String? userinfo = null;
String? userinfo2 = null;
#override
void initState() {
// TODO: implement initState
Future.delayed(Duration(seconds: 10), () {
setState(() {
userinfo = "response";
});
// userinfo = "response";
});
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: ListView(
shrinkWrap: true,
children: [
Text(""),
Text(""),
Text(userinfo != null ? userinfo.toString() : "loading..."),
Row(
children: [
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Container(
child: Text(userinfo2.toString()), );
} else {
return SizedBox(
child: CircularProgressIndicator(),
height: 45,
width: 45,
);
// else
// return Container(
// child: CircularProgressIndicator(),
// height: 45,
// width: 45,
// );
}
},
future: _future(),
),
],
)
// InsertData(),
],
),
);
}
_future() async {
await Future.delayed(Duration(seconds: 5), () {
userinfo2 = "Completed";
// setState(() {
//
// });
// userinfo = "response";
});
}
}
I'm trying to get and display 2 variable values from another dart file, ("int myId" and "String myMenu") , these variables are updated with every "onTap" widget, my code works, but only if i do a "hot reload", i think that i need to put a "setstate" somewhere, but i'm having difficulty to implement it.
I think the problem is there, my widget text returns "null" to me, but if I hit the menu button and do a "hot reload", it's ok.
displayText.dart
import 'package:flutter/material.dart';
import './menu.dart';
class display extends StatefulWidget {
int myId;
String myMenu;
display(this.myId, this.myMenu);
#override
_displayState createState() => _displayState();
}
class _displayState extends State<display> {
Future myVarUsed() async {
//Each press on the button return the value
setState(() {
print('myIdDsiplay: ${widget.myId}'); // null
print('myMenuDisplay : ${widget.myMenu}'); // null
});
}
#override
void initState() {
super.initState();
myVarUsed();
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
height: 250,
width: 250,
child: Row(
children: [
Text('My ID is : ${widget.myId}'),
Text('My menu is : ${widget.myMenu}'),
],
),
);
}
}
This file contains the menu inside a scrollbar, each button return the ID and the name (of the button) and store it in 2 variable ("int myId" and "String myMenu") that i want to pass.
menu.dart
import 'package:flutter/material.dart';
import './mylist.dart';
import './displayText.dart';
class Menu extends StatefulWidget {
static int myId;
static String myMenu;
#override
_MenuState createState() => _MenuState();
}
class _MenuState extends State<Menu> {
Container scrollList() {
final PageController controller = PageController(initialPage: 1, keepPage: true, viewportFraction: 0.35);
return Container(
color: Colors.red,
height: 90,
child: PageView.builder(
scrollDirection: Axis.horizontal,
controller: controller,
itemCount: listdata.length,
physics: BouncingScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Container(
child: gestureDetector_Ontap(index),
);
},
),
);
}
GestureDetector gestureDetector_Ontap(int index) {
return GestureDetector(
onTap: () {
Menu.myId = listdata[index].id;
Menu.myMenu = listdata[index].menuObj;
display(Menu.myId, Menu.myMenu);
print('myIDMenu ${Menu.myId}');
print('myMenuMenu ${Menu.myMenu}');
},
child: Container(
alignment: AlignmentDirectional.center,
child: Text(
'${listdata[index].menuObj}',
),
),
);
}
Widget build(BuildContext context) {
return Container(
child: scrollList(),
);
}
}
This file contains my list and his class
mylist.dart
class listModel {
int id;
String menuObj;
listModel(this.id, this.menuObj);
}
List listdata = [
listModel(0, 'Menu01'),
listModel(1, 'Menu02'),
listModel(2, 'Menu03'),
listModel(3, 'Menu04'),
listModel(4, 'Menu05')
];
And the container
main.dart
import 'package:flutter/material.dart';
import './menu.dart';
import './displayText.dart';
import './mylist.dart';
void main() {
runApp(MyHomePage());
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: Column(
children: <Widget>[
Menu(),
display(Menu.myId, Menu.myMenu),
],
),
),
),
);
}
}
The problem
You're defining Menu this way:
class Menu extends StatefulWidget {
static int myId;
static String myMenu;
#override
_MenuState createState() => _MenuState();
}
When your app starts, myId and myMenu are uninitialized variables, therefore they're implicitely set to null.
Inside _MyHomePageState, you call
display(Menu.myId, Menu.myMenu)
Since you haven't initialized Menu.myId and Menu.myMenu yet, they're still null.
When you tap the GestureDetector, you initialize Menu.myId and Menu.myMenu this way:
Menu.myId = listdata[index].id;
Menu.myMenu = listdata[index].menuObj;
display(Menu.myId, Menu.myMenu);
print('myIDMenu ${Menu.myId}');
print('myMenuMenu ${Menu.myMenu}');
Now, Menu.myId and Menu.myMenu are defined to non-null values. However, this will not update the Container's display(Menu.myId, Menu.myMenu), so they'll still be null, you need to update it by yourself.
The solution
I've added comments through the code, pointing a better approach:
import 'package:flutter/material.dart';
// Avoid displaying the warning "Name types using UpperCamelCase."
class Display extends StatefulWidget {
// Make these fields final and the constructor const
final int myId;
final String myMenu;
const Display(this.myId, this.myMenu);
#override
_DisplayState createState() => _DisplayState();
}
// Avoid displaying the warning "Name types using UpperCamelCase."
class _DisplayState extends State<Display> {
// You don't need this Future nor this initState
//
// Future myVarUsed() async {
// setState(() {
// print('myIdDsiplay: ${widget.myId}'); // null
// print('myMenuDisplay : ${widget.myMenu}'); // null
// });
// }
//
// #override
// void initState() {
// super.initState();
// myVarUsed();
// }
#override
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
height: 250,
width: 250,
child: Row(
children: [
Text('My ID is : ${widget.myId}'),
Text('My menu is : ${widget.myMenu}'),
],
),
);
}
}
class Menu extends StatefulWidget {
// Avoid using mutable static fields
// static int myId;
// static String myMenu;
// To simplify, you can add a onChanged callback to
// be triggered whenever you change `myId` and `myMenu`
final void Function(int myId, String myMenu) onChanged;
const Menu({this.onChanged});
#override
_MenuState createState() => _MenuState();
}
class _MenuState extends State<Menu> {
Container scrollList() {
final PageController controller = PageController(initialPage: 1, keepPage: true, viewportFraction: 0.35);
return Container(
color: Colors.red,
height: 90,
child: PageView.builder(
scrollDirection: Axis.horizontal,
controller: controller,
itemCount: listdata.length,
physics: BouncingScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Container(
child: gestureDetectorOntap(index),
);
},
),
);
}
// Avoid displaying the warning "Name non-constant identifiers using lowerCamelCase."
GestureDetector gestureDetectorOntap(int index) {
return GestureDetector(
onTap: () {
// Make these local variables
int myId = listdata[index].id;
String myMenu = listdata[index].menuObj;
// Call the `onChanged` callback
widget.onChanged(myId, myMenu);
// This widget is being thrown away
// display(Menu.myId, Menu.myMenu);
print('myIDMenu $myId');
print('myMenuMenu $myMenu');
},
child: Container(
alignment: AlignmentDirectional.center,
child: Text(
'${listdata[index].menuObj}',
),
),
);
}
Widget build(BuildContext context) {
return Container(
child: scrollList(),
);
}
}
// Avoid the warning "Name types using UpperCamelCase."
class ListModel {
// You can make these fields final and the constructor const
final int id;
final String menuObj;
const ListModel(this.id, this.menuObj);
}
// You can make this list const to avoid modifying it unintentionally later
const List<ListModel> listdata = [
ListModel(0, 'Menu01'),
ListModel(1, 'Menu02'),
ListModel(2, 'Menu03'),
ListModel(3, 'Menu04'),
ListModel(4, 'Menu05')
];
void main() {
runApp(MyHomePage());
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Create fields to store the current `myId` and current `myMenu`
int myId;
String myMenu;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: Column(
children: <Widget>[
// Add the `onChanged` callback here, updating this widget state
Menu(
onChanged: (newMyId, newMyMenu) {
setState(() {
myId = newMyId;
myMenu = newMyMenu;
});
}
),
// Access the current values here
Display(myId, myMenu),
],
),
),
),
);
}
}
Well the issue is kinda simple, but it needs to be done on a specific way. First I have a Class extending "ChangeNotifier" this class will perform some async tasks, so while it is doing so there's a variable that indicates if the class is currently bussy or not, so far it works flawlessly.
Using Riverpod as state managment I instanciate said class and provide it along my widget tree, but there's one Widget that needs to display a dialog and inside this dialog it can execute async tasks from the Class that I've been passing around. It all works except for the fact that I would like to display a CircularProgressIndicator inside this dialog, and it doesn't seems to be reacting propperly to the state changes.
Here's a sample code to recreate the scenario:
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
final dataProvider = ChangeNotifierProvider<Data>((_) => Data());
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'huh?',
theme: ThemeData(primarySwatch: Colors.blue),
home: FirstPage(),
);
}
}
class FirstPage extends HookWidget {
#override
Widget build(BuildContext context) {
final data = useProvider(dataProvider);
print('DATA STATE [source: FirstPage, data: ${data.loading}]');
return Scaffold(
body: Center(
child: Container(
width: 200,
height: 50,
child: ElevatedButton(
child: Text('show dialog'),
onPressed: () => showDialog(
context: context,
builder: (_) => Alert(data: data),
),
),
),
),
);
}
}
class Alert extends StatelessWidget {
const Alert({required this.data});
final Data data;
Widget build(BuildContext context) {
print('DATA STATE [source: Alert, data: ${data.loading}]');
return AlertDialog(
content: Container(
width: 500,
height: 500,
padding: EdgeInsets.symmetric(horizontal: 100, vertical: 200),
child: ElevatedButton(
child: data.loading ? CircularProgressIndicator(color: Colors.white) : Text('click here'),
onPressed: () async => await data.randomTask(),
),
),
);
}
}
class Data extends ChangeNotifier {
Data({
this.loading = false,
});
bool loading;
Future<void> randomTask() async {
print('Actually waiting 3 seconds..');
_update(loading: true);
await Future.delayed(Duration(seconds: 3));
print('Waiting done.');
_update(loading: false);
}
void _update({bool? loading}) {
this.loading = loading ?? this.loading;
notifyListeners();
}
}
Notice the prints I've placed, because of them if you run the app you'll see outputs on the console like:
DATA STATE [source: FirstPage, data: false]
DATA STATE [source: Alert, data: false]
Actually waiting 3 seconds..
DATA STATE [source: FirstPage, data: true]
Waiting done.
DATA STATE [source: FirstPage, data: false]
Which means that the state is actually changing, and everything is working fine, except for the dialog that seems to be static.
I already tried adding a "loading" bool as part of the "Alert" widget, and letting it manage its own state, and it works, but the code is not as clean as I would like to, because the Class "Data" is supposed to manage this kind of stuff.
Is there anything that can be done?
Thankyou in advance!
Adding StatefulBulider do the trick
class Alert extends StatelessWidget {
const Alert({required this.data});
final Data data;
Widget build(BuildContext context) {
print('DATA STATE [source: Alert, data: ${data.loading}]');
return AlertDialog(
content: StatefulBuilder(builder: (context, setState) {
return Container(
width: 500,
height: 500,
padding: EdgeInsets.symmetric(horizontal: 100, vertical: 200),
child: ElevatedButton(
child: data.loading
? CircularProgressIndicator(color: Colors.white)
: Text('click here'),
onPressed: () async => await data.randomTask(),
),
);
}),
);
}
}
I'm trying to restart an animated gif on Flutter. The gif image loads from network without a problem and animates after loading. I need to restart the animation on tapping a button.
Tried so far:
- setState
- change Key to some other unique key and setState to rebuild.
Solution as #chemamolins 's suggestion:
int _robotReloadCount=0;
....
GestureDetector(
onTap: () {
onTapRobot();
},
child: Center(
child: Container(
margin: EdgeInsets.only(top: 55.0, bottom: 5.0),
height: 150.0,
width: 150.0,
child:
FadeInImage(
key: this._robotImageKey,
placeholder: AssetImage('assets/common/robot_placeholder.png'),
image: NetworkImage(snapshot.data['robot_image_path'] +"robot_level" +snapshot.data['robot_level'].toString() +".gif"+"?"+this._robotReloadCount.toString()))),
),
),
....
onTapRobot() async{
setState(() {
this._robotReloadCount++;
});
}
I have done a lot of tests and it is not easy. The image is cached by the 'ImageProvider' and whatever you change or no matter the times you invoke build() the image is loaded from what is available in the cache.
So, apparently, you only have two options.
Either you rebuild with a new url, for instance by appending #whatever to the image url.
Or you remove the image from the cache as shown in the code below.
In either case you need to fetch again the image from the network.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String url = "https://media.giphy.com/media/hIfDZ869b7EHu/giphy.gif";
void _evictImage() {
final NetworkImage provider = NetworkImage(url);
provider.evict().then<void>((bool success) {
if (success) debugPrint('removed image!');
});
setState(() {});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: Image.network(url),
),
floatingActionButton: new FloatingActionButton(
onPressed: _evictImage,
child: new Icon(Icons.remove),
),
);
}
}