防止滚动的英雄组件跳到应用栏顶部

11

我有一个Hero,它可以滚动,因此其中一部分会离开屏幕。当我触发转换时,它似乎突然跳到AppBar的顶部,然后在反向转换时跳回下面。如何强制AppBar保持在Hero的顶部?

video

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    home: new Example(),
    theme: new ThemeData(primaryColor: Colors.orange),
    debugShowCheckedModeBanner: false,
  ));
}

Widget positionHeroOverlay(BuildContext context, Widget overlay, Rect rect, Size size) {
  final RelativeRect offsets = new RelativeRect.fromSize(rect, size);
  return new Positioned(
    top: offsets.top,
    right: offsets.right,
    bottom: offsets.bottom,
    left: offsets.left,
    child: overlay,
  );
}

class LogoPageRoute extends MaterialPageRoute<Null> {
  LogoPageRoute(this.colors) : super(
    builder: (BuildContext context) {
      return new Scaffold(
        appBar: new AppBar(
          title: new Text('Flutter Logo'),
        ),
        body: new ConstrainedBox(
          constraints: new BoxConstraints.expand(),
          child: new Hero(
            tag: colors,
            child: new FlutterLogo(colors: colors),
          ),
        ),
      );
    },
  );

  /// The color of logo to display
  final MaterialColor colors;

  @override
  final Duration transitionDuration = const Duration(seconds: 1);
}

final List<MaterialColor> swatches = [
  Colors.blue,
  Colors.orange,
  Colors.green,
];

class Example extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('All Logos'),
      ),
      body: new ListView(
        children: swatches.map((MaterialColor colors) {
          return new InkWell(
            onTap: () {
              Navigator.push(context, new LogoPageRoute(colors));
            },
            child: new Hero(
              tag: colors,
              child: new FlutterLogo(size: 360.0, colors: colors),
            ),
          );
        }).toList(),
      ),
    );
  }
}
3个回答

6
在一个 Hero 中包装你的 AppBar,以强制它置于顶部。
  appBar: new PreferredSize(
    child: new Hero(
      tag: AppBar,
      child: new AppBar(
        title: new Text('All Logos'),
      ),
    ),
    preferredSize: new AppBar().preferredSize,
  ),

对于详情页的 AppBar,我建议强制显示返回按钮,这样在页面标题更改时它会同时出现。

    appBar: new PreferredSize(
      child: new Hero(
        tag: AppBar,
        child: new AppBar(
          leading: const BackButton(),
          title: new Text('Flutter Logo'),
        ),
      ),
      preferredSize: new AppBar().preferredSize,
    ),

以下是它的外观:

video


2
你会失去应用栏的滑动转换效果。 - Rainer Wittmann
是的,我希望有人能提交更好的答案 :) - Collin Jackson
3
考虑到 Hero 使用导航叠加层,我认为要实现完全相同的动画可能需要大量工作或难以维护的代码。 - Rémi Rousselet
导航栏在 iPhone X 及以上设备的 Hero 转场期间会跳动。这是一个解决方法:https://github.com/flutter/flutter/issues/27848#issuecomment-484970205 - Andrey Gordeev

3

比apbbar和bottombar更大的照片怎么样? - Burak Mete Erdoğan
你是什么意思?照片更大了。不管怎样,这种解决方法并不总是有效的。它取决于滚动偏移和导航。你可以调整flightShuttleBuilder函数来支持你的情况。 - Sergey Zhukov

0
使用这个:
flightShuttleBuilder:
                                (BuildContext flightContext,
                                    Animation<double> animation,
                                    HeroFlightDirection flightDirection,
                                    BuildContext fromHeroContext,
                                    BuildContext toHeroContext) {
                              // make hero more smoothly
                              final Hero hero = (flightDirection ==
                                      HeroFlightDirection.pop
                                  ? fromHeroContext.widget
                                  : toHeroContext.widget) as Hero;

                              return hero.child;
                            },

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接