我正在尝试创建高度可变的项目的轮播。将PageView或ListView与水平滚动一起使用时,我需要给它一个恒定的高度,如下所示:
class CarouselVariableHightState extends State<CarouselVariableHight> {
double height = 200;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Carousel')),
body: ListView(
children: <Widget>[
Text('My Carousel'),
Container(
height: height,
child: PageView(
children: <Widget>[
_buildCarouselItem(),
_buildCarouselItem(),
_buildCarouselItem(),
_buildCarouselItem(),
],
),
),
Text('end of List')
],
),
);
}
Widget _buildCarouselItem() {
return Column(
children: [
Container(
color: Colors.red,
height: Random().nextInt(200).toDouble(),
child: Text('Text with random length')
)
]
);
}
}
Run Code Online (Sandbox Code Playgroud)
但是我的物品包含文字,我不知道它的长度。我不想限制CarouselItem的高度,因为它可能会截断文本。我该如何使用PageView之类的东西,根据当前显示的项目调整其自身尺寸?
我认为解决方案可能是获取CarouselItem的高度,然后将其设置为PageView的高度。但是我想不出一种方法来增加我当前的轮播项目的高度。
有任何想法吗?
And*_*ski 28
您可以在下面找到一个 PageView 的示例,该示例将其高度调整为当前显示的子项。带动画:
这个想法是:
SizeReportingWidget。_heights在与子项索引对应的索引上调用。_currentPagePageView在 a 中SizedBox并为其指定当前显示的孩子的高度。我添加了一个方便的 getter 调用_currentHeight来检索高度。SizedBoxin包裹起来TweenAnimationBuilder,使高度变化平滑且具有动画效果,而不是笨拙的跳跃。ExpandablePageViewclass ExpandablePageView extends StatefulWidget {
final List<Widget> children;
const ExpandablePageView({
Key key,
@required this.children,
}) : super(key: key);
@override
_ExpandablePageViewState createState() => _ExpandablePageViewState();
}
class _ExpandablePageViewState extends State<ExpandablePageView> with TickerProviderStateMixin {
PageController _pageController;
List<double> _heights;
int _currentPage = 0;
double get _currentHeight => _heights[_currentPage];
@override
void initState() {
_heights = widget.children.map((e) => 0.0).toList();
super.initState();
_pageController = PageController() //
..addListener(() {
final _newPage = _pageController.page.round();
if (_currentPage != _newPage) {
setState(() => _currentPage = _newPage);
}
});
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TweenAnimationBuilder<double>(
curve: Curves.easeInOutCubic,
duration: const Duration(milliseconds: 100),
tween: Tween<double>(begin: _heights[0], end: _currentHeight),
builder: (context, value, child) => SizedBox(height: value, child: child),
child: PageView(
controller: _pageController,
children: _sizeReportingChildren
.asMap() //
.map((index, child) => MapEntry(index, child))
.values
.toList(),
),
);
}
List<Widget> get _sizeReportingChildren => widget.children
.asMap() //
.map(
(index, child) => MapEntry(
index,
OverflowBox(
//needed, so that parent won't impose its constraints on the children, thus skewing the measurement results.
minHeight: 0,
maxHeight: double.infinity,
alignment: Alignment.topCenter,
child: SizeReportingWidget(
onSizeChange: (size) => setState(() => _heights[index] = size?.height ?? 0),
child: Align(child: child),
),
),
),
)
.values
.toList();
}
Run Code Online (Sandbox Code Playgroud)
SizeReportingWidgetclass SizeReportingWidget extends StatefulWidget {
final Widget child;
final ValueChanged<Size> onSizeChange;
const SizeReportingWidget({
Key key,
@required this.child,
@required this.onSizeChange,
}) : super(key: key);
@override
_SizeReportingWidgetState createState() => _SizeReportingWidgetState();
}
class _SizeReportingWidgetState extends State<SizeReportingWidget> {
Size _oldSize;
@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) => _notifySize());
return widget.child;
}
void _notifySize() {
if (!this.mounted) {
return;
}
final size = context?.size;
if (_oldSize != size) {
_oldSize = size;
widget.onSizeChange(size);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Khe*_*rel 11
有两种可能的解决方案:正确的一种和hacky的一种。
正确的解决方案:因为 PageView 试图获得所有可能的高度,所以我们不能在任何没有高度的小部件中使用它。所以如果我们没有高度,我们需要使用另一个小部件,例如 StackWidget 并重新创建 PageView 行为:滑动、动画等。它不会是一个大库,如果你只想制作简单的东西,小于我猜是 200-300 行。
hacky 解决方案是在构建 PageView 小部件之前检查所有元素的高度。构建 PageView 时不能更改元素的高度。因此,如果您需要在渲染轮播之前创建服务器请求。
要获得高度,使用 IndexedStack 更容易,因为它具有最高元素的高度,但仅显示第一个(默认情况下)。
class CarouselVariableHight extends StatefulWidget {
@override
CarouselVariableHightState createState() => CarouselVariableHightState();
}
final widgetHeights = <double>[
Random().nextInt(300).toDouble(),
Random().nextInt(300).toDouble(),
Random().nextInt(300).toDouble(),
Random().nextInt(300).toDouble(),
];
class CarouselVariableHightState extends State<CarouselVariableHight> {
double height;
GlobalKey stackKey = GlobalKey();
bool widgetHasHeigh;
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
super.initState();
}
_afterLayout(_) {
final RenderBox renderBoxRed = stackKey.currentContext.findRenderObject();
final sizeRed = renderBoxRed.size;
setState(() {
height = sizeRed.height;
});
}
final caruselItems = widgetHeights
.map((height) => Column(children: [
Container(
color: Colors.red,
height: Random().nextInt(300).toDouble(),
child: Text('Text with random length'))
]))
.toList();
_buildStack() {
Widget firstElement;
if (height == null) {
firstElement = Container();
} else {
firstElement = Container(
height: height,
child: PageView(
children: caruselItems,
),
);
}
return IndexedStack(
key: stackKey,
children: <Widget>[
firstElement,
...caruselItems,
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Carousel')),
body: ListView(
children: <Widget>[
Text('My Carousel'),
_buildStack(),
Text('end of List'),
],
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
743 次 |
| 最近记录: |