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);
}
...
}
我想在这个底部Widget中放置一个Text,我不知道它里面的文本会有多长。
如何实现底部小部件的动态高度?
有没有办法在小工具布局之前测量小工具的高度?
编辑25/04/2018
最后,我按照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,
),
),
],
),
],
)));
}
答案 0 :(得分:2)
PreferredSizeWidget
的重点是否,您无法动态调整此小部件的大小。
背后的原因是Scaffold
使用该首选大小来进行一些计算。如果在渲染之前appbar尺寸未知,那将是不可能的。
您必须相应地重新考虑您的用户界面。
答案 1 :(得分:2)
有没有办法在小工具布局之前测量小工具的高度?
通常,您可以在build()方法中构建UI时使用LayoutBuilder,但在这种情况下它可能无法帮助您。
在这里,您可以尝试使用RenderParagraph渲染文本并在构建Scaffold之前对其进行测量。您可以使用屏幕宽度作为宽度约束,布局RenderParagraph,检索高度,并将其用作首选大小。
也就是说,如果你的文字在你的脚手架的生命周期中发生变化,你将无法在以后更改首选高度。
答案 2 :(得分:0)
我使用以下代码解决此问题。
toolbarHeight
是文本高度(动态)。
注意:此页面呈现两次。
var toolbarHeight;
BuildContext? renderBoxContext;
@override
void initState() {
super.initState();
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
var renderBox = renderBoxContext?.findRenderObject() as RenderBox;
toolbarHeight = renderBox.size.height;
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Material(
child: getBody(context),
);
}
getBody(BuildContext context) {
var mediaQuery = MediaQuery.of(context).size;
state.toolbarHeight ??= mediaQuery.height;
return SizedBox(
width: mediaQuery.width,
height: mediaQuery.height,
child: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: false,
floating: true,
snap: false,
backwardsCompatibility: true,
centerTitle: true,
bottom: PreferredSize(
preferredSize: Size(mediaQuery.width, state.toolbarHeight),
child: Builder(
builder: (ctx){
state.renderBoxContext = ctx;
return Align(
alignment: Alignment.topLeft,
child: ColoredBox(
color: Colors.green,
child: Text('line1\nline2\nline3'),
),
);
},
),
),
flexibleSpace: FlexibleSpaceBar(
title: Text('FlexibleSpaceBar'),
centerTitle: true,
collapseMode: CollapseMode.pin,
),
),
SliverPadding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
sliver: SliverFixedExtentList(
itemExtent: 110,
delegate: SliverChildBuilderDelegate(
(context, index) {
return Text(' item $index');
},
childCount: 10,
),
),
),
],
),
);
}