Flutter tween 基本动画在“FutureBuilder”中不起作用

Flutter tween basic animation is not working inside `FutureBuilder`

Flutter tween 基本动画在内部不起作用FutureBuilder

我使用 gridview.builder 创建了一个图片库页面,但出于某种原因,动画在 futurebuilder 中不起作用。我直接在 body 容器内的静态图像上尝试了相同的动画,它完美地工作 fine.Need 以某种方式在 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,
                            ),
                          ),
                        ),
                      ),
                    ),
            ])

您可以使用 Hero 小部件,它使用标签为您完成很多工作:

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,
        ),
      ),
    );
  }
}

动画是 运行 但您的构建小部件没有更新,即重建

试试这个代码,如果它能像你预期的那样工作,请告诉我。

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,
                  ),
                ),
              ),
            ),
          ),
        ]);
      },
    );
  }
}