Flutter:Hero 小部件、Navigation 2.0 和 Provider 不能一起正常工作

Posted

技术标签:

【中文标题】Flutter:Hero 小部件、Navigation 2.0 和 Provider 不能一起正常工作【英文标题】:Flutter: Hero widget, Navigation 2.0 and Provider are not working properly together 【发布时间】:2021-02-11 18:47:01 【问题描述】:

我尝试将Hero 小部件与ChangeNotifierProvider 和新的Navigation 2.0 系统一起使用。但我在那里面临问题。当不使用changeNotifier 时,相同的代码有效

我面临的问题是,在弹出第二页W2后,第一页的文字(即英雄的孩子)消失了。

下面是完整的代码。 runApp(HeroTestApp2()) 照常工作。但我很想让第一种方法奏效。请帮忙。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

main(List<String> args) 
  runApp(HeroTestApp());


class MyModel extends ChangeNotifier 
  bool _go = false;
  bool get go => _go;
  set go(bool go) 
    _go = go;
    notifyListeners();
  


class HeroTestApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return ChangeNotifierProvider<MyModel>(
      create: (context) => MyModel(),
      builder: (context, _) 
        final state = context.watch<MyModel>();
        return MaterialApp(
          home: Navigator(
            pages: [
              MaterialPage(child: W1(onTapped: null)),
              if (state.go) MaterialPage(child: W2()),
            ],
            onPopPage: (route, result) 
              if (!route.didPop(result)) return false;
              state.go = false;
              return true;
            ,
            observers: [HeroController()],
          ),
        );
      ,
    );
  


class HeroTestApp2 extends StatefulWidget 
  @override
  _HeroTestApp2State createState() => _HeroTestApp2State();


class _HeroTestApp2State extends State<HeroTestApp2> 
  bool go = false;

  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      home: Navigator(
        pages: [
          MaterialPage(
            child: W1(onTapped: () 
              setState(() 
                go = true;
              );
            ),
          ),
          if (go) MaterialPage(child: W2()),
        ],
        onPopPage: (route, result) 
          if (!route.didPop(result)) return false;
          go = false;
          return true;
        ,
        observers: [HeroController()],
      ),
    );
  


class W1 extends StatelessWidget 
  final void Function() onTapped;

  const W1(Key key, this.onTapped) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return GestureDetector(
      onTap: onTapped ??
          () => context.read<MyModel>().go = true,
      child: Scaffold(
        appBar: AppBar(),
        body: Container(
          alignment: Alignment.topRight,
          child: Hero(
            tag: "topic",
            child: DefaultTextStyle(
              style: TextStyle(
                  fontSize: 40,
                  decoration: TextDecoration.none,
                  color: Colors.blue),
              child: Text(
                "data",
                style: TextStyle(fontSize: 40),
              ),
            ),
          ),
        ),
      ),
    );
  


class W2 extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        alignment: Alignment.bottomLeft,
        child: Hero(
          tag: "topic",
          child: DefaultTextStyle(
            style: TextStyle(
                fontSize: 140,
                decoration: TextDecoration.none,
                color: Colors.blue),
            child: Text(
              "data",
            ),
          ),
        ),
      ),
    );
  

【问题讨论】:

【参考方案1】:

好的,我找到答案了。

observers: [HeroController()],

每次状态改变时,洞树都会与 HeroController 一起重建。解决方法是在changeNotifier上方定义HeroController:

class HeroTestApp extends StatelessWidget 
  final heroC = HeroController();

  @override
  Widget build(BuildContext context) 
    return ChangeNotifierProvider<MyModel>(
      create: (context) => MyModel(),
      builder: (context, _) 
        final state = context.watch<MyModel>();
        return MaterialApp(
          home: Navigator(
            pages: [
              MaterialPage(child: W1(onTapped: null)),
              if (state.go) MaterialPage(child: W2()),
            ],
            onPopPage: (route, result) 
              if (!route.didPop(result)) return false;
              state.go = false;
              return true;
            ,
            observers: [heroC],
          ),
        );
      ,
    );
  

谢谢。

【讨论】:

Tks,你救了我的一天,兄弟 很高兴听到它帮助了某人。 ?

以上是关于Flutter:Hero 小部件、Navigation 2.0 和 Provider 不能一起正常工作的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:Hero 小部件、Navigation 2.0 和 Provider 不能一起正常工作

Flutter - 来自 Firebase 的英雄小部件子图像 url

禁用 Flutter Hero 反向动画

Flutter:在 ListView Builder 中使用 Hero 动画

Flutter:使用包装器时如何使用Routes在页面之间进行路由

Flutter每周一个Widget系列