Flutter将SliverAppBar与Hero小部件配合使用

2guxujil  于 2023-02-13  发布在  Flutter
关注(0)|答案(2)|浏览(162)

我在使用SliverAppBar时遇到问题。

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Demo Home Page'),
      ),
      body: Center(
        child: Row(
          children: [Colors.red, Colors.blue, Colors.yellow]
              .map((e) => GestureDetector(
                    onTap: () {
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (_) => ScrollPage(color: e),
                          ));
                    },
                    child: Hero(
                      tag: e,
                      child: Container(
                        width: 100,
                        height: 100,
                        color: e,
                      ),
                    ),
                  ))
              .toList(),
        ),
      ),
    );
  }
}
import 'package:flutter/material.dart';

class ScrollPage extends StatefulWidget {
  const ScrollPage({super.key, required this.color});

  final Color color;

  @override
  State<ScrollPage> createState() => _ScrollPageState();
}

class _ScrollPageState extends State<ScrollPage> {
  // final GlobalKey key = GlobalKey<SliverState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          Hero(
            tag: widget.color,
            child: SliverAppBar.large(
              key: UniqueKey(),
              expandedHeight: 200,
              backgroundColor: widget.color,
              title: const Text(
                'This is a title blblaa',
              ),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => ListTile(
                title: Text('Item $index'),
              ),
              childCount: 100,
            ),
          ),
        ],
      ),
    );
  }
}

我收到如下错误:

════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 6405 pos 12: 'renderObject.child == child': is not true.

以及

════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 6369 pos 12: 'child == _child': is not true.
framework.dart:6369
The relevant error-causing widget was
MaterialApp

有时候:

════════ Exception caught by widgets library ═══════════════════════════════════
Duplicate GlobalKey detected in widget tree.
════════════════════════════════════════════════════════════════════════════════

我做了类似的不使用Appbar,我实现了它。演示视频here。但是,我真的想在这种情况下使用SliverAppbar。
完整的最小可复制项目:https://github.com/iqfareez/flutter_hero_sliver
如何让SliverAppBar与Hero一起工作?

voase2hg

voase2hg1#

您可以尝试将Hero小工具移出SliverAppBar,将其环绕在整个CustomScrollView周围。以下是您可以修改代码以实现此目的的方法:

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Hero(
        tag: 'row',
        child: Center(
          child: Row(
            children: [Colors.red, Colors.blue, Colors.yellow]
                .map((e) => GestureDetector(
                      onTap: () {
                        Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (_) => ScrollPage(color: e),
                            ));
                      },
                      child: Container(
                        width: 100,
                        height: 100,
                        color: e,
                      ),
                    ))
                .toList(),
          ),
        ),
      ),
    );
  }
}

class ScrollPage extends StatefulWidget {
  const ScrollPage({super.key, required this.color});

  final Color color;

  @override
  State<ScrollPage> createState() => _ScrollPageState();
}

class _ScrollPageState extends State<ScrollPage> {
  // final GlobalKey key = GlobalKey<SliverState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Hero(
        tag: 'row',
        child: CustomScrollView(
          slivers: [
            SliverAppBar(
              key: UniqueKey(),
              expandedHeight: 200,
              backgroundColor: widget.color,
              title: const Text(
                'This is a title blblaa',
              ),
            ),
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) => ListTile(
                  title: Text('Item $index'),
                ),
                childCount: 100,
              ),
            ),
          ],
        ),
      ),
    );
  }
}
uyhoqukh

uyhoqukh2#

这里的问题是Hero是一个通用的小部件,而不是一个小部件,这是在用Hero小部件 Package SliverAppBar时出现的问题。
你能做到

SliverToBoxAdapter(
  child: Hero(
    tag: widget.color,
    child: // customAppBar but it might loss the scroll-effect,

此外,您可以将Scaffold Package 为Hero小部件,但它将显示略有不同的动画。
您可以创建SliverPersistentHeaderDelegate
检查pr并提交差异。

import 'package:flutter/material.dart';

class ScrollPage extends StatefulWidget {
  const ScrollPage({super.key, required this.color});

  final Color color;

  @override
  State<ScrollPage> createState() => _ScrollPageState();
}

class _ScrollPageState extends State<ScrollPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverPersistentHeader(
              delegate: MySliverPersistentHeaderDelegate(widget.color)),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => ListTile(
                title: Text('Item $index'),
              ),
              childCount: 100,
            ),
          ),
        ],
      ),
    );
  }
}

class MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
  final tag;

  MySliverPersistentHeaderDelegate(this.tag);
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Hero(
      tag: tag,
      child: Material(
        color: tag,
        child: Stack(
          children: [
            Align(
              child: const Text(
                'This is a title blblaa',
              ),
            ),
            Align(
              alignment: Alignment.topLeft,
              child: IconButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  icon: Icon(Icons.arrow_back)),
            ),
          ],
        ),
      ),
    );
  }

  @override
  double get maxExtent => 200;

  @override
  double get minExtent => kToolbarHeight;

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
      true;
}

相关问题