Как предотвратить анимацию героя от SliverAppBar? - PullRequest
0 голосов
/ 29 марта 2020

У меня есть анимация героя, которая должна анимировать изображение от ListView до фона FlexibleSpaceBar внутри SliverAppBar. Это прекрасно работает, за исключением того, что анимация героя происходит поверх SliverAppBar, а когда анимация заканчивается, внезапно появляется SliverAppBar поверх фона, что выглядит не очень хорошо.

Как я могу либо а) включить SliverAppBar в переход героя, чтобы он появлялся поверх изображения в процессе перехода, либо б) заставить переход героя происходить под SliverAppBar, не покрывая его?

Пример кода:

import 'dart:math';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',
      routes: {
        '/': (context) => HomePage(),
        '/details': (context) => DetailsPage(),
      },
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        preferredSize: AppBar().preferredSize,
        child: Hero(
          tag: 'appbar',
          child: AppBar(
            title: Text('title'),
            actions: <Widget>[
              PopupMenuButton<String>(
                itemBuilder: (BuildContext context) {
                  return [
                    PopupMenuItem<String>(
                      child: Text('Action'),
                    )
                  ];
                },
              ),
            ],
          ),
        ),
      ),
      body: ListView.builder(
        padding: const EdgeInsets.fromLTRB(10, 10, 10, 0),
        itemCount: 10,
        itemBuilder: (context, index) => buildListItem(context, index),
      ),
    );
  }

  Widget buildListItem(BuildContext context, int index) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 10),
      child: InkWell(
        onTap: () async {
          await Navigator.of(context).pushNamed(
            '/details',
            arguments: index,
          );
        },
        child: Row(
          children: <Widget>[
            Hero(
              tag: index,
              child:
                  SizedBox(width: 80, height: 80, child: widgetForIndex(index)),
            ),
          ],
        ),
      ),
    );
  }
}

Widget widgetForIndex(int index) {
  return Container(color: Color.fromARGB(255, max(0, 255 - 20 * index), 0, 0));
}

class DetailsPage extends StatefulWidget {
  @override
  _DetailsPageState createState() => _DetailsPageState();
}

class _DetailsPageState extends State<DetailsPage> {
  @override
  Widget build(BuildContext context) {
    final int index = ModalRoute.of(context).settings.arguments;
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            title: Text('Details'),
            expandedHeight: 300,
            flexibleSpace: FlexibleSpaceBar(
              background: Hero(
                tag: index,
                child: widgetForIndex(index),
              ),
            ),
          ),
          SliverToBoxAdapter(
            child: Column(
              children: [
                Container(
                  color: Colors.green,
                  width: 200,
                  height: 200,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
...