自动计算`SliverPersistentHeaderDelegate`的`maxExtent`

问题描述 投票:1回答:2

请考虑以下示例,该示例旨在在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),
            ),
          ],
        ),
      ),
    );
  }
}

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

请注意,TitleBar的布局也可能比上例更复杂。因此,通常的问题是如何“收缩” SliverPersistentHeaderDelegate

flutter flutter-layout flutter-sliver
2个回答
0
投票

我认为您可能正在寻找_titleBar.preferredSize.height,但不能确定


0
投票

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

[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,
                    ),
                ),
            )
        ],
    );
},

);

© www.soinside.com 2019 - 2024. All rights reserved.