前言
这几天正在研究几个比较有名的开源项目,偶然发现了SlidingUpPanelLayout这个神器,经过一番研究,和大家一起分享一下学习心得。
如果要使用滑动菜单,目前最流行的应该是DrawerLayout,这个由谷歌开源的控件已经被放在android包中,使用起来非常的方便,唯一的遗憾是DrawerLayout只支持左右滑动的菜单,但是并不支持上下滑动的菜单,我们今天要介绍的SlidingUpPanelLayout,相当于竖向的DrawerLayout。
首先我们看一个动画:
很多的音乐播放器都有这样的交互,使用SlidingUpPanelLayout就可以实现。
SlidingUpPanelLayout早在2016年就已经发布了,肯定已经非常的稳定,大家可以到github上先看看基本的使用方法。
https://github.com/umano/AndroidSlidingUpPanel
正文
首先我们需要在build.gradle文件中依赖SlidingUpPanelLayout:
dependencies {
repositories {
mavenCentral()
}
compile 'com.sothree.slidinguppanel:library:3.4.0'
}
我们写一个最简单的布局:
仅仅定义xml,一个可以上滑的菜单就完成了。接下来我们看看SlidingUpPanelLayout都提供了哪些方法。
setPanelHeight
setPanelHeight对应自定义属性umanoPanelHeight。
当菜单被折叠时,显示的高度
上面的demo中已经使用了这个自定义属性,非常好理解。
setOverlayed
setOverlayed对应自定义属性umanoOverlay。
意思是菜单是否要覆盖到主页面之上:
如果是false,相当于LinearLayout,主页面在上,菜单在下
如果是true,相当于FrameLayout
默认是false类型,具体按照UE的需求自行选择。
setClipPanel
setClipPanel对应自定义属性umanoClipPanel。
是否要裁剪菜单的区域,特别注意,此属性只会在 Overlayed = false的时候有效
如果是true,会把被菜单遮盖的区域,主页面的内容会被裁掉。
如果是false,菜单的内容和主页面的内容会同时显示,覆盖在上面。
这个属性,我猜测主要是为了优化绘制速度的,如果你的菜单有不透明背景,建议设置为true,缩小主页面绘制的区域范围,提高流畅度。
setDragView
setDragView对应自定义属性umanoDragView。
从字面的意思来看,就是可以拖拽的View,如果你不希望整个菜单都可以被手势展开或折叠,可以设置某一个View作为响应手势的热区。
setParallaxOffset
setParallaxOffset对应自定义属性umanoParallaxOffset。
当菜单在滑动的时候,主页面一起移动的视觉偏差。
例如菜单展开的过程中,主页面向上移动100dp,视觉上有一种主页面被顶上去的效果。
setFadeOnClickListener
setFadeOnClickListener没有对应的自定义属性。
如果你在滑动的过程中,点击了菜单以外的部分,你会发现菜单的展开或折叠动画被中断了,如果你希望在点击的时候做什么处理,你可以设置setFadeOnClickListener。不过此处有坑,那就是你的主页面必须是可点的,以刚才的demo为例:
我设置的主页面只是一个TextView,TextView默认是不可点击的,所以无论怎么点setFadeOnClickListener都不会触发,所以需要手动加上android:clickable=true,才会响应setFadeOnClickListener。
setCoveredFadeColor
setCoveredFadeColor对应自定义属性umanoFadeColor。
菜单覆盖在主页面上的背景颜色,此颜色可以被rootView的背景颜色盖住,也可以理解为阴影的颜色
setAnchorPoint
setAnchorPoint对应自定义属性umanoAnchorPoint。
自定义的菜单展开的锚点比例。值为0-1之间的小数,非手动拖拽菜单的情况下(例如点击)只会展开到这个锚点的比例。
例如,setAnchorPoint(0.5f),菜单只会自动展开一半。
setPanelState
设置菜单的展开状态,目前主要有:
public enum PanelState {
EXPANDED, // 展开
COLLAPSED, // 折叠
ANCHORED, // 锚点
HIDDEN, // 隐藏
DRAGGING // 拖拽中(个人觉得理解为变化中更合适)
}
与之相关属性有umanoInitialState:菜单的初始状态。
setScrollableView
setScrollableView对应的自定义属性为umanoScrollableView。
可以滚动的Child。如果内部有ScrollView,ListView,RecyclerView,通过这个方法,会把手势的滑动让给他们,从而避免SlidingUpPanelLayout和child之间的手势冲突。
SlidingUpPanelLayout只能设置一个child作为ScrollableView。
setScrollableViewHelper
setScrollableViewHelper没有对应的自定义属性。
他的作用和setScrollableView类似,只不过setScrollableViewHelper更具有通用性,可以对的每一个View自定义手势处理:
public int getScrollableViewScrollPosition(View scrollableView, boolean isSlidingUp) {
if (scrollableView == null) return 0;
if (scrollableView instanceof ScrollView) {
...
} else if (scrollableView instanceof ListView && ((ListView) scrollableView).getChildCount() > 0) {
...
} else if (scrollableView instanceof RecyclerView && ((RecyclerView) scrollableView).getChildCount() > 0) {
....
} else {
return 0;
}
}
ScrollableViewHelper内部已经处理了ScrollView,ListView,RecyclerView,能够满足大部分的需求。
addPanelSlideListener
addPanelSlideListener是SlidingUpPanelLayout最核心的api,监听菜单展开的进度。他的用法和动画的的监听基本一样:
SlidingUpPanelLayout.PanelSlideListener {
override fun onPanelSlide(panel: View?, slideOffset: Float) {
// panel :就是菜单的根布局
// slideOffset:菜单展开的比例,值为0到1,0为折叠状态,1为展开状态
}
override fun onPanelStateChanged(
panel: View?,
previousState: SlidingUpPanelLayout.PanelState?,
newState: SlidingUpPanelLayout.PanelState?
) {
// newState:目前SlidingUpPanelLayout的状态
}
}
EXPANDED, // 展开
COLLAPSED, // 折叠
ANCHORED, // 锚点,这个状态只有设置了锚点才会有
HIDDEN, // 隐藏
DRAGGING // 拖拽中(个人觉得理解为变化中更合适),无论是点击还是拖拽,只要是菜单在滑动,都会进入这个状态。
总结
关于SlidingUpPanelLayout的所有内容到此结束了,几乎所有的api我们都已经介绍了,但是具体的效果建议大家自己去尝试,尤其是ClipPanel和Overlayed,有什么问题可以留言讨论。