下拉刷新框架Android-Ultra-Pull-To-Refresh的学习与

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/shan286/article/details/54949130

之所以做这件事,是因为前者已经没有在维护了,所以把现在的下拉刷新框架PullToRefresh框架换成Android-Ultra-Pull-To-Refresh框架。

一、下载和配置

在网址为:https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh的地址,把这个项目下载下来,解压后找到名为“ptr_lib”的文件夹,直接丢进我们的项目中。(注:这里我为了方便自己识别,改为了AndroidPtr_Library)。

 

第一步:在整个工程的settings.gradle文件中添加     

include:’ AndroidPtr_Library’

后,在Project Structure中找到我们的项目,点击弹框右侧添加按钮,添加一个命名为“AndroidPtr_Library”的Module Dependency。

 

第二步:在项目的build.gradle文件中添加依赖

compile project(':AndroidPtr_Library')


做完上面这两步后,点击“Rebuild Project”,“,然后就报错了,报错内容如下:

Error:(4, 1) A problemoccurred evaluating project ':AndroidPtr_Library'.

> Could not getunknown property 'ANDROID_BUILD_SDK_VERSION' for project':AndroidPtr_Library' of type org.gradle.api.Project.


所以就有了第三步:在整个工程的gradle.properties文件中添加

ANDROID_BUILD_MIN_SDK_VERSION=8

ANDROID_BUILD_TARGET_SDK_VERSION=22

ANDROID_BUILD_SDK_VERSION=22

ANDROID_BUILD_TOOLS_VERSION=22.0.1


接着运行便没有问题了,也可以看到下拉刷新的框架已经加进来了。


二、Header改造之PtrClassicDefaultHeader类

在源码中有很多叫***Header的类,也就是我们下拉刷新的头部对应的类,这里我们先来看最原始的PtrClassicDefaultHeader的类。

在这个类里面有几个主要方法:

initView()    初始化视图

buildAnimation() 初始化动画对象,这里面有两个旋转动画用于图片为一个箭头的ImageView在下拉时改变箭头方向。

重写onDetachedFromWindow()    当视图销毁时,判断下拉时更新时间的线程是否为空,如果不为空就停止该线程。

tryUpdateLastUpdateTime() 更新最后的刷新时间

getLastUpdateTime()   也就是获得最后的刷新时间

重写onUIPositionChange()  这个方法是用来判断位置变化从而在里面对ImageView进行动画处理

了解了这些方法后,再来看这个类对应的布局,也就是一个命名为“cube_ptr_classic_default_header”的布局文件,它由四个部分组成,一个根据旋转动画RotateAnimation变化方向的ImageView,两个TextView,一个用来刷新时显示刷新的状态(下拉刷新-释放刷新-加载中-更新完成),一个则是在下拉刷新时提示上次更新的时间,一个ProgressBar(刷新时转动)。

接着我们就可以对下拉刷新的头部进行改造了。这里我新建了一个类命名为“SherryPtrClassicDefaultHeader”,在这个类里面我只用到了ImageView和TextView。布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="60dp">

        <LinearLayout
            android:id="@+id/sherry_ptr_classic_header_rotate_view_header_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginLeft="10dp"
            android:gravity="center"
            android:orientation="vertical">

            <TextView
                android:id="@+id/sherry_ptr_classic_header_rotate_view_header_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#666666"
                android:textSize="14sp" />
        </LinearLayout>

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toLeftOf="@+id/sherry_ptr_classic_header_rotate_view_header_text">

            <ImageView
                android:id="@+id/sherry_ptr_classic_header_rotate_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:src="@drawable/default_ptr_rotate"/>

        </FrameLayout>
    </RelativeLayout>

</LinearLayout>

这里我的ImageView的默认图片是一个类似于圆形ProgressBar的图片,也就是上面的“default_ptr_rotate”。接着附上我的java类代码:

public class SherryPtrClassicDefaultHeader extends FrameLayout implements PtrUIHandler {

    private final static String KEY_SharedPreferences = "cube_ptr_classic_last_update";
    private static SimpleDateFormat sDataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final int ROTATION_ANIMATION_DURATION = 1200;
    private int mRotateAniTime = 150;
    private RotateAnimation mFlipAnimation;
    private RotateAnimation mReverseFlipAnimation;
    private TextView mTitleTextView;
    private View mRotateView;
    private float mDownHeight = 0;
    private long mLastUpdateTime = -1;
    private String mLastUpdateTimeKey;

    public SherryPtrClassicDefaultHeader(Context context) {
        super(context);
        initViews(null);
    }

    public SherryPtrClassicDefaultHeader(Context context, AttributeSet attrs) {
        super(context, attrs);
        initViews(attrs);
    }

    public SherryPtrClassicDefaultHeader(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initViews(attrs);
    }

    protected void initViews(AttributeSet attrs) {
        TypedArray arr = getContext().obtainStyledAttributes(attrs, R.styleable.PtrClassicHeader, 0, 0);
        if (arr != null) {
            mRotateAniTime = arr.getInt(R.styleable.PtrClassicHeader_ptr_rotate_ani_time, mRotateAniTime);
        }
        buildAnimation();
        View header = LayoutInflater.from(getContext()).inflate(R.layout.sherry_ptr_classic_default_header, this);

        mRotateView = header.findViewById(R.id.sherry_ptr_classic_header_rotate_view);

        mTitleTextView = (TextView) header.findViewById(R.id.sherry_ptr_classic_header_rotate_view_header_title);

        resetView();
    }

    public void setRotateAniTime(int time) {
        if (time == mRotateAniTime || time == 0) {
            return;
        }
        mRotateAniTime = time;
        buildAnimation();
    }

    /**
     * Specify the last update time by this key string
     *
     * @param key
     */
    public void setLastUpdateTimeKey(String key) {
        if (TextUtils.isEmpty(key)) {
            return;
        }
        mLastUpdateTimeKey = key;
    }

    /**
     * Using an object to specify the last update time.
     *
     * @param object
     */
    public void setLastUpdateTimeRelateObject(Object object) {
        setLastUpdateTimeKey(object.getClass().getName());
    }

    private void buildAnimation() {
        mFlipAnimation = new RotateAnimation(0, mDownHeight * 360 / 100, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        mFlipAnimation.setInterpolator(new LinearInterpolator());
        mFlipAnimation.setDuration(100);
        mFlipAnimation.setRepeatCount(Animation.INFINITE);
        mFlipAnimation.setRepeatMode(Animation.RESTART);

        mReverseFlipAnimation = new RotateAnimation(0, 720, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
        mReverseFlipAnimation.setDuration(ROTATION_ANIMATION_DURATION);
        mReverseFlipAnimation.setRepeatCount(Animation.INFINITE);
        mReverseFlipAnimation.setRepeatMode(Animation.RESTART);
    }

    private void resetView() {
        hideRotateView();
    }

    private void hideRotateView() {
        mRotateView.clearAnimation();
        mRotateView.setVisibility(INVISIBLE);
    }

    @Override
    public void onUIReset(PtrFrameLayout frame) {
        resetView();
    }

    @Override
    public void onUIRefreshPrepare(PtrFrameLayout frame) {


        mRotateView.setVisibility(VISIBLE);
        mTitleTextView.setVisibility(VISIBLE);
        if (frame.isPullToRefresh()) {
            mTitleTextView.setText(getResources().getString(R.string.ynf_ptr_pull_down_to_refresh));
        } else {
            mTitleTextView.setText(getResources().getString(R.string.ynf_ptr_pull_down));
        }
    }

    @Override
    public void onUIRefreshBegin(PtrFrameLayout frame) {
        mTitleTextView.setVisibility(VISIBLE);
        mTitleTextView.setText(R.string.ynf_ptr_refreshing);

    }

    @Override
    public void onUIRefreshComplete(PtrFrameLayout frame) {

        mTitleTextView.setVisibility(VISIBLE);
        mTitleTextView.setText(getResources().getString(R.string.ynf_ptr_refresh_complete));

        // update last update time
        SharedPreferences sharedPreferences = getContext().getSharedPreferences(KEY_SharedPreferences, 0);
        if (!TextUtils.isEmpty(mLastUpdateTimeKey)) {
            mLastUpdateTime = new Date().getTime();
            sharedPreferences.edit().putLong(mLastUpdateTimeKey, mLastUpdateTime).commit();
        }
    }

    @Override
    public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {

        final int mOffsetToRefresh = frame.getOffsetToRefresh();
        final int currentPos = ptrIndicator.getCurrentPosY();
        final int lastPos = ptrIndicator.getLastPosY();

        mDownHeight = mOffsetToRefresh;
        Log.d("xueli-----------", "currentPos==" + currentPos + ",lastPos==" + lastPos + ",mOffsetToRefresh==" + mOffsetToRefresh
                +"isUnderTouch==" + isUnderTouch);
        if (currentPos < mOffsetToRefresh && lastPos >= mOffsetToRefresh) {
            if (status == PtrFrameLayout.PTR_STATUS_LOADING) {
                crossRotateLineFromBottomUnderTouch(frame);
                if (mRotateView != null) {
                    Log.d("xueli----2------", "mReverseFlipAnimation");
                    mRotateView.clearAnimation();
                    mRotateView.startAnimation(mReverseFlipAnimation);
                }
            }
        } else if (currentPos > mOffsetToRefresh && lastPos <= mOffsetToRefresh) {
            if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
                crossRotateLineFromTopUnderTouch(frame);
                if (mRotateView != null) {
                    Log.d("xueli----1------", "mFlipAnimation");
                    mRotateView.clearAnimation();
                    mRotateView.startAnimation(mFlipAnimation);
                }
            }
        }
    }

    private void crossRotateLineFromTopUnderTouch(PtrFrameLayout frame) {
        if (!frame.isPullToRefresh()) {
            mTitleTextView.setVisibility(VISIBLE);
            mTitleTextView.setText(R.string.ynf_ptr_release_to_refresh);
        }
    }

    private void crossRotateLineFromBottomUnderTouch(PtrFrameLayout frame) {
        mTitleTextView.setVisibility(VISIBLE);
        if (frame.isPullToRefresh()) {
            mTitleTextView.setText(getResources().getString(R.string.ynf_ptr_pull_down_to_refresh));
        } else {
            mTitleTextView.setText(getResources().getString(R.string.ynf_ptr_pull_down));
        }
    }
}

改完了之后,要注意的一点就是把除了PtrClassicDefaultHeader以外,用到PtrClassicDefaultHeader的地方,把名字都改成SherryPtrClassicDefaultHeader,其实也就是PtrClassicFrameLayout类中的PtrClassicDefaultHeader。

三、下拉刷新控件的使用

首先看布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/gray_shallow"
    android:orientation="vertical">

    <include layout="@layout/title" />

    <in.srain.cube.views.ptr.PtrClassicFrameLayout
        android:id="@+id/ptr_my_coupon"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        cube_ptr:ptr_duration_to_close="200"
        cube_ptr:ptr_duration_to_close_header="1000"
        cube_ptr:ptr_keep_header_when_refresh="true"
        cube_ptr:ptr_pull_to_fresh="false"
        cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"
        cube_ptr:ptr_resistance="1.7">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ListView
                android:id="@+id/lv_my_coupon"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:cacheColorHint="@android:color/transparent"
                android:divider="@null"
                android:fadingEdge="none"
                android:fastScrollEnabled="false"
                android:listSelector="@null"
                android:overScrollMode="never"
                android:scrollbars="none" />

            <include
                android:id="@+id/my_coupons_empty"
                layout="@layout/my_coupon_empty"
                android:visibility="gone" />
        </RelativeLayout>
    </in.srain.cube.views.ptr.PtrClassicFrameLayout>

</LinearLayout>

从布局文件我们可以看到,这里我们是直接使用了<in.srain.cube.views.ptr.PtrClassicFrameLayout />,然后在这个FrameLayout里面再放入我们想要下拉刷新显示的布局,要注意的是,这个里面只能有一个子View,不然会报错,所以这里可以看到的是我用的一个相对布局,那么在代码里面当页面为空时,我可以设置ListView不可见,然后显示页面为空时的布局,也就是my_coupon_empty布局文件。

附上java类里面使用的主要代码:

vPtrClsFl = (PtrClassicFrameLayout) findViewById(R.id.ptr_my_coupon);
vPtrClsFl.setPtrHandler(new PtrHandler() {
     @Override
     public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
         return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);
     }

     @Override
     public void onRefreshBegin(PtrFrameLayout frame) {
         // 调接口拿数据
    }
});


好的,那么以上就是我学习与使用下拉刷新框架Android-Ultra-Pull-To-Refresh的一些小心得,有不对的地方欢迎大家指正,转载请附链接。





展开阅读全文

没有更多推荐了,返回首页