android-Ultra-Pull-To-Refresh下拉刷
大家都知道android-Ultra-Pull-To-Refresh是一个功能很强大的下拉刷新框架。
项目地址:https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh
原理剖析文档:android-Ultra-Pull-to-Refresh
Demo地址:https://raw.githubusercontent.com/liaohuqiu/android-Ultra-Pull-To-Refresh/master/ptr-demo.apk
相信正常的使用都没什么问题,但是有些点还是要注意的。
1、自定义下拉头部的几个方法的调用时机:
/**
* 重置 View ,隐藏忙碌进度条,隐藏箭头 View ,更新最后刷新时间。
* Content 重新回到顶部, Header 消失,整个下拉刷新过程完全结束以后,重置 View 。
*/
@Override
public void onUIReset(PtrFrameLayout ptrFrameLayout) {
}
/**
* 准备刷新,隐藏忙碌进度条,显示箭头 View ,显示文字,如果是下拉刷新,显示“下拉刷新”,如果是释放刷新,显示“下拉”。
* 准备刷新,Header 将要出现时调用。
*/
@Override
public void onUIRefreshPrepare(PtrFrameLayout ptrFrameLayout) {
}
/**
* 开始刷新,Header 进入刷新状态之前调用。
* 开始刷新,隐藏箭头 View ,显示忙碌进度条,显示文字,显示“加载中...”,更新最后刷新时间。
*/
@Override
public void onUIRefreshBegin(PtrFrameLayout ptrFrameLayout) {
}
/**
* 刷新结束,隐藏箭头 View ,隐藏忙碌进度条,显示文字,显示“更新完成”,写入最后刷新时间。
* 刷新结束,Header 开始向上移动之前调用。
*/
@Override
public void onUIRefreshComplete(PtrFrameLayout ptrFrameLayout) {
}
/**
* 下拉过程中位置变化回调。
* <p>
* 在拖动情况下,当下拉距离从 小于刷新高度到大于刷新高度 时,箭头 View 从向下,变成向上,同时改变文字显示。
* 当下拉距离从 大于刷新高度到小于刷新高度 时,箭头 View 从向上,变为向下,同时改变文字显示。
*/
@Override
public void onUIPositionChange(PtrFrameLayout ptrFrameLayout, boolean b, byte b1, PtrIndicator ptrIndicator) {
float percent = Math.min(1f, ptrIndicator.getCurrentPercent());
}
然后在自定义头部的时候最好把布局也顺便写进去,这样使用起来就比较方便一点:
public class CommonPtrHeader extends FrameLayout implements PtrUIHandler{
private View headerView;
private ProgressBar mProgressBar;
public CommonPtrHeader(Context context) {
super(context);
init();
}
public CommonPtrHeader(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
headerView = LayoutInflater.from(getContext()).inflate(R.layout.pull_to_refresh_head, this);
mProgressBar = (ProgressBar) headerView.findViewById(R.id.pull_to_refresh_progress);
}
}
2、当下拉刷新中有 ViewPager 时,比如 ListView 上面加个 Banner 广告条,这时候其实是会有滑动冲突的,那么网上搜很多都说要重写 ViewPager 或者 PtrFrameLayout,而且大部分都是达不到效果的,其实细心的你可能会发现,PtrFrameLayout 已经提供好方法来解决这一问题了,只是我们平时比较容易忽略:
Q&A好了,只需要这样就能解决冲突了:
ptrFrame.disableWhenHorizontalMove(true);
-----------------------------分割线(补充)-------------------------------------------------------
上面说的设置 disableWhenHorizontalMove ,大家是不是发现好像没什么用,是的,下面在网上找了个方法,使用中顺利解决了冲突问题,而且好像还没发现什么问题,需要重写一下 PtrClassicFrameLayout ,下面是代码:
public class FixPtrFrameLayout extends PtrClassicFrameLayout {
private float startY;
private float startX;
// 记录viewPager是否拖拽的标记
private boolean mIsHorizontalMove;
// 记录事件是否已被分发
private boolean isDeal;
private ViewPager mViewPager;
private int mTouchSlop;
public FixPtrFrameLayout(Context context) {
super(context);
}
public FixPtrFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FixPtrFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* PtrHTFrameLayout has a viewpager
*
* @param viewPager
*/
public void setViewPager(ViewPager viewPager) {
this.mViewPager = viewPager;
if (mViewPager == null) {
throw new IllegalArgumentException("viewPager can not be null");
}
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mViewPager == null) {
return super.dispatchTouchEvent(ev);
}
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// 记录手指按下的位置
startY = ev.getY();
startX = ev.getX();
// 初始化标记
mIsHorizontalMove = false;
isDeal = false;
break;
case MotionEvent.ACTION_MOVE:
// 如果已经判断出是否由横向还是纵向处理,则跳出
if (isDeal) {
break;
}
/**拦截禁止交给Ptr的 dispatchTouchEvent处理**/
mIsHorizontalMove = true;
// 获取当前手指位置
float endY = ev.getY();
float endX = ev.getX();
float distanceX = Math.abs(endX - startX);
float distanceY = Math.abs(endY - startY);
if (distanceX != distanceY) {
// 如果X轴位移大于Y轴位移,那么将事件交给viewPager处理。
if (distanceX > mTouchSlop && distanceX > distanceY) {
mIsHorizontalMove = true;
isDeal = true;
} else if (distanceY > mTouchSlop) {
mIsHorizontalMove = false;
isDeal = true;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//下拉刷新状态时如果滚动了viewpager 此时mIsHorizontalMove为true 会导致PtrFrameLayout无法恢复原位
// 初始化标记,
mIsHorizontalMove = false;
isDeal = false;
break;
}
if (mIsHorizontalMove) {
return dispatchTouchEventSupper(ev);
}
return super.dispatchTouchEvent(ev);
}
}
使用方法就是通过里面的 setViewPager 方法将你的 banner里面的 viewpager 赋值进去就好,如果你的 banne r是写在 adapter 里面的,那你可以将 FixPtrFrameLayout 的实例赋值进去 adapter 里面,再设置 viewpager 就行。