Flutter tween basic animation is not working inside `FutureBuilder`
3,482
Solution 1
The animation is running but your build widget is not updating i.e. rebuild
try this code if it works as you expected let me know.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
void main() => runApp(GalleryGrid());
class GalleryGrid extends StatefulWidget {
@override
_GalleryGridState createState() => _GalleryGridState();
}
class GalleryModel {
final String thumbnailUrl;
GalleryModel(this.thumbnailUrl);
factory GalleryModel.fromJson(Map<String, dynamic> data) {
return GalleryModel(data['thumbnailUrl']);
}
}
class _GalleryGridState extends State<GalleryGrid>
{
List<GalleryModel> lists = List();
Future<List<GalleryModel>> fetchPost() async {
final response =
await http.get("https://jsonplaceholder.typicode.com/photos");
if (response.statusCode == 200) {
var datas = json.decode(response.body);
lists = (datas as List)
.map((data) => new GalleryModel.fromJson(data))
.toList();
return lists;
} else {
throw Exception("Failed to load photos");
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: FutureBuilder(
future: fetchPost(),
builder: (context, data) {
switch (data.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
default:
return new GridWidget(lists: lists);
}
},
),
),
);
//),
//);
}
}
class GridWidget extends StatefulWidget {
const GridWidget({
Key key,
@required this.lists,
}) ;
final List<GalleryModel> lists;
@override
GridWidgetState createState() {
return new GridWidgetState();
}
}
class GridWidgetState extends State<GridWidget> with TickerProviderStateMixin{
AnimationController _controller;
Animation _squeezeOutAnimation, transformationAnim;
@override
void initState() {
super.initState();
_controller =
AnimationController(duration: Duration(seconds: 3), vsync: this);
transformationAnim = BorderRadiusTween(
begin: BorderRadius.circular(150.0),
end: BorderRadius.circular(0.0))
.animate(CurvedAnimation(parent: _controller, curve: Curves.ease))
..addListener(() {
setState(() {});
});
_squeezeOutAnimation = Tween<double>(begin: 150.0, end: 1000.0)
.animate(CurvedAnimation(parent: _controller, curve: Curves.ease));
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemCount: widget.lists.length,
itemBuilder: (BuildContext context, int index) {
return Stack(children: <Widget>[
Container(
child: Card(
shape: BeveledRectangleBorder(
borderRadius: transformationAnim.value),
elevation: 10.0,
child: GestureDetector(
onTap: () {
print('Card $index is pressed');
_controller.reset();
_controller.forward();
},
child: Container(
width: _squeezeOutAnimation.value,
height: _squeezeOutAnimation.value,
child: Image.network(
widget.lists[index].thumbnailUrl,
fit: BoxFit.fill,
width: _squeezeOutAnimation.value,
),
),
),
),
),
]);
},
);
}
}
Solution 2
You could use the Hero Widget which does a lot of the work for you using tags:
class HomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Image> images;
@override
void initState() {
images = new List<Image>();
images.add(Image.asset("assets/blue.png"));
images.add(Image.asset("assets/red.png"));
images.add(Image.asset("assets/green.png"));
images.add(Image.asset("assets/yellow.png"));
images.add(Image.asset("assets/pink.png"));
images.add(Image.asset("assets/cyan.png"));
// get images
super.initState();
}
@override
Widget build(BuildContext context) {
return Material(
child: GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: images.length,
itemBuilder: (context, index) {
String tag = "Image" + index.toString();
return Hero(
tag: tag,
child: Material(
child: InkWell(
child: GridTile(child: images[index]),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(title: Text(tag)),
body: ImagePage(image: images[index], imageTag: tag));
}));
},
)));
},
));
}
}
class ImagePage extends StatefulWidget {
final Image image;
final String imageTag;
ImagePage({this.image, this.imageTag});
@override
State<StatefulWidget> createState() => new _ImagePageState();
}
class _ImagePageState extends State<ImagePage> {
@override
Widget build(BuildContext context) {
return Hero(
tag: widget.imageTag,
child: Material(
child: Center(
child: widget.image,
),
),
);
}
}
Author by
rahul.sharma
I am a full stack developer from last 1 year , my primary field is Android App Development.
Updated on December 08, 2022Comments
-
rahul.sharma over 1 year
Flutter tween basic animation is not working inside
FutureBuilder
I have created a image gallery page using gridview.builder , but the animation doesnt works inside
futurebuilder
for some reason. I tried same animation on an static image directly inside the container of the body and it worked perfectly fine.Need some way to animate network images inside futurebuilder.class _GalleryGridState extends State<GalleryGrid> with TickerProviderStateMixin { AnimationController _controller; Animation _squeezeOutAnimation, transformationAnim; List<GalleryModel> lists = List(); Future<List<GalleryModel>> fetchPost() async { final response = await http.get("https://jsonplaceholder.typicode.com/photos"); if (response.statusCode == 200) { var datas = json.decode(response.body); lists = (datas as List) .map((data) => new GalleryModel.fromJson(data)) .toList(); return lists; } else { throw Exception("Failed to load photos"); } } @override void initState() { super.initState(); _controller = AnimationController(duration: Duration(seconds: 3), vsync: this); transformationAnim = BorderRadiusTween( begin: BorderRadius.circular(150.0), end: BorderRadius.circular(0.0)) .animate(CurvedAnimation(parent: _controller, curve: Curves.ease)); _squeezeOutAnimation = Tween<double>(begin: 150.0, end: 1000.0) .animate(CurvedAnimation(parent: _controller, curve: Curves.ease)); } @override void dispose() { super.dispose(); _controller.dispose(); } @override Widget build(BuildContext context) { return FutureBuilder( future: fetchPost(), builder: (context, data) { switch (data.connectionState) { case ConnectionState.waiting: return Center(child: CircularProgressIndicator()); default: return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), itemCount: lists.length, itemBuilder: (BuildContext context, int index) { return Stack( children: <Widget>[ Container( child: Card( shape: BeveledRectangleBorder( borderRadius: transformationAnim.value), elevation: 10.0, child: GestureDetector( onTap: () { _controller.forward(); }, child: Container( width: _squeezeOutAnimation.value, height: _squeezeOutAnimation.value, child: Image.network( lists[index].thumbnailUrl, fit: BoxFit.fill, width: _squeezeOutAnimation.value, ), ), ), ), ), ])