一、滑动监听
在flutter 中滑动监听的一般实现方式有两种:分别是ScrollerController和NotificationListener。
二、ScrollerController
- offset : 可滚动组件的当前的滑动偏移量;
- jumpTo(double offset)跳转到指定位置;
- animateTo(double offset,@required Duration duration,@required Curve curve) 动画式跳转到指定位置;
三、NotificationListener(通知冒泡)
Flutter中子组件与父组件之间的通信可以通过发送通知来完成(Notification,父组件通过NotificationListener组件来监听自己关注的通知,这一方式就是通知冒泡。
NotificationListener常用的属性和方法:
- onNotification 通知处理回调,返回值类型为bool型,返回值为true时会组织冒泡,父级将再也收不到该通知;返回值为false时继续向上冒泡通知。
四、两者区别
首先这两种方式都可以实现对滚动的监听,但是他们还是有一些区别:
- ScrollController可以控制滚动控件的滚动,而NotificationListener是不可以的。
- 通过NotificationListener可以在从可滚动组件到widget树根之间任意位置都能监听,而ScrollController只能和具体的可滚动组件关联后才可以。
- 收到滚动事件后获得的信息不同;NotificationListener在收到滚动事件时,通知中会携带当前滚动位置和ViewPort的一些信息,而ScrollController只能获取当前滚动位置。
五、应用(实现AppBar滑动渐变)
以NotificationListener为例,整体思路是:监听页面滑动距离,使用透明度组件覆盖在appbar之上,使之透明度随滑动距离等比例增大,从而实现滑动渐变效果。封装后的组件代码如下:
const APPBAR_SCROLL_OFFSET = 100;
class SlideGradientAppBar extends StatefulWidget {
final Widget body; //滑动主体
final String title; //主标题
final bool isTabTitle; //是否为tabbar
final List<String> tabTitles; //tabbar标题列表
final TabController tabController; //tabbar的controller列表
SlideGradientAppBar(
{this.body,
this.title,
this.isTabTitle = false,
this.tabTitles,
this.tabController});
@override
State<StatefulWidget> createState() {
return _SlideGradientAppBar();
}
}
class _SlideGradientAppBar extends State<SlideGradientAppBar> {
double appBarAlpha = 0; //appbar透明度
//滑动渐变透明度变化算法
_onScroll(offset) {
double alpha = offset / APPBAR_SCROLL_OFFSET;
if (alpha < 0) {
alpha = 0;
} else if (alpha > 1) {
alpha = 1;
}
setState(() {
appBarAlpha = alpha;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
StatusBar(
child: Container(
height: 0,
),
brightness: appBarAlpha == 0 ? Brightness.light : Brightness.dark,
),
NotificationListener(
// ignore: missing_return
onNotification: (scrollNotification) {
if (scrollNotification is ScrollUpdateNotification &&
scrollNotification.depth == 0) {
_onScroll(scrollNotification.metrics.pixels);
}
},
child: widget.body),
Opacity(
opacity: appBarAlpha,
child: Container(
width: screenWidth,
height: statusBarHeight + 40.px,
decoration:
BoxDecoration(color: Colors.white, boxShadow: <BoxShadow>[
new BoxShadow(
color: const Color(0xffE5E9F0),
offset: new Offset(0.0, 1.0),
blurRadius: 16.0,
),
]),
),
),
Container(
height: 40.px,
margin: EdgeInsets.only(top: statusBarHeight),
child: Row(
mainAxisAlignment: widget.isTabTitle?MainAxisAlignment.start:MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pop();
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 15.px, vertical: 10.px),
child: Image(
image: AssetImage(
appBarAlpha == 0
? AssetConstant.back_white_2x
: AssetConstant.back_black_2x,
),
width: 10.px,
height: 18.px,
),
)),
widget.isTabTitle
? Container(
width: 80.px*widget.tabTitles.length,
alignment: Alignment.centerLeft,
child: TabBar(
labelPadding: EdgeInsets.symmetric(horizontal: 0),
indicator: const BoxDecoration(),
labelColor: Colors.white,
unselectedLabelColor: Color(0xFF8EBFFF),
labelStyle: TextStyle(fontSize: 18.px),
unselectedLabelStyle: TextStyle(fontSize: 15.px),
controller: widget.tabController,
tabs: widget.tabTitles
.map((e) => Text(
e,
style: TextStyle(
decoration: TextDecoration.none,
fontWeight: FontWeight.w600,
color: appBarAlpha == 0
? Colors.white
: Color(0xff333333)),
))
.toList()),
)
: Expanded(
child: Container(
alignment: Alignment.center,
child: Text(
widget.title,
style: TextStyle(
decoration: TextDecoration.none,
fontSize: 18.px,
fontWeight: FontWeight.w600,
color: appBarAlpha == 0
? Colors.white
: Color(0xff333333)),
),
),
),
Container(
width: 40.px,
)
],
),
),
],
),
);
}
}
使用时调用组件即可,例如:
@override
Widget build(BuildContext context) {
return SlideGradientAppBar(
body: widget //主页面组件
title: "审批详情",);
),
}
实现效果为:
appbar 滑动渐变.gif
网友评论