在 Flutter 中使用 PageView 的 viewportFraction 属性时,将未左对齐的内容居中对齐的解决方案。
最编程
2024-05-06 11:26:58
...
问题描述
要做一个 类似 Swiper 一样,内容可以根据手势左右滑动的效果,于是想到了用 PageView 去实现,PageView 默认是占满整个内容区域的,如果想让两块内容显示在一屏内,就需要设置 viewportFraction 属性,这时候问题来了,设置了 viewportFraction 后,内容区域默认会居中显示,没有属性能够让区域左对齐!!!。
最终参考了一哥们的解决方案:使用自定义 CustomPageView Pageview aligned left @flutter · GitHub
使用方式
1:在项目中新建 custom_page_view.dart 文件
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class CustomPageView extends StatefulWidget {
CustomPageView({
Key key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
List<Widget> children = const <Widget>[],
this.dragStartBehavior = DragStartBehavior.start,
this.allowImplicitScrolling = false,
this.restorationId,
@required this.viewportDirection,
}) : assert(allowImplicitScrolling != null),
controller = controller ?? _defaultPageController,
childrenDelegate = SliverChildListDelegate(children),
super(key: key);
CustomPageView.builder({
Key key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
this.dragStartBehavior = DragStartBehavior.start,
this.allowImplicitScrolling = false,
this.restorationId,
@required this.viewportDirection,
}) : assert(allowImplicitScrolling != null),
controller = controller ?? _defaultPageController,
childrenDelegate =
SliverChildBuilderDelegate(itemBuilder, childCount: itemCount),
super(key: key);
CustomPageView.custom({
Key key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PageController controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
@required this.childrenDelegate,
this.dragStartBehavior = DragStartBehavior.start,
this.allowImplicitScrolling = false,
this.restorationId,
@required this.viewportDirection,
}) : assert(childrenDelegate != null),
assert(allowImplicitScrolling != null),
controller = controller ?? _defaultPageController,
super(key: key);
final bool allowImplicitScrolling;
final String restorationId;
final Axis scrollDirection;
final bool reverse;
final viewportDirection;
final PageController controller;
final ScrollPhysics physics;
final bool pageSnapping;
final ValueChanged<int> onPageChanged;
final SliverChildDelegate childrenDelegate;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
@override
_CustomPageViewState createState() => _CustomPageViewState();
}
class _CustomPageViewState extends State<CustomPageView> {
int _lastReportedPage = 0;
@override
void initState() {
super.initState();
_lastReportedPage = widget.controller.initialPage;
}
AxisDirection _getDirection(BuildContext context) {
switch (widget.scrollDirection) {
case Axis.horizontal:
assert(debugCheckHasDirectionality(context));
final TextDirection textDirection = Directionality.of(context);
final AxisDirection axisDirection =
textDirectionToAxisDirection(textDirection);
return widget.reverse
? flipAxisDirection(axisDirection)
: axisDirection;
case Axis.vertical:
return widget.reverse ? AxisDirection.up : AxisDirection.down;
}
return null;
}
@override
Widget build(BuildContext context) {
final AxisDirection axisDirection = _getDirection(context);
final ScrollPhysics physics = _ForceImplicitScrollPhysics(
allowImplicitScrolling: widget.allowImplicitScrolling,
).applyTo(widget.pageSnapping
? _kPagePhysics.applyTo(widget.physics)
: widget.physics);
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification.depth == 0 &&
widget.onPageChanged != null &&
notification is ScrollUpdateNotification) {
final PageMetrics metrics = notification.metrics as PageMetrics;
final int currentPage = metrics.page.round();
if (currentPage != _lastReportedPage) {
_lastReportedPage = currentPage;
widget.onPageChanged(currentPage);
}
}
return false;
},
child: Scrollable(
dragStartBehavior: widget.dragStartBehavior,
axisDirection: axisDirection,
controller: widget.controller,
physics: physics,
restorationId: widget.restorationId,
viewportBuilder: (BuildContext context, ViewportOffset position) {
return Viewport(
cacheExtent: widget.allowImplicitScrolling ? 1.0 : 0.0,
cacheExtentStyle: CacheExtentStyle.viewport,
axisDirection: axisDirection,
offset: position,
slivers: <Widget>[
SliverFillViewport(
viewportFraction: widget.controller.viewportFraction,
delegate: widget.childrenDelegate,
padEnds: widget.viewportDirection,
),
],
);
},
),
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
description
.add(EnumProperty<Axis>('scrollDirection', widget.scrollDirection));
description.add(
FlagProperty('reverse', value: widget.reverse, ifTrue: 'reversed'));
description.add(DiagnosticsProperty<PageController>(
'controller', widget.controller,
showName: false));
description.add(DiagnosticsProperty<ScrollPhysics>(
'physics', widget.physics,
showName: false));
description.add(FlagProperty('pageSnapping',
value: widget.pageSnapping, ifFalse: 'snapping disabled'));
description.add(FlagProperty('allowImplicitScrolling',
value: widget.allowImplicitScrolling,
ifTrue: 'allow implicit scrolling'));
}
}
final PageController _defaultPageController = PageController();
const PageScrollPhysics _kPagePhysics = PageScrollPhysics();
class _ForceImplicitScrollPhysics extends ScrollPhysics {
const _ForceImplicitScrollPhysics({
@required this.allowImplicitScrolling,
ScrollPhysics parent,
}) : assert(allowImplicitScrolling != null),
super(parent: parent);
@override
_ForceImplicitScrollPhysics applyTo(ScrollPhysics ancestor) {
return _ForceImplicitScrollPhysics(
allowImplicitScrolling: allowImplicitScrolling,
parent: buildParent(ancestor),
);
}
@override
final bool allowImplicitScrolling;
}
2:将原来的 PageView 改成 CustomPageView
CustomPageView(
viewportDirection: false, // 关键在于这个属性,加上即可
controller: PageController(viewportFraction: 0.8),
children: [
Container(color: Colors.red),
Container(color: Colors.blue),
Container(color: Colors.green),
Container(color: Colors.white),
])
运行效果
相关issue
Left Aligned ViewPort in Page View · Issue #52014 · flutter/flutter · GitHub
上一篇: 48 竹林风--正史文学与阮籍简介
下一篇: 和谐之美--《红楼梦》中的对联