推荐阅读:
liaohuqiu/android-Ultra-Pull-To-Refresh
我眼中的下拉刷新
android-Ultra-Pull-To-Refresh 源码解析
Ultra-Pull-To-Refresh 自定义下拉刷新视差动画
android-Ultra-Pull-To-Refresh/SwipeRefreshLayout嵌套ViewPager/ScrollView滑动冲突解决
准备工作,添加依赖:
//刷新
compile 'in.srain.cube:ultra-ptr:1.0.11'
//
compile 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
一、自定义刷新头部viewgroup实现PtrUIHandler接口:
/**
* step0:下拉/准备下拉状态
* step1:下拉->可刷新状态
* step2:刷新状态
* step3:刷新结束状态
*/
public class PtrMeiTuanHeader extends LinearLayout implements PtrUIHandler {
private static final String TAG = PtrMeiTuanHeader.class.getSimpleName();
@BindView(R.id.ivFirst)
ImageView ivFirst;
@BindView(R.id.ivSecond)
ImageView ivSecond;
@BindView(R.id.ivThird)
ImageView ivThird;
@BindView(R.id.tvMsg)
TextView tvMsg;
private Matrix mMatrix = new Matrix();
private AnimationDrawable mSecondAnimation;
private AnimationDrawable mThirdAnimation;
public PtrMeiTuanHeader(Context context) {
this(context, null);
}
public PtrMeiTuanHeader(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PtrMeiTuanHeader(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
View headerView = LayoutInflater.from(context).inflate(R.layout.header_meituan, this);//
ButterKnife.bind(headerView);
init();
}
/**
* 初始化帧动画
*/
private void init() {
mSecondAnimation = (AnimationDrawable) ivSecond.getDrawable();
mThirdAnimation = (AnimationDrawable) ivThird.getDrawable();
}
/**
* 刷新准备 : Header 将要出现时调用。
*
* @param frame
*/
@Override
public void onUIRefreshPrepare(PtrFrameLayout frame) {//调用1
Log.e("111111","onUIRefreshPrepare");
pullStep0(0.0f);
}
/**
* 开始刷新 : Header 进入刷新状态之前调用。
*
* @param frame
*/
@Override
public void onUIRefreshBegin(PtrFrameLayout frame) {//调用4
Log.e("111111","onUIRefreshBegin");
pullStep2();
}
/**
* 刷新结束 : Header 开始向上移动之前调用。
*
* @param frame
*/
@Override
public void onUIRefreshComplete(PtrFrameLayout frame) {//调用5
Log.e("111111","onUIRefreshComplete");
pullStep3();
}
/**
* 刷新重置 : Content重新回到顶部Header消失,重置 View。
*
* @param frame
*/
@Override
public void onUIReset(PtrFrameLayout frame) {//调用6
Log.e("111111","onUIReset");
resetView();
}
/**
* isUnderTouch: 是否松手(true、false)
* status: 状态(1:init、2:prepare、3:loading、4:complete)
*/
@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();//前一个位置
if (isUnderTouch) {//下拉过程的两个阶段:到达可释放刷新位置前后
if (lastPos < currentPos && currentPos < mOffsetToRefresh) {//调用2
Log.e("111111","onUIPositionChange ----");
float scale = lastPos / (float) mOffsetToRefresh;
pullStep0(scale);
} else {//调用3
Log.e("111111","onUIPositionChange ++++");
pullStep1(frame);
}
}
}
private void pullStep0(float scale) {
ivFirst.setVisibility(View.VISIBLE);
ivSecond.setVisibility(View.INVISIBLE);
ivThird.setVisibility(View.INVISIBLE);
scaleImage(scale);
tvMsg.setText(getResources().getString(R.string.cube_ptr_pull_down_to_refresh));
}
private void pullStep1(PtrFrameLayout frame) {
if (!frame.isPullToRefresh()) {
ivFirst.setVisibility(View.INVISIBLE);
ivSecond.setVisibility(View.VISIBLE);
ivThird.setVisibility(View.INVISIBLE);
mSecondAnimation.start();
tvMsg.setText(getResources().getString(R.string.cube_ptr_release_to_refresh));
}
}
private void pullStep2() {
ivFirst.setVisibility(View.INVISIBLE);
ivSecond.setVisibility(View.INVISIBLE);
ivThird.setVisibility(View.VISIBLE);
cancelAnimationSecond();
mThirdAnimation.start();
tvMsg.setText(R.string.cube_ptr_refreshing);
}
private void pullStep3() {
ivFirst.setVisibility(View.INVISIBLE);
ivSecond.setVisibility(View.INVISIBLE);
ivThird.setVisibility(View.VISIBLE);
cancelAnimationThird();
tvMsg.setText(getResources().getString(R.string.cube_ptr_refresh_complete));
}
private void scaleImage(float scale) {
mMatrix.setScale(scale, scale, ivFirst.getWidth() / 2, ivFirst.getHeight() / 2);
ivFirst.setImageMatrix(mMatrix);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
resetView();
}
private void resetView() {
cancelAnimations();
}
private void cancelAnimations() {
cancelAnimationSecond();
cancelAnimationThird();
}
private void cancelAnimationSecond() {
if (mSecondAnimation != null && mSecondAnimation.isRunning()) {
mSecondAnimation.stop();
}
}
private void cancelAnimationThird() {
if (mThirdAnimation != null && mThirdAnimation.isRunning()) {
mThirdAnimation.stop();
}
}
}
二、自定义刷新viewgroup继承PtrFrameLayout
1、添加头布局setHeaderView
2、实现头部监听addPtrUIHandler
public class PtrlMeiTuanFrameLayout extends PtrFrameLayout {
public PtrlMeiTuanFrameLayout(Context context) {
super(context);
init();
}
public PtrlMeiTuanFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PtrlMeiTuanFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
PtrMeiTuanHeader mHeaderView = new PtrMeiTuanHeader(getContext());
setHeaderView(mHeaderView);
addPtrUIHandler(mHeaderView);
}
}
3、布局中使用刷新viewgroup:
<?xml version="1.0" encoding="utf-8"?>
<com.example.lenovo.myptrrefreshtest.view.PtrlMeiTuanFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ptrFrame_custom"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tvDrag"
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center"
android:text="@string/meituan"
android:textSize="16sp" />
</LinearLayout>
</com.example.lenovo.myptrrefreshtest.view.PtrlMeiTuanFrameLayout>
4、代码中设置刷新:
ptrFrame.setPtrHandler(new PtrHandler() {
@Override
public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
return true;
}
@Override
public void onRefreshBegin(PtrFrameLayout frame) {
ptrFrame.postDelayed(new Runnable() {
@Override
public void run() {
//请求数据
Log.e("111111","请求数据");
//刷新结束
ptrFrame.refreshComplete();
}
}, 2000);
}
});
其他:
1、完整的一次下拉刷新,打印log如下:
onUIRefreshPrepare
onUIPositionChange ----
onUIPositionChange ----
onUIPositionChange ----
onUIPositionChange ----
onUIPositionChange ----
onUIPositionChange ----
onUIPositionChange ----
onUIPositionChange ++++
onUIPositionChange ++++
onUIPositionChange ++++
onUIPositionChange ++++
onUIPositionChange ++++
onUIPositionChange ++++
onUIRefreshBegin
请求数据
onUIRefreshComplete
onUIReset
注:PtrFrameLayout.getOffsetToRefresh:到达这个位置,释放后才会执行”请求数据”
2、在一次完整的下拉刷新过程中实现PtrUIHandler接口的方法调用图:
3、onUIPositionChange的参数isUnderTouch,status在一次完整的下拉刷新过程中值得变化图:
isUnderTouch:手指是否触摸屏幕,下拉过程中一直为true,释放为false。
status:在PtrFrameLayout中有定义:
public final static byte PTR_STATUS_INIT = 1;
private byte mStatus = PTR_STATUS_INIT;
public final static byte PTR_STATUS_PREPARE = 2;
public final static byte PTR_STATUS_LOADING = 3;
public final static byte PTR_STATUS_COMPLETE = 4;