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:

Code Demo

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,
        ),
      ),
    );
  }
}
Share:
3,482
rahul.sharma
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, 2022

Comments

  • rahul.sharma
    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,
                                ),
                              ),
                            ),
                          ),
                        ),
                ])