Layout 有没有办法在SliverAppBar的底部小部件中实现动态高度

Layout 有没有办法在SliverAppBar的底部小部件中实现动态高度,layout,flutter,appbar,bottombar,flutter-sliver,Layout,Flutter,Appbar,Bottombar,Flutter Sliver,SliverAppBar有一个属性bottom,该属性必须具有preferredSize 现在我让它返回常量值: ... new SliverAppBar( expandedHeight: _kFlexibleSpaceMaxHeight, flexibleSpace: new FlexibleSpaceBar(.....) ... bottom: new BottomBar(...), // has to have

SliverAppBar有一个属性bottom,该属性必须具有preferredSize

现在我让它返回常量值:

  ...
  new SliverAppBar(
    expandedHeight: _kFlexibleSpaceMaxHeight,
    flexibleSpace: new FlexibleSpaceBar(.....)
    ...                   
    bottom: new BottomBar(...), // has to have preferredSize
  ),
  ...

class BottomBar extends StatelessWidget implements PreferredSizeWidget {
    ...
    @override
      Size get preferredSize {
        return new Size.fromHeight(my_constant_height_value);
      }

    ...
    }
我想把一个文本放在这个底部小部件中,我不知道里面的文本会有多长

如何实现底部小部件的动态高度

有没有一种方法可以在布局前测量小部件的高度

2018年4月25日编辑

最后,我按照Thibault的指示,最终得出以下结论:

// 'as rendering' to avoid conflict with 'package:intl/intl.dart'
import 'package:flutter/rendering.dart' as rendering; 

...

// this is the function that returns the height of a Text widget
// given the text
double getHeight(String text, BuildContext context, bool isTitle) {
  var rp = rendering.RenderParagraph(
    new TextSpan(
        style: isTitle
            ? Theme.of(context).primaryTextTheme.title
            : Theme.of(context).primaryTextTheme.subhead,
        text: text,
        children: null,
        recognizer: null),

    // important as the user can have increased text on his device
    textScaleFactor: MediaQuery.of(context).textScaleFactor, 

    textDirection: rendering.TextDirection.ltr,
  );
  var horizontalPaddingSum = 20; // optional 
  var width = MediaQuery.of(context).size.width - horizontalPaddingSum;
  // if your Text widget has horizontal padding then you have to 
  // subtract it from available width to get the needed results
  var ret = rp.computeMinIntrinsicHeight(width);
  return ret;
}

...


  _kPreferredBBTextHeight =
      getHeight(mTitle ?? "", context, true);

  var verticalPaddingSum = 10;
  _kPreferredBBSubTextHeight = getHeight(mSubtitle ?? "", context,false) + verticalPaddingSum;

  _kPreferredBottomBarSize =
      _kPreferredBBTextHeight + _kPreferredBBSubTextHeight + 48;

  _kFlexibleSpaceMaxHeight =
      _kPreferredBottomBarSize + _kPreferredBottomBarSize + kToolbarHeight;

  _backgroudBottomPadding = _kPreferredBottomBarSize;

...
new CustomSliverAppBar(
                pinned: true,
                automaticallyImplyLeading: false,
                primary: true,
                expandedHeight: _kFlexibleSpaceMaxHeight,
                flexibleSpace: new FlexibleSpaceBar(
                  background: new Padding(
                      padding:
                          new EdgeInsets.only(bottom: _backgroudBottomPadding),
                      child: new Image(
                        image: new NetworkImage(mImageUrl),
                        fit: BoxFit.cover,
                      )),
                ),
                bottom: new BottomBar(
                  fixedHeight: _kPreferredBottomBarSize,
                ),
              ),

...

class BottomBar extends StatelessWidget implements PreferredSizeWidget {
  final double fixedHeight;

  BottomBar({this.fixedHeight});

  @override
  Size get preferredSize {
    return new Size.fromHeight(this.fixedHeight);
  }

  @override
  Widget build(BuildContext context) {
    // https://github.com/flutter/flutter/issues/3782
    return new Container(
        height: this.fixedHeight,
        child: new Material(
            color: Theme.of(context).primaryColor,
            child: new Column(
              children: <Widget>[
                new Row(
                  children: <Widget>[
                    new IconButton(
                      icon: new Icon(Icons.arrow_back, color: Colors.white),
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                    ),
                    new Expanded(
                      child: new Container(),
                    ),
                    new IconButton(
                      icon: new Icon(Icons.share, color: Colors.white),
                      onPressed: () {
                        print("share pressed");
                      },
                    )
                  ],
                ),
                new Column(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    new Padding(
                        padding: new EdgeInsets.only(left: 10.0, right: 10.0),
                        child: new Container(
                          child: new Container(
                            alignment: Alignment.centerLeft,
                            child: new Text(
                              mTitle ?? "",
                              style: Theme.of(context).primaryTextTheme.title,
                            ),
                          ),
                        )),
                    new Container(
                      padding: new EdgeInsets.only(
                          left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
                      alignment: Alignment.centerLeft,
                      child: new Text(
                        mSubtitle ?? "",
                        style: Theme.of(context).primaryTextTheme.subhead,
                      ),
                    ),
                  ],
                ),
              ],
            )));
  }
/“作为呈现”以避免与“package:intl/intl.dart”冲突
导入“package:flatter/rendering.dart”作为渲染;
...
//这是返回文本小部件高度的函数
//给定文本
双getHeight(字符串文本、BuildContext上下文、bool-isTitle){
var rp=rendering.RenderParagraph(
新文本跨度(
款式:isTitle
?Theme.of(context).primaryTextTheme.title
:Theme.of(context.primaryTextTheme.subhead),
文本:文本,
children:null,
识别器:空),
//重要的是,用户可以在其设备上增加文本
textScaleFactor:MediaQuery.of(context).textScaleFactor,
textDirection:rendering.textDirection.ltr,
);
var horizontalPaddingSum=20;//可选
var width=MediaQuery.of(context).size.width-horizontalPaddingSum;
//如果文本小部件具有水平填充,则必须
//将其从可用宽度中减去以获得所需的结果
var ret=rp.computeMinIntrinsicHeight(宽度);
返回ret;
}
...
_kPreferredBBTextHeight=
getHeight(mTitle??”,上下文,true);
var verticalPaddingSum=10;
_kPreferredBBSubTextHeight=getHeight(mSubtitle??),上下文,false)+垂直填充;
_kPreferredBottomBarSize=
_kPreferredBBTextHeight+_kPreferredBBSubTextHeight+48;
_kFlexibleSpaceMaxHeight=
_kPreferredBottomBarSize+_kPreferredBottomBarSize+kToolbarHeight;
_BackgroundBottompAdding=\u kPreferredBottomBarSize;
...
新CustomSliverAppBar(
对,,
自动嵌入:false,
小学:对,
扩展高度:kFlexibleSpaceMaxHeight,
flexibleSpace:新的FlexibleSpaceBar(
背景:新的填充(
衬垫:
仅限新边缘集(底部:背景底部),
孩子:新形象(
图像:新网络图像(mImageUrl),
适合:BoxFit.cover,
)),
),
底部:新底部栏(
固定高度:\ kPreferredBottomBarSize,
),
),
...
类BottomBar扩展了无状态小部件实现PreferredSizeWidget{
最终双固定高度;
底部栏({this.fixedHeight});
@凌驾
大小获取首选大小{
返回新的Size.fromHeight(this.fixedHeight);
}
@凌驾
小部件构建(构建上下文){
// https://github.com/flutter/flutter/issues/3782
退回新货柜(
高度:此为固定高度,
儿童:新材料(
颜色:主题。背景。原色,
子:新列(
儿童:[
新行(
儿童:[
新图标按钮(
图标:新图标(Icons.arrow\u back,颜色:Colors.white),
已按下:(){
Navigator.of(context.pop();
},
),
新扩展(
子级:新容器(),
),
新图标按钮(
图标:新图标(Icons.share,颜色:Colors.white),
已按下:(){
印刷品(“按股份”);
},
)
],
),
新专栏(
mainAxisAlignment:mainAxisAlignment.space,
儿童:[
新填料(
填充:仅限新边集(左:10.0,右:10.0),
子容器:新容器(
子容器:新容器(
对齐:alignment.centerLeft,
儿童:新文本(
mTitle??“,
样式:Theme.of(context).primaryTextTheme.title,
),
),
)),
新容器(
填充:仅限新边设置(
左:10.0,右:10.0,顶部:5.0,底部:5.0),
对齐:alignment.centerLeft,
儿童:新文本(
mSubtitle??“,
样式:Theme.of(context).primaryTextTheme.subhead,
),
),
],
),
],
)));
}

PreferredSizeWidget
的全部要点是,您不能动态调整此小部件的大小

其背后的原因是
Scaffold
使用首选大小进行一些计算。如果在渲染之前appbar大小未知,这是不可能的

你必须相应地重新考虑你的用户界面

有没有一种方法可以在布局前测量小部件的高度

通常,在build()方法中构建UI时,可以使用LayoutBuilder,但在这种情况下,它可能对您没有帮助

在这里,您可以尝试RenderParagraph渲染文本,并在构建脚手架之前测量文本。您可以使用屏幕宽度作为宽度约束,布局RenderParagraph,检索高度,并将其用作首选大小

也就是说,你