flutter 滚动隐藏悬浮按钮
- 实现思路,当开始滚动的时候,执行动画让中间的悬浮按钮向右移动。当滚动结束的时候复位动画
监听滚动的方法有两种
第一种 NotificationListener 在widget树中,子widget滚动时会向上发送notification,通过NotificationListener可以监控到该notification。NotificationListener也是一个widget,可以将被监控的widget放入其child内。
NotificationListener
const NotificationListener({
Key key,
@required this.child, 被监控的子widget树
this.onNotification, 监控到notification后的回调方法。
})
onNotification(ScrollNotification notification) , 此方法需要一个返回值,表示是否拦截住notification,如果是true,那么notifcation到此为止;如果是false,那么notification会继续向更外层widget传递。参数ScrollNotification包含了监听到的信息。
ScrollNotification
ScrollNotification({
@required this.metrics, 所有信息都在这里存储 ScrollMetrics
@required this.context,
});
第二种是通过ScrollController来监听
ScrollController 常用方法
- addListener 滑动监听方法,在initState中监听
- _scrollController.position.pixels 滑动距离
- _scrollController.offset 滚动的偏移量
- _scrollController.position.maxScrollExtent 最大可滑动距离,滑动组件内容长度
- -_scrollController.position.minScrollExtent 最小可滑动距离,0
- _scrollController.position.viewportDimension 滑动视图所占长度
- _scrollController.dispose() 销毁监听,在dispose方法中调用
- _scrollController.jumpTo 控制滑动组件的滑动距离,无动画
- _scrollController.animateTo(10); 控制滑动组件的滑动距离,有动画
- _scrollController.position.jumpTo 同上
- _scrollController.position.animateTo 同上
controller.addListener((){
print(controller......)
});
下面我们开始实现我们的效果
第一步
我们使用Scaffold floatingActionButton 来添加我们widget ,配合 floatingActionButtonLocation 设置下位置,
Scaffold(
appBar: PreferredSize(
child: _getAppBar(),
preferredSize: Size(double.infinity,44),
),
backgroundColor: Colors.white,
floatingActionButton: AnimationWidget(),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
body: ...,
);
创建悬浮按钮 AnimationWidget
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
//状态管理
class NotifierAnimation extends ChangeNotifier{
//回调方法
ValueChanged stopValueChanged;
void animationStartAndEnd(isStop){
stopValueChanged(isStop);
notifyListeners();
}
}
class AnimationWidget extends StatefulWidget {
@override
_AnimationWidgetState createState() => _AnimationWidgetState();
}
class _AnimationWidgetState extends State with SingleTickerProviderStateMixin{
AnimationController _animationController;
Animation _animation;
@override
void initState() {
super.initState();
//实例化动画
_animationController = new AnimationController(vsync: this,duration: new Duration(milliseconds: 240));
_animation = Tween(begin: Offset(0,0), end: Offset(0.8, 0)).animate(_animationController);
}
@override
void didChangeDependencies() {
//Provider 状态管理 得到回调如果true 那就是开始动画
final counter = Provider.of(context);
if (counter !=null) {
Provider.of(context,listen: false).stopValueChanged=((v){
if(v){
//开始动画
_animationController.forward();
}else{
//复位动画
_animationController.reverse();
}
});
}
}
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.centerRight,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: 100),
SlideTransition(
child: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.red
),
),position: _animation,),
],
)
);
}
}
这么这里使用到的是NotificationListener,因为ScrollController不能得到什么时候开始滚动什么时候结束滚动,
第二步 创建 NotificationListener child就是你的滚动视图 可以是 ListView CustomScrollView,也可以包裹 三方插件 SmartRefresher
NotificationListener(
onNotification: (notification){
if( notification.depth == 0){
switch (notification.runtimeType){
case ScrollStartNotification:{
//开始滚动 执行动画
Provider.of(context,listen: false).animationStartAndEnd(true);
}
break;
case ScrollUpdateNotification: print("正在滚动") ; break;
case ScrollEndNotification:{
print("滚动停止");
//滚动停止 结束动画 复位
Provider.of(context,listen: false).animationStartAndEnd(false);
} break;
case OverscrollNotification: print("滚动到边界"); break;
}
}
return;
},
child: ListView()
);
我们这里通过三方插件Provider状态共享来执行动画 ,当然了你也可以使用其他方法,无非就是一个回调,调用我们封装好的widget 来执行动画
Main
//Provider
void main() {
NotifierAnimation notifierAnimation = NotifierAnimation();
runApp(MultiProvider(
providers: [
ChangeNotifierProvider.value(value: notifierAnimation),
],
child: MyApp(),
));
}