您的位置:首页 > 移动开发 > Android开发

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

2017-02-13 17:23 507 查看
之所以做这件事,是因为前者已经没有在维护了,所以把现在的下拉刷新框架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的一些小心得,有不对的地方欢迎大家指正,转载请附链接。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息