如何根据其内容动态设置 DraggableScrollableSheet 最大尺寸?
问题
所以基本上这是一个相当老的问题,我无法通过谷歌解决。问题是 DraggableScrollableSheet
不会根据其内容大小来调整其最大大小,而只有一个静态值 maxChildSize
,如果您不这样做,那就不好了想要查看工作表中的大量空白区域。
有什么解决办法吗?
有谁知道一些根据其内容大小设置 DragabbleScrollableSheet maxChildSize
的技巧或提供任何替代方案来解决此问题?
测试项目
我创建了一个小应用程序只是为了演示该问题。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (_) => DraggableScrollableSheet(
initialChildSize: 0.8,
minChildSize: 0.3,
maxChildSize: 0.8,
expand: false,
builder: (_, controller) =>
ListView(
shrinkWrap: true,
controller: controller,
children: <Widget>[
Container(
color: Colors.red,
height: 125.0
),
Container(
color: Colors.white,
height: 125.0
),
Container(
color: Colors.green,
height: 125.0
),
],
)
)
),
child: const Text("Show scrollable sheet"),
),
],
),
),
);
}
}
- 我尝试使用 GlobalKey 来获取 Listview 的大小,我认为这是不可能的,因为它有问题而且速度很慢。
- 我也尝试过 LayoutBuilder,但没有产生严重的结果。
Problem
So basically it's quite an old problem, which I couldn't fix with Google. The problem is that DraggableScrollableSheet
doesn't size its maximum size based on its content size, but with only a static value maxChildSize
, which is just not good if you don't want to look at a lot of empty spaces in your sheet.
Any Solution?
Does anyone know some hack to set DragabbleScrollableSheet maxChildSize
based on its content size or give any alternatives to solve this issue?
Test project
I created a small application just for demonstrating the issue.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (_) => DraggableScrollableSheet(
initialChildSize: 0.8,
minChildSize: 0.3,
maxChildSize: 0.8,
expand: false,
builder: (_, controller) =>
ListView(
shrinkWrap: true,
controller: controller,
children: <Widget>[
Container(
color: Colors.red,
height: 125.0
),
Container(
color: Colors.white,
height: 125.0
),
Container(
color: Colors.green,
height: 125.0
),
],
)
)
),
child: const Text("Show scrollable sheet"),
),
],
),
),
);
}
}
- I tried with GlobalKey to get the size of Listview, which I don't think is possible, because it's just buggy and slow.
- I also tried LayoutBuilder, but with no serious results.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(3)
我可能有一个解决方案。我在 SingleChildListView
和 MeasureSize
小部件中使用了 Column
来自 此处获取列的高度。列渲染后,获取列的大小,并相应调整 DragabbleScrollableSheet 的最大高度。初始工作表高度设置为 0,并且使用draggableScrollController 可以在渲染列后将动画设置为 _maxSize。
解决方案
class BottomSheet extends StatefulWidget {
const BottomSheet({required this.children, Key? key}) : super(key: key);
List<Widget> children;
@override
State<BottomSheet> createState() => _BottomSheetState();
}
class _BottomSheetState extends State<BottomSheet> {
DraggableScrollableController draggableScrollController = DraggableScrollableController();
double _maxSize = 1;
void _setMaxChildSize(Size size) {
setState(() {
// get height of the container.
double boxHeight = size.height;
// get height of the screen from mediaQuery.
double screenHeight = MediaQuery.of(context).size.height;
// get the ratio to set as max size.
double ratio = boxHeight/screenHeight;
_maxSize = ratio;
_animateToMaxHeight(ratio);
});
}
void _animateToMaxHeight(double ratio) {
draggableScrollController.animateTo(ratio, duration: Duration(seconds: 1), curve: Curves.linear);
}
@override
Widget build(BuildContext context) {
return DraggableScrollableSheet(
controller: draggableScrollController,
initialChildSize: 0,
minChildSize: 0.3,
maxChildSize: _maxSize,
expand: false,
builder: (_, scrollController) =>
SingleChildScrollView(
controller: scrollController,
child: MeasureSize(
onChange: _setMaxChildSize,
child: Column(
children: widget.children;
),
),
),
);
}
}
测量尺寸
为了完整起见,我还在此处提供了测量尺寸小部件。
class MeasureSize extends SingleChildRenderObjectWidget {
final OnWidgetSizeChange onChange;
const MeasureSize({
Key? key,
required this.onChange,
required Widget child,
}) : super(key: key, child: child);
@override
RenderObject createRenderObject(BuildContext context) {
return MeasureSizeRenderObject(onChange);
}
@override
void updateRenderObject(
BuildContext context, covariant MeasureSizeRenderObject renderObject) {
renderObject.onChange = onChange;
}
}
背景:
在 flutter 中获取(子)widget 的高度并不容易,只能在 widget 渲染后才能完成。
直接使用全局键获取 ListView
的大小似乎以某种方式返回 0。(我尝试过使用全局键并获取渲染框。)因此我使用单个 SingleChildScrollView
以 Column
作为子项。这样就可以获取 Column
的大小,但只能在呈现 Column
的布局之后才能获取。
将控制器定义为 DraggableScrollableSheet
var dragController = DraggableScrollableController();
然后你可以像这样使用它:
DraggableScrollableSheet(
controller: controller.dragController,
initialChildSize: 0.25,
minChildSize: 0.25,
maxChildSize: 1,
/** Your code Here **/
],
),
现在你可以获取 DraggableScrollableSheet 的大小dragController.size
从 0 到 1
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我意识到问题是你无法在 DraggableScrollableSheet 中正确测量 ListView 大小,所以我想出了一个想法,也许我应该在其他地方测量 ListView 。
这是我想出的办法,虽然效率很低,但目前总比没有好。我也想知道更好的解决方案。
更新:
如果您的内容大小发生变化,您仍然希望解决该问题。因此,您必须在构建期间或构建之后测量大小,并在构建中提供 PostFrameCallback 以显示正确大小的 DraggableScrollableSheet。所以最终你的代码将如下所示:
I realized the problem is that you cannot measure the ListView size correctly in DraggableScrollableSheet, so I came up with an idea, that maybe I should measure the ListView somewhere else.
This is what I've come up with, it's quite inefficient, but it's better than nothing for now. I would also like to know a better solution though.
Update:
You still want to work around the problem if your content size changes. For this reason you have to measure size during build or after build and provide PostFrameCallback in build to show the correct sized DraggableScrollableSheet. So eventually your code would look like this: