【问题标题】:Hero animation is not working when navigating to new page flutter导航到新页面时,英雄动画不起作用
【发布时间】:2021-12-29 22:07:42
【问题描述】:

我在网格视图中有产品项目,这是一个未来的构建器,并用 Hero Widget 包装并通过 id 给出了一个唯一标签,详细的新页面我也用 Hero Widget 包装并给出了相同的唯一标签,但动画正在工作仅当返回屏幕时。我不明白为什么导航到新页面时英雄动画不起作用,可能是因为 Future builder?或者我犯了什么错误?不知道发生了什么,谁能帮我实现漂亮的英雄动画。下面我提供了我的代码。请随时提出任何问题。提前致谢。 main.dart

import 'package:flutter/material.dart';
import 'package:httprequest/screens/all_products.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const AllProductsScreen(),
    );
  }
}

all_products.dart

import 'package:flutter/material.dart';
import 'package:httprequest/screens/single_product.dart';
import 'package:httprequest/services/api_services.dart';

class AllProductsScreen extends StatefulWidget {
  const AllProductsScreen({Key? key}) : super(key: key);

  @override
  _AllProductsScreenState createState() => _AllProductsScreenState();
}

class _AllProductsScreenState extends State<AllProductsScreen> {
  Future ? products;
  @override
  void initState() {
    // TODO: implement initState
    products = ApiServices().getAllProducts();
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Products"),
      ),
      body: Container(
        padding: EdgeInsets.all(8.0),
        child: FutureBuilder(
          future: products,
          builder: (context, AsyncSnapshot snapshot){
            if(snapshot.hasData){
               return Center(
                 child: GridView.builder(
                     gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
                         maxCrossAxisExtent: 200,
                         childAspectRatio: 2 / 3,
                         crossAxisSpacing: 20,
                         mainAxisSpacing: 20),
                     itemCount: snapshot.data.length,
                     itemBuilder: (BuildContext ctx, index) {
                       return GestureDetector(
                         child: Hero(
                           tag: snapshot.data[index]["id"],
                           child: Card(
                             child: Container(
                               padding: EdgeInsets.all(5.0),
                               child: Column(
                                 children: [
                                   Image.network(snapshot.data[index]["image"],height: 180,width: 180,),
                                   Text(snapshot.data[index]["title"],textAlign: TextAlign.center,maxLines: 2,overflow: TextOverflow.ellipsis,),
                                   Text("\$: ${snapshot.data[index]["price"]}")
                                 ],
                               ),
                               decoration: BoxDecoration(
                                   color: Colors.white,
                                   borderRadius: BorderRadius.circular(15)),
                             ),
                           ),
                         ),
                         onTap: () {
                           Navigator.push(context, MaterialPageRoute(builder: (context) => SingleProduct(snapshot.data[index]["id"])));
                         },
                       );
                     }),
               );
              }
              return const Center(child: CircularProgressIndicator(),);
          },
        ),
      ),
    );
  }
}

single_product.dart

import 'package:flutter/material.dart';
import 'package:httprequest/services/api_services.dart';

class SingleProduct extends StatefulWidget {
final id;
SingleProduct(this.id);
  @override
  _SingleProductState createState() => _SingleProductState();
}

class _SingleProductState extends State<SingleProduct> {
  Future ? product;
  @override
  void initState() {
    // TODO: implement initState
    product = ApiServices().getSingleProduct(widget.id);
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Products"),
      ),
      body: FutureBuilder(
        future: product,
        builder: (context,AsyncSnapshot snapshot){
          if(snapshot.hasData){
            return Container(
              color: Colors.white,
              child: Column(
                children: [
                  Hero(
                    tag: widget.id,
                    child: Container(
                      color: Colors.transparent,
                      child: Center(
                        child: Image.network(snapshot.data["image"],height: 200,width: 200,),
                      ),
                    ),
                  ),
                  Expanded(
                    child: Container(
                      color: Colors.transparent,
                      child: Card(
                        color: Colors.white,
                        elevation: 20.0,
                        shape: RoundedRectangleBorder(
                            //side: BorderSide(width: 0.2),
                            borderRadius: BorderRadius.only(topRight: Radius.circular(20),topLeft: Radius.circular(20))),
                        child: Container(
                          padding: EdgeInsets.all(10.0),
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: [
                              Container(
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(snapshot.data["title"],textAlign: TextAlign.center,style: TextStyle(fontWeight: FontWeight.bold,fontSize: 16),),
                                    SizedBox(height: 5,),
                                    Row(
                                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                      children: [
                                        Text("\$: ${snapshot.data["price"]}",style: TextStyle(fontSize: 16),),
                                        Row(
                                          children: [
                                            Text(snapshot.data["rating"]["rate"].toString(),style: TextStyle(fontSize: 16),),
                                            Icon(Icons.star,color: Colors.yellow,size: 20,),
                                          ],
                                        ),
                                      ],
                                    ),
                                    SizedBox(height: 5,),
                                    Text(("Category: ${snapshot.data["category"]}"),textAlign: TextAlign.left,style: TextStyle(fontSize: 16),),
                                    SizedBox(height: 5,),
                                    Text(snapshot.data["description"],textAlign: TextAlign.justify,style: TextStyle(fontSize: 16),),
                                  ],
                                ),
                              ),
                              Align(
                                alignment: Alignment.bottomCenter,
                                  child: Container(
                                    padding: EdgeInsets.all(15),
                                    decoration: BoxDecoration(
                                      shape: BoxShape.rectangle,
                                      borderRadius: BorderRadius.circular(50),
                                      color: Colors.black,
                                    ),
                                    height: 50,
                                    width: 130,
                                    //color: Colors.black,
                                    child: Row(
                                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                      children: [
                                        Icon(Icons.shopping_cart,color: Colors.white,),
                                        Text("Add to cart",style: TextStyle(color: Colors.white),),
                                      ],
                                    ),
                                  ),
                                ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            );
          }
          return Center(child: CircularProgressIndicator());
        },
      ),
    );
  }
}

api_services.dart

import 'dart:developer';
import 'dart:convert';
import 'package:http/http.dart' as http;

class ApiServices {
  Future getAllProducts() async {
    var allProcuctsUri = Uri.parse('https://fakestoreapi.com/products');
    var response = await http.get(allProcuctsUri);
    log("All Products response : ${response.statusCode.toString()}");
    log("All Products body : ${response.body}");
    return json.decode(response.body);
  }

  Future getSingleProduct(int id) async {
    var singleProcuctUri = Uri.parse('https://fakestoreapi.com/products/${id}');
    var response = await http.get(singleProcuctUri);
    log("Single Product response : ${response.statusCode.toString()}");
    log("Single Product body : ${response.body}");
    return json.decode(response.body);
  }
}

【问题讨论】:

  • 我对转换不太了解,但我认为 hero 小部件的孩子需要相同。因此,在 single_product.dart 中尝试使用 Card 小部件将 Container 小部件包装在 Hero 中。
  • @darkstar 但我已经这样做了,我用 Hero 小部件包装了容器。如果我弄错了,你能提供一个工作代码,那对我真的很有帮助。

标签: flutter dart flutter-animation flutter-widget flutter-http


【解决方案1】:

你必须在 hero 小部件中为你想要动画的两个屏幕提供相同的标签。您已经用 HeroAnimation 包装了要制作动画的小部件并提供标签,然后用 HeroAnimation 包装另一个屏幕并为两个 HeroAnimation 小部件提供相同的标签..

【讨论】:

    【解决方案2】:

    检查两个标签是否相同首先打印all_products.dart的snapshot.data[index]["id"]和single_product.dart的widget.id。

    如果第二页标签为空,请在 single_product.dart 的 build 中初始化一个变量,如

     @override
     
    String finalid=widget.id; //add this and get reference from this
    
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("Products"),
          ),
    

    如果两个标签都是字符串格式会更好。

    【讨论】:

      猜你喜欢
      • 2023-03-03
      • 2018-11-01
      • 2014-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-02
      • 2020-07-31
      • 1970-01-01
      相关资源
      最近更新 更多