上次做的那个下拉刷新效果太差了,于是看了一下网上的刷新框架,自己实现了一个类似于百度贴吧的下拉刷新
我暂时发现原始下拉刷新的效果有两种
一种是百度的,down手势的时候,未在顶部,也能够下拉出刷新头部,下拉出头部之后,再继续上拉,头部隐藏之后,手势也会完全的交给内容View,这种在我看来是比较合理的
另一种就是很多软件用的,只有当down手势的那一刻整个内容区域在顶部的时候才可以下拉刷新,并且下拉出头部再上拉隐藏,内容view也获取不到后续的手势
我就是按照百度贴吧的效果做的,其中手势的处理算是很蛋疼的一件事情,效果图
其中里面还有listview,
手势的处理
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = ev.getY();
//如果此时正在进行滑动,并且此时的状态不为正在刷新,则直接把动画停止
if(runnable != null && currentState != RefreshState.REFRESHING){
runnable.stop();
}
break;
case MotionEvent.ACTION_MOVE:
//如果向下滑动的距离超过了一定的数值,则父控件直接将该手势截取,用于判断是否应该将下拉刷新的view
//显示出来 @see #isPullDownEnable
if(isPullDownEnable() && (ev.getY()-lastY) > viewConfiguration.getScaledTouchSlop()){
//重置回false
requestDisallowInterceptTouchEvent(false);
//代表父控件不能释放改手势了
canReleaseTouchEvent = false;
}
//这个条件用来判断,用户把头部下拉出来一点,但是接着上拉,使得头部隐藏,隐藏之后,所有的手势又得重新交给子控件去处理
//所以此时必须要满足两个条件,一个是我已经截取了该手势和另一个是我应该释放该手势
//另一个需要注意的是listview,这个view很特殊
if(canCatchTouchevent && canReleaseTouchEvent && isChildViewNeedDown()){
if(first){
ev.setAction(MotionEvent.ACTION_DOWN);
Log.e("zhao", "listview"+ev.getAction());
first = false;
}
contentView.dispatchTouchEvent(ev);
}
break;
case MotionEvent.ACTION_UP:
//不要忘记将其重置回false状态
canCatchTouchevent = false;
canReleaseTouchEvent = false;
first = true;
default:
break;
}
// Log.e("zhao", "dispatch");
return super.dispatchTouchEvent(ev);
}
/**
* 由于listView开始滚动的时候,他会调用parent.requestDisallowInterceptTouchEvent(true);
* 所以父控件的这个onInterceptTouchEvent以后就不调用了,这个一定要注意,所以这种情况就需要去dispatchTouchEvent中
* 去处理了,因为dispatchTouchEvent是一定会执行的
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = ev.getY();
canCatchTouchevent = false;
//如果此时头部可见,则一定截取该手势
if(isHeadVisible())
canCatchTouchevent = true;
break;
case MotionEvent.ACTION_MOVE:
//如果向下滑动的距离超过了一定的数值,则父控件直接将该手势截取,用于判断是否应该将下拉刷新的view
//显示出来 @see #isPullDownEnable
if(isPullDownEnable() && (ev.getY()-lastY) > viewConfiguration.getScaledTouchSlop()){
canCatchTouchevent = true;
}
lastY = ev.getY();
break;
default:
break;
}
// Log.e("zhao", "onintercept"+canCatchTouchevent);
return super.onInterceptTouchEvent(ev) || canCatchTouchevent;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Boolean isHandled = false;
if(!canReleaseTouchEvent){
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isHandled = true;
break;
case MotionEvent.ACTION_MOVE:
moveY = event.getY() - lastY;
lastY = event.getY();
//如果手势为向上滑动,或者手势向下并且头部没有完全隐藏,这两种情况将该手势截取
if(isPullDownEnable() && (moveY > 0 || (moveY<=0 && getScrollY()<0)) ){
pullHeadDown(moveY);
isHandled = true;
//这里需要将其置为true,以防用户反复将头部划出,隐藏,划出,隐藏。。。。
first = true;
canReleaseTouchEvent = false;
}else{
// Log.e("zhao", "canrelease"+canReleaseTouchEvent+"movey"+moveY+"getscrolly"+getScrollY());
//只有当此时用户已经手动将头部下拉下来,并且此时刷新状态不等于refresing时才将状态变为done
//因为可能出现正在刷新但是刷新未完成,但是用户手动下拉使得头部隐藏,此时不应该直接变为done
if(!isHeadVisible() && currentState!=RefreshState.REFRESHING) {
changeState(RefreshState.DONE);
}
canReleaseTouchEvent = true;
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if(currentState == RefreshState.RELEASETOREFRESH){
resetRefreshing();
changeState(RefreshState.REFRESHING);
isHandled = true;
}else if (currentState == RefreshState.REFRESHING){
//此时如果正在刷新,用户还继续往上拉,则重置位置,其他情况不处理
if(getScrollY() < -head.getHeight())
resetRefreshing();
}else{
changeState(RefreshState.DONE);
}
break;
default:
break;
}
}
// Log.e("zhao", "ontouch"+isHandled);
//如果这里返回false,则这个ontouchevent应该recycle,并且touchevent事件又重新开始循环走oninterceptTouchEvent
return isHandled;
}