颤振补间基本动画在“FutureBuilder”中不起作用

Posted

技术标签:

【中文标题】颤振补间基本动画在“FutureBuilder”中不起作用【英文标题】:Flutter tween basic animation is not working inside `FutureBuilder` 【发布时间】:2019-05-01 03:34:07 【问题描述】:

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

我使用 gridview.builder 创建了一个图片库页面,但由于某种原因,动画在 futurebuilder 中不起作用。我直接在 body 容器内的静态图像上尝试了相同的动画,效果非常好。需要一些方法来为 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,
                            ),
                          ),
                        ),
                      ),
                    ),
            ])

【问题讨论】:

【参考方案1】:

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

试试这个代码,如果它按预期工作,请告诉我。

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

【讨论】:

thanx 兄弟它的工作,bt 现在的问题是所有的图像都在一次动画,我希望点击的项目只有动画,使用当前动画是否可以实现。 @rahul.sharma 我想是的,如果你设法将一张卡片提取到它自己的小部件中并将动画相关代码放在那里,我认为它可以工作。试一试,让我知道是否我可以提供更多帮助。 是的,我也在想同样的逻辑,谢谢,我会试一试【参考方案2】:

您可以使用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,
        ),
      ),
    );
  

【讨论】:

欣赏它,但我的目标是仅在同一屏幕上弹出点击的图像,帮助我实现它 我尝试在没有futurebuilder的情况下为图像制作动画,效果很好,所以futurebuilder导致动画出现问题。

以上是关于颤振补间基本动画在“FutureBuilder”中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 FutureBuilder 中使用 Uint8List 的颤振给出错误

flash动画有几种基本类型?

选择值时出现颤振下拉按钮错误[使用来自 api 和 FutureBuilder 的数据]

android中补间动画怎样循环执行

Android 开发学习

如何用补间动画效果绘制三个 js 线条几何?