andnroidTECH_ANDROID

android-Ultra-Pull-To-Refresh下拉刷

2016-06-27  本文已影响6781人  L_Xian

大家都知道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 就行。

上一篇下一篇

猜你喜欢

热点阅读