如何限制可拖动滚动表根据其子高度在颤动中获取高度?
Posted
技术标签:
【中文标题】如何限制可拖动滚动表根据其子高度在颤动中获取高度?【英文标题】:How to limit draggable scrollable sheet to take height according to its child height in flutter? 【发布时间】:2020-06-03 09:27:05 【问题描述】:我正在使用draggableScrollableSheet
。我正在给这些参数
DraggableScrollableSheet(initialChildSize: 0.4,maxChildSize: 1,minChildSize: 0.4,builder: (BuildContext context, ScrollController scrollController)
return SingleChildScrollView(controller: scrollController,
child: Theme(
data: Theme.of(context).copyWith(canvasColor: Colors.transparent),
child: Opacity(
opacity: 1,
child: IntrinsicHeight(
child: Column(mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(height: 10,),
Container(
margin: EdgeInsets.only(right: 300),
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Colors.blue,
width: 3,
style: BorderStyle.solid),
),
),
),
Card(
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
S
.of(context)
.we_have_found_you_a_driver,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
Text(S
.of(context)
.driver_is_heading_towards +
' $widget.order.foodOrders.first.food.restaurant.name')
],
),
),
],
),
elevation: 5,
),
SizedBox(height: 10,),
Card(
elevation: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
CircleAvatar(
radius: 50.0,
backgroundColor: Colors.white,
child:
Image.asset(
'assets/img/image_not_available.jpg'),
),
Expanded(
child: Column(mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Row(mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
child: Text('Test',
textAlign: TextAlign.start,
style: new TextStyle(
color: Colors.black,
fontSize: 16.0,
)),
),
Icon(Icons.star, color: Colors.yellow.shade700,)
],
),
SizedBox(height: 30,),
Row(mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
child: Container(
child: Text('Mobile number',
textAlign: TextAlign.start,
style: new TextStyle(
color: Colors.black,
fontSize: 16.0,
)),
),
),
Icon(Icons.phone,),
SizedBox(width: 10,),
Icon(Icons.message),
],
),
],
),
)
]),
),
SizedBox(height: 10,),
Card(
child: Align( alignment: Alignment(-1,1),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
S
.of(context)
.you_ordered_from + ' $widget.order.foodOrders.first.food.restaurant.name',
style: TextStyle(
color: Colors.grey,
),
),
SizedBox(
height: 5,
),
Column(children: List.generate(widget.order.foodOrders.length,(index)
return Text(
'$widget.order.foodOrders[index].food.name'
);
,),),
Row(
children: <Widget>[
Column(crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('See details', style: TextStyle(fontWeight: FontWeight.bold,color: Colors.blue),),
],
),
],
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
SizedBox(height: 40,),
Row(
children: <Widget>[
Icon(Icons.monetization_on),
Text(widget.order.foodOrders
.first.price
.toString()),
],
),
],
),
),
],
),
),
elevation: 5,
),
],
),
),
),
),
)
我还使用了单个子滚动视图和列,以便我可以在 draggableScrollableSheet 的该列中显示我的卡片。但我希望 draggableScrollableSheet 动态获取高度而不是定义大小。就像现在我只想显示 2 到 3 张卡片,并且是全屏显示。但我希望它占据屏幕的最小高度。我们怎样才能做到这一点?
【问题讨论】:
如果你有答案,请分享! 【参考方案1】:我已经使用 Flutter 一周,但我找到了解决方案。如果我错了,可能不合格,所以请纠正我。
所以我所做的是为底部工作表创建一个名为bsRatio
的变量。这将是子视图/小部件(或底部工作表内容)的高度除以父/屏幕的高度。此比率应设置为 DraggableScrollableSheet 的 maxChildSize
甚至可能是 initialChildSize
。
因此,在您的父小部件或 Widget State 类中添加类似这样的内容。
class ParentWidget extends StatefulWidget
ParentWidget(Key? key) : super(key: key);
@override
State<ParentWidget> createState() => _ParentWidgetState();
class _ParentWidgetState extends State<ParentWidget>
var bsRatio = 0.4; // Set an initial ratio
@override
Widget build(BuildContext context)
// The line below is used to get status bar height. Might not be required if you are not using the SafeArea
final statusBarHeight = MediaQuery.of(context).viewPadding.top;
// If you are not using SafeArea Widget you can skip subtracting status bar height from the Window height
final windowHeight = MediaQuery.of(context).size.height - statusBarHeight;
// This below is a callback function that will be passed to the child Widget of the DraggableScrollableSheet ->
childHeightSetter(childHeight)
// setState rebuilds the UI with the new `bsRatio` value
setState(()
// The new bottom sheet max height ratio is the height of the Child View/Widget divide by the screen height
bsRatio = childHeight / windowHeight;
);
return Scaffold(
backgroundColor: Colors.black12,
body: SafeArea(
child: Stack(
children: [
const SomeBackgroundView(),
DraggableScrollableSheet(
initialChildSize: bsRatio, // here you set the newly calculated ratio as the initial height of the Bottom Sheet
minChildSize: 0.2,
maxChildSize: bsRatio, // here you set the newly calculated ratio as the initial height of the Bottom Sheet
snap: true,
builder: (_, controller)
return LayoutBuilder(builder: (_, box)
// Added a container here to add some curved borders and decent looking shadows via the decoration property
return Container(
child: SingleChildScrollView(
controller: controller,
// The child view/widget `MyBottomSheet` below is the actual bottom sheet view/widget
child: MyBottomSheet(childHeightSetter: childHeightSetter),
),
decoration: const BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 5.0,
spreadRadius: 2.0
)
],
borderRadius: BorderRadius.all(Radius.circular(20.0))
),
);
);
,
),
],
),
),
);
这将是您的子视图/小部件(也是您的 BottomSheet 视图/小部件)
class MyBottomSheet extends StatefulWidget
// This below is the local callback variable. The `?` is because it may not be set if not required
final ValueSetter<double>? childHeightSetter;
const MyBottomSheet(Key? key, this.childHeightSetter) : super(key: key);
@override
_MyBottomSheetState createState() => _MyBottomSheetState();
class _LoginBottomSheetState extends State<LoginBottomSheet>
// bsKey is the key used to reference the Child widget we are trying to calculate the height of. Check the `Card` container below
GlobalKey bsKey = GlobalKey();
// this method will me used to get the height of the child content and passed to the callback function so it can be triggered and the ratio can be calculated and set in the parent widget
_getSizes()
final RenderBox? renderBoxRed =
bsKey.currentContext?.findRenderObject() as RenderBox?;
final cardHeight = renderBoxRed?.size.height;
if (cardHeight != null)
super.widget.childHeightSetter?.call(cardHeight);
// This is the function to be called after the Child has been drawn
_afterLayout(_)
_getSizes();
@override
void initState()
super.initState();
// On initialising state pass the _afterLayout method as a callback to trigger after the child Widget is drawn
WidgetsBinding.instance?.addPostFrameCallback(_afterLayout);
@override
Widget build(BuildContext context)
return Card(
key: bsKey, // This is the key mentioned above used to calculate it's height
color: Colors.white,
shadowColor: Colors.black,
elevation: 40.0,
margin: EdgeInsets.zero,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0))),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// Random children for bottom sheet content
const SizedBox(height: 10.0),
Center(
child: Container(
child: const SizedBox(width: 40.0, height: 5.0),
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(5.0)
),
),
),
const SizedBox(height: 10.0),
const AnotherBottomSheetContentView()
],
),
);
【讨论】:
【参考方案2】:initialChildSize 是 ScrollView 在实际滚动之前的高度,这意味着您实际上可以决定它的外观。 这是一个例子![the draggable scrollsheet here has initialChildSize: 0.1,maxChildSize: 1,minChildSize: 0.1, ]1
【讨论】:
您如何为 draggablescrollablesheet 指定高度。就像在你的情况下,如果我添加另一个 textformfield 然后布局会动态调整自己,或者我们必须静态设置高度? im 使用 SingleChildScrollView 和 Column ,列主轴大小设置为最小,这意味着您的列大小相对于您的孩子会增长 我刚刚重新编辑了我的问题。现在我还在我的问题中包含了代码。我也给了柱子的最小高度。你能看看我哪里做错了吗? 子卡列未设置为最小值 糟糕的答案。没有例子以上是关于如何限制可拖动滚动表根据其子高度在颤动中获取高度?的主要内容,如果未能解决你的问题,请参考以下文章