Flutter:SliverPersistentHeader在滚动时重建自身

3
我已经为我遇到的这个问题建立了一个小测试示例。从下面的gif中可以看出,Flutter应用仅在顶部具有标题。当我下拉刷新时,标题不会重新构建自身。但是,当我将标题向上推时,标题会重新构建自身多次。同时请注意,我在我的代码中没有调用setState(),所以我不确定它如何知道在我将scrollview向上推时需要重新构建自身。
我希望标题根本不要重新构建自身,因为没有理由使其重新构建自身。它是静态/无状态的,不应该发生任何变化。标题的大小也不应改变(因此展开高度和折叠高度相同,为136.0)。

enter image description here

这是我用来示范的代码,你可以使用它来重新创建:

import 'package:meta/meta.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:math' as math;
import 'dart:async';

class _TestHeader extends SliverPersistentHeaderDelegate {
  _TestHeader({
    @required this.collapsedHeight,
    @required this.expandedHeight,
    @required this.showHeading,
  });

  bool showHeading;
  final double expandedHeight;
  final double collapsedHeight;

  @override
  double get minExtent => collapsedHeight;

  @override
  double get maxExtent => math.max(expandedHeight, minExtent);

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    print("rebuilding headings");
    return new SafeArea(
        child: Column(children: <Widget>[
      const SizedBox(height: 24.0),
      new GestureDetector(
        onTap: () {
        },
        child: new Container(
          decoration: const BoxDecoration(
            color: CupertinoColors.white,
            border: const Border(
              top: const BorderSide(color: const Color(0xFFBCBBC1), width: 0.0),
              bottom:
                  const BorderSide(color: const Color(0xFFBCBBC1), width: 0.0),
            ),
          ),
          height: 44.0,
          child: new Padding(
            padding:
                const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
            child: new SafeArea(
              top: false,
              bottom: false,
              child: new Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: const <Widget>[
                  const Text(
                    'This is my heading',
                    style: const TextStyle(color: CupertinoColors.activeBlue, fontSize: 16.0),
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    ]));
  }

  @override
  bool shouldRebuild(@checked _TestHeader oldDelegate) {
//    return false;
    return expandedHeight != oldDelegate.expandedHeight ||
        collapsedHeight != oldDelegate.collapsedHeight;
  }
}

class TestHeaderPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new TestHeaderState();
  }
}


class TestHeaderState extends State<TestHeaderPage> {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new CupertinoPageScaffold(
      //i will need to convert this to a sliver list to make this work properly.
        backgroundColor: const Color(0xFFEFEFF4),
        navigationBar: new CupertinoNavigationBar(
          middle: new Text('Test Headers'),
        ),
        child: new SafeArea(
          child: new CustomScrollView(slivers: <Widget>[
            new CupertinoRefreshControl(onRefresh: () {
              print("pulling on refresh");
              return Future<void>(() {});
                }),
            new SliverPersistentHeader(
                delegate: new _TestHeader(
                    collapsedHeight: 136.0,
                    expandedHeight: 136.0,
                    showHeading: true)),
          ]),
        ));
  }

}
1个回答

4

这是完全正常的。

你的_TestHeader不是一个小部件。仅仅因为它有build方法并不意味着它是一个小部件。:)

你扩展了SliverPersistentHeaderDelegate,它用于构建SliverPersistentHeader

问题在于:SliverPersistentHeader也不是一个小部件。它是一种不同的方式来渲染屏幕上的东西,称为sliver。

而且,在SliverPersistentHeader的情况下,它是一种特定类型的sliver,每当滚动偏移量发生变化时就会重新构建。也就是说,可以处理特定于滚动的动画。例如,向上滚动使标题消失。向下滚动使其弹回。


谢谢您的解释。我也注意到我需要提供折叠和展开高度的标题,但我只想要一个静态标题。难道没有一种方法可以只呈现一个静态标题(一个固定大小且大小不会改变的标题),而无需提供折叠和展开高度吗? - Simon
1
您无需将它们传递给_TestHeader。 您可以从构造函数中删除它们并将minExtentmaxExtent硬编码为136.0 - Rémi Rousselet

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