Flutter监控滚动控制和实际appBar滚动渐变
Flutter中的滚动监控一般可以通过两种方式实现,即ScrollController
和NotificationListener
。
ScrollController介绍
scrollController
介绍ScrollController
的常用属性和方法:
offset
:可滚动组件当前的滚动位置。jumpTo(双偏移)
跳转到指定位置,offset
为滚动偏移。animateTo(double offset,duration,curvecurve)
与jumpTo(double offset)
相同,不同之处在于animateTo
在跳跃时执行动画,您必须运行执行动画所需的时间和动画曲线。
ScrollPosition
ScrollPosition 用于存储可滚动组件的滚动位置。 ScrollController 对象可由多个可滚动组件使用。
ScrollController 为每个滚动组件创建一个 ScrollPosition 对象来存储位置信息。 ScrollPosition 存储在 ScrollController 的定位属性中。它是一个 List
数组。 ScrollPosition 是 ScrollController 中实际存储位置信息的地方,而 offset 只是一个有用的属性。如果你查看源代码,你会发现偏移量是从 ScrollPosition 获取的。
/// Returns the attached [ScrollPosition], from which the actual scroll offset
/// of the [ScrollView] can be obtained.
/// Calling this is only valid when only a single position is attached.
ScrollPosition get position {
assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.');
assert(_positions.length == 1, 'ScrollController attached to multiple scroll views.');
return _positions.single;
}
/// The current scroll offset of the scrollable widget.
/// Requires the controller to be controlling exactly one scrollable widget.
double get offset => position.pixels;
复制代码
A ScrollController
虽然可以对应多个可滚动组件,但读取滚动位置需要offset
一对一读取。在一对多的情况下,我们可以使用其他方法来读取滚动位置。现在假设一个 ScrollController
对应两个可滚动组件,那么可以通过 position.elementAt(index)
得到 ScrollPosition
,从而得到 补偿
:
controller.positions.elementAt(0).pixels
controller.positions.elementAt(1).pixels
复制代码
ScrollPosition方法
ScrollPosition
常用的方法有两种:animateTo()
和jumpTo()
,他们才是真正的掌控者有 about 跳转到滑块位置的方法。 ScrollController中这两个同名的方法最终会在内部调用ScrollPosition的两个方法。
Future<void> animateTo(
double offset, {
@required Duration duration,
@required Curve curve,
}) {
assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.');
final List<Future<void>> animations = List<Future<void>>(_positions.length);
for (int i = 0; i < _positions.length; i += 1)
// 调用 ScrollPosition 中的 animateTo 方法
animations[i] = _positions[i].animateTo(offset, duration: duration, curve: curve);
return Future.wait<void>(animations).then<void>((List<void> _) => null);
}
复制代码
ScrollController 控制原理
ScrollController
还有三个重要的方法:
createScrollPosition
:当ScrollController
如果与可滚动组件关联时,首先是可滚动组件 The调用方法ScrollController的createScrollPosition
来创建一个ScrollPosition
来存储滚动位置信息。
ScrollPosition createScrollPosition(
ScrollPhysics physics,
ScrollContext context,
ScrollPosition oldPosition);
复制代码
- 滚动组件调用
createScrollPosition
方法后,调用attach
方法获取要添加的创建编号的ScrollPosition
信息位置
在属性中,这一步称为“注册位置”。注册后才能调用animateTo()
和jumpTo()
。
void attach(ScrollPosition position);
复制代码
- 最后,当可滚动组件被销毁时,会调用方法
detach()
,从ScrollController
转移对象ScrollPosition
位置
从属性中删除。此步骤称为“注销位置”。退出后,animateTo()
和jumpTo()
不再被调用。
void detach(ScrollPosition position);
复制代码
介绍NotificationListener
气泡通知
Flutter Widget 树中的子 Widget 可以通过发送通知(Notification)与父 Widget(包括祖先 Widget)进行通信,父组件可以通过NotificationListener
用于监听其关心的通知的组件。这种通信方式类似于Web开发中的浏览器冒泡。 Flutter 中使用术语“冒泡”,称为 通知气泡
通知气泡 气泡与用户触摸事件气泡类似,但有一个区别:通知气泡可以中止,但用户触摸事件气泡则不能。
u Flutter 使用通知中很多地方的持续通知,比如scrollble widgets,分发 滚动通知(ScrollNotification)和 其中, ScrollUpdateNotification都继承自类 目前, 首先,两种方法都可以控制滚动,但还是有一些区别: 有关完整代码,请参阅下面 GitHub 项目中的文件 完整代码请参见下面 GitHub 项目中的文件 作者:小风臧月ScrollLLL
通过监听来确定滚动条的位置 滚动通知
。 switch (notification.runtimeType){
case ScrollStartNotification: print("开始滚动"); break;
case ScrollUpdateNotification: print("正在滚动"); break;
case ScrollEndNotification: print("滚动停止"); break;
case OverscrollNotification: print("滚动到边界"); break;
}
复制代码
ScrollStartNotification
和 _controller.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.ease);
复制代码
ScrollNotification
。不同类型的通知子类将包含不同的信息。 ScrollUpdateNotification
有属性scrollDelta
,记录了移动的情况。当NotificationListener
继承了StatelessWidget
类时,我们可以直接将其放在widget编号中,并通过其中的onNotification
指定一个模板参数。该类型必须取自通知
。例如,当可以显式指定模板参数时,通知类型为滚动结束通知: NotificationListener<ScrollEndNotification>
复制代码
NotificationListener
仅接收此参数类型。通知。onNotification
回调是通知处理回调,返回值为布尔类型(bool)。当返回值为true
时,阻止冒泡,父Widget无法再收集。关于通知;当返回值为false
时,消息不断冒泡。 两者的区别
ScrollController
可以控制滚动控件的滚动,而NotificationListener
是不允许的。 NotificationListener
,您可以侦听从可滚动组件到小部件树根的任何位置,而ScrollController
只能与特定的可滚动组件关联。 NotificationListener
收到滚动事件后,通知会包含一些有关当前滚动位置和ViewPort的信息,而ScrollController
只能获取当前滚动位置。 ScrollController实例
渲染
代码实现步骤
Scaffolding
组件body
A 内 堆叠
的级联小部件,其中放置了 列表视图
和自定义 appBar
; floatingActionButton
放置一个浮动按钮以返回顶部。Scaffold(
body: Stack(
children: <Widget>[
MediaQuery.removePadding(
removeTop: true,
context: context,
child: ListView.builder(
// ScrollController 关联滚动组件
controller: _controller,
itemCount: 100,
itemBuilder: (context, index) {
if (index == 0) {
return Container(
height: 200,
child: Swiper(
itemBuilder: (BuildContext context, int index) {
return new Image.network(
"http://via.placeholder.com/350x150",
fit: BoxFit.fill,
);
},
itemCount: 3,
autoplay: true,
pagination: new SwiperPagination(),
),
);
}
return ListTile(
title: Text("ListTile:$index"),
);
},
),
),
Opacity(
opacity: toolbarOpacity,
child: Container(
height: 98,
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Center(
child: Text(
"ScrollerDemo",
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
),
),
),
)
],
),
floatingActionButton: !showToTopBtn
? null
: FloatingActionButton(
child: Icon(Icons.keyboard_arrow_up),
onPressed: () {
_controller.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.ease);
},
),
)
复制代码
scrollController
对象,初始化时添加对滚动的监听,并关联到ListView
可滚动小部件:ScrollController _controller = new ScrollController();
@override
void initState() {
_controller.addListener(() {
print(_controller.offset); //打印滚动位置
})
}
复制代码
double t = _controller.offset / DEFAULT_SCROLLER;
if (t < 0.0) {
t = 0.0;
} else if (t > 1.0) {
t = 1.0;
}
setState(() {
toolbarOpacity = t;
});
复制代码
floatingActionButton
的实际状态,并确定floatingActionButton
是否必须显示。 :if(_controller.offset < DEFAULT_SHOW_TOP_BTN && showToTopBtn){
setState(() {
showToTopBtn = false;
});
}else if(_controller.offset >= DEFAULT_SHOW_TOP_BTN && !showToTopBtn){
setState(() {
showToTopBtn = true;
});
}
复制代码
floatingActionButton
返回顶部: _controller.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.ease);
复制代码
/demo/scroller_demo.dart
。 ?偏移量:if (notification is ScrollUpdateNotification && notification.depth == 0) {
double t = notification.metrics.pixels / DEFAULT_SCROLLER;
if (t < 0.0) {
t = 0.0;
} else if (t > 1.0) {
t = 1.0;
}
setState(() {
toolbarOpacity = t;
});
print(notification.metrics.pixels); //打印滚动位置
}
复制代码
/demo/notification_listener_demo.dart
。
链接:https://juejin.im/post/5d8f0ad6e51d45780f0604c8
来源:掘金
版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明出处。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。