DragTopLayout.

在豌豆荚的应用详情页中有个ViewPager布局,该布局头部添加了一个可上下收展的view用于显示应用资料。实现思路基本上就是利用 ViewDragHelper进行拖动来控制头部的view的布局。当TopView可见时,手势事件被拖动层截获控制上下拖动达到TopView的折叠和展开效果。当TopView不可见时,手势事件交由ViewPager进行控制达到ListView正常滚动,并在ListView的onScroll 滚动监听中判断ListView是否触顶。如果触顶则下拉拖动ViewPager显示TopView.

项目已经上传到Github的DragTopLayout

先看下效果图: 

实现过程


1.继承一个FrameLayout,在FrameLayout中控制子View拖动。FrameLayout初始化中实例化一个ViewDragHelper对象。

ViewDragHelper.create(this, 1.0f, callback);

2.参数中callback即为拖动过程中所有的事件回调,实现一个ViewDragHelper.Callback()。 
Callback中的所用到得方法如下:

?
1
2
3
4
5
6
7
8
9
10
// 判断child是否是拖动的目标
tryCaptureView(View child,  int pointerId)
// 拖动位置的处理,可以处理拖动过程中的最高位置或者最低位置
clampViewPositionVertical(View child,  int top,  int dy)
// 拖动后view位置的改变
onViewPositionChanged(View view,  int left,  int top,  int dx,  int dy)
// 拖动手势释放后的处理
onViewReleased(View releasedChild,  float xvel,  float yvel)
// 拖动状态的改变
onViewDragStateChanged( int state)

3.覆盖onInterceptTouchEvent和onTouchEvent方法,将事件拦截处理。

?
1
2
3
4
5
6
7
8
9
10
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
     return shouldIntercept && dragHelper.shouldInterceptTouchEvent(ev);
}
 
@Override
public boolean onTouchEvent(MotionEvent event) {
     dragHelper.processTouchEvent(event);
     return true ;
}

4.覆盖computeScroll方法,用以实现拖动后的滚动效果

?
1
2
3
4
5
6
@Override
public void computeScroll() {
     if (dragHelper.continueSettling( true )) {
         ViewCompat.postInvalidateOnAnimation( this );
     }
}

5.简单地拖动差不多实现了,下面就需要在Callback中进行拖动事件的自定义逻辑处理了。 
先利用tryCaptureView判断当前touch的view是否是目标拖动view,返回true则拖动处理,false不处理。

return child == dragContentView;

在clampViewPositionVertical方法中处理拖动的最高高度不超过上边界。

?
1
2
3
4
@Override
public int clampViewPositionVertical(View child,  int top,  int dy) {
         return Math.min(topViewHeight, Math.max(top, getPaddingTop()));
}

在onViewPositionChanged方法中控制拖动后新位置的处理。因为拖动过程中还需对TopView进行相应地处理,所以在方法内记录拖动的top位置,并在onLayout回调方法中处理最新位置的现实。

?
1
2
3
4
5
6
@Override
public void onViewPositionChanged(View changedView,  int left,  int top,  int dx,  int dy) {
     super .onViewPositionChanged(changedView, left, top, dx, dy);
     contentTop = top;
     requestLayout();
}

当释放手势后判断手势方向利用settleCapturedViewAt方法进行处理最终滚动位置。其中yvel参数>0代表快速往下滑动,否则为快速往上滑动。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public void onViewReleased(View releasedChild,  float xvel,  float yvel) {
     super .onViewReleased(releasedChild, xvel, yvel);
     // yvel > 0 Fling down || yvel < 0 Fling up
     int top;
     if (yvel >  0 || contentTop > topViewHeight) {
         top = topViewHeight + getPaddingTop();
     else {
         top = getPaddingTop();
     }
     if (wizard.enableSliding) {
         dragHelper.settleCapturedViewAt(releasedChild.getLeft(), top);
     }
     postInvalidate();
}


这样就处理好了拖动的所有事件了。具体代码可参考Github上的项目。

https://github.com/chenupt/DragTopLayout
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值