自动计算SliverPersistentHeaderDelega

自动计算SliverPersistentHeaderDelega

本文介绍了自动计算SliverPersistentHeaderDelegate的maxExtent的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下示例,该示例旨在在 CustomScrollView 内呈现固定的标题栏(带有可能的自定义长/短文本).

Consider the following example that is intended to render a pinned title bar (with a potentially custom long/short text) inside of a CustomScrollView.

class TitleBar extends StatelessWidget {
  TitleBar(this.text);

  final String text;

  @override
  Widget build(BuildContext context) => Text(
        text,
        style: TextStyle(fontSize: 30),
        maxLines: 3,
        overflow: TextOverflow.ellipsis,
      );
}

class TitleBarDelegate extends SliverPersistentHeaderDelegate {
  final String text;

  TitleBarDelegate(this.text);

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => TitleBar(text);

  @override
  bool shouldRebuild(TitleBarDelegate oldDelegate) => oldDelegate.text != text;

  @override
  double get maxExtent => ???;

  @override
  double get minExtent => maxExtent; // doesn't shrink
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: CustomScrollView(
          slivers: [
            SliverPersistentHeader(
              pinned: true,
              delegate: TitleBarDelegate('Potentially very long text'),
            ),
            SliverToBoxAdapter(
              child: Text("Foo " * 1000),
            ),
          ],
        ),
      ),
    );
  }
}

问题是:如何根据实际的 TitleBar 计算 maxExtent .问题在于实际的 TitleBar 的大小取决于文本,因此通常可以预先计算.

The question is: How can I compute maxExtent based on the actual TitleBar. The problem is that the actual TitleBar's size depends on the text and is hence to generally computable in advance.

请注意,与上面的示例相比, TitleBar 的布局也可能更复杂.因此,通常的问题是如何收缩" SliverPersistentHeaderDelegate .

Note that TitleBar might also have some more complex layout than it has in the example above. So the general question is how to 'shrink-wrap' an SliverPersistentHeaderDelegate.

推荐答案

我最近遇到了同样的问题,并提出了以下脏"解决方案,假设标题仅包含具有给定文本样式的文本,并且您提供了最大宽度值.

I recently faced the same issue and came up with the following "dirty" solution, assuming the header only contains text with a given text style and you provide it with a max width value.

SliverPersistentHeaderDelegate 看起来像这样:

class SliverPersistentTitleDelegate extends SliverPersistentHeaderDelegate {

SliverPersistentTitleDelegate({
    @required this.width,
    @required this.text,
    this.textStyle,
    this.padding,
    this.extend = 10
}) {
    // create a text painter
    final TextPainter textPainter = TextPainter(
        textDirection: TextDirection.ltr,
    )
    ..text = TextSpan(
        text: text,
        style: _textStyle,
    );

    // layout the text with the provided width, taking the horizontal padding into account
    final double horizontalPadding = _padding.left + _padding.right;
    textPainter.layout(maxWidth: width - horizontalPadding);

    // measure minHeight and maxHeight, taking the vertical padding and text height into account
    final double verticalPadding = _padding.top + _padding.bottom;
    _minHeight = textPainter.height + verticalPadding;
    _maxHeight = minHeight + extend;
}

final double width;
final String text;
final TextStyle textStyle;
final EdgeInsets padding;
final double extend;
double _minHeight;
double _maxHeight;

final core.ThemeProvider _themeProvider = di.get<core.ThemeProvider>();

@override
double get minExtent => _minHeight;

@override
double get maxExtent => maxHeight;

TextStyle get _textStyle => this.textStyle
    ?? _themeProvider
        .defaultTheme
        .appBarTheme
        .textTheme;

EdgeInsets get _padding => padding ?? EdgeInsets.zero;

@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent)
{
    return Padding(
        padding: _padding,
        child: Text(
            text,
            style: _textStyle ,
        ),
    );
}

@override
bool shouldRebuild(SliverPersistentTitleDelegate oldDelegate) {

    return width != oldDelegate.width
        || text != oldDelegate.text
        || textStyle != oldDelegate.textStyle
        || padding != oldDelegate.padding
        || extend != oldDelegate.extend
        || _maxHeight != oldDelegate._maxHeight
        || _minHeight != oldDelegate._minHeight;
}

}

使用此类很简单:

return LayoutBuilder(
    builder: (context, constrains) {

    return CustomScrollView(
        slivers: <Widget>[
            SliverPersistentHeader(
                pinned: false,
                floating: true,
                delegate: SliverPersistentTitleDelegate(
                    width: constrains.maxWidth,
                    text: "Some long dynamic title",
                    textStyle: titleTextStyle,
                    padding: EdgeInsets.only(
                        left: 16,
                        right: 16,
                    ),
                ),
            )
        ],
    );
},

);

这篇关于自动计算SliverPersistentHeaderDelegate的maxExtent的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 00:55