之前分享过一篇仿微信下拉显示小程序的控件,今天分享的与之相似,只不过是下拉展示全部的view,同时主界面可以添加任意布局.支持绑定AbsListview子类,和可滑动的view.
演示:
b1.gif从上面的演示中,可以看到,有4种动作:
- 下拉,没有超过预设阀值,则回弹到关闭状态
- 下拉,超过阀值,这滚动到b1(隐藏的view)完全打开的状态
- 上拉,没有超过预设阀值,则回弹到b1完全打开状态
- 上拉,超过阀值,这滚动到b1(隐藏的view)完全关闭的状态
作用的view上就是view的显示与隐藏问题,之前我们使用改变viewpadding值,这里我们使用动态改变view的margin值,从而改变view显示与隐藏.
所以我们的思路是:
在onTouchEvent的监听中,
- MOVE状态下,根据手势,时刻改变b1的marginTop值,达到随手势打开view和关闭view的动态效果
- 在UP状态下,根据手势状态(下拉或上拉),预设阀值,b1的显示状态判断b1的滚动动作.
view的滚动,依然使用Scroller滚动器.
关键步骤:
1.自定义view继承LinearLayout,初始化basementLayout和currentLayout布局
setOrientation(VERTICAL);//设置纵向布局
basementLayout = new RelativeLayout(context);//负一楼layout
currentLayout = new RelativeLayout(context);//当前layout
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
// 测量当前view的高度,通过margintop隐藏负一楼layout
height = getHeight();
layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
layoutParams.setMargins(0, -height, 0, 0);//隐藏b1
basementLayout.setLayoutParams(layoutParams);
basementLayout.setEnabled(true);
LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
currentLayout.setLayoutParams(layoutParams1);
//添加到当前view中
addView(basementLayout);
addView(currentLayout);
}
});
2.MOVE状态下,改变b1的marginTop
计算手指在Y轴上滑动的距离,根据手势方向设置marginTop
layoutParams.setMargins(0, marginTop, 0, 0);
basementLayout.setLayoutParams(layoutParams);
3.UP状态下,view自动滚动到指定位置
创建Scroller实例,同时设置插值器(初始化里创建)
scroller = new Scroller(context, new DecelerateInterpolator());
使用startScroll设置滚动区间
scroller.startScroll(0, startY, 0, endY, duration);
postInvalidate();//必须(或Invalidate();)
重写computeScroll()方法:
public void computeScroll() {
moving = scroller.computeScrollOffset();
if (scroller.computeScrollOffset()) {
/*获取实时的Y轴的变化值
*这个变化值是从上边传入的startY 到 (startY + endY)
*如:startY =0,endY=100;则变化区间是从0一直递增到100;
*startY=100,endY = -100,则变化区间是100递减到0
*/
int currY = scroller.getCurrY();//获取实时的Y轴的变化值
postInvalidate();//必须(或Invalidate();)
//通过这个变化值,时刻改变marginTop的值,就达到了自动滚动的效果
layoutParams.setMargins(0, currY, 0, 0);
basementLayout.setLayoutParams(layoutParams);
}
以上只是一些重点环节,要想实现最终效果,还有很多细节要处理:
- onInterceptTouchEvent(MotionEvent ev)对于手势拦截的处理(关键)
- float,int转换导致的精度损失问题
- 零界点的判断
- 子view的是否可滑动
...
涉及代码比较零散,不好阐述,详细的实现点击查看源码
网友评论