搞了这么久的Android,多是我渠道比较闭塞,一直没找到比较好用的下拉刷新,往上找的第三方比较知名的一些,都说有这样那样的瑕疵,一直用的SwipeRefreshLayout 作下拉加载,而后在RecycleView最后多加一个item,只要加载了这个item,就自动加载更多,要多low有多low,彻底没有欲望去搞别人那种很炫酷的效果。java
附上原味效果图(能够经过继承本代码来定制,提供有相关方法和接口的,后续博客会说明并举例):android
代码区分了5中状态供不一样的应用场景使用,提供了方法可直接设置,也能够各类状态无缝切换:ide
下拉刷新两种:可下拉、不可下拉(带阻尼回弹)布局
上拉加载三种:上拉加载、到底自动加载、不加载(带阻尼回弹)post
源码只有两个文件,一个类(RefreshRelativeLayout)和一个布局文件(refresh_relative_layout.xml),全部代码均用的最原始的方式,并没有其余比较高深的第三方的东西,能够直接导入使用动画
经过设置回调接口监听刷新和加载时间,至于数据,能够经过getRecyclerView方法获取RecyclerView,至于怎么给RecyclerView加上数据操做,这里我就很少废话了,下面是一段调用代码:this
//list是数据,adapter是适配器,这两个东西我就不放出来了,你们都懂 RefreshRelativeLayout recyclerView = (RefreshRelativeLayout) findViewById(R.id.recyclerView); recyclerView.setOnRefreshListener(new RefreshRelativeLayout.OnRefreshListener() { @Override public void onRefresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { adapter.setData(list); recyclerView.setRefreshing(false); } }, 2000);//延迟两秒操做 } }); recyclerView.setOnLoadListener(new RefreshRelativeLayout.OnLoadListener() { @Override public void onLoad() { new Handler().postDelayed(new Runnable() { @Override public void run() { adapter.addData(list); recyclerView.setLoading(false); } }, 2000);//延迟两秒操做 } }); adapter.setData(list); recyclerView.getRecyclerView().setAdapter(adapter); }
总体构成是由一个父RelativeeLayout容器包裹三大部件(头部RelativeLayout、RecyclerView、尾部RelativeLayout)构成;经过重写父RelativeeLayout的dispatchTouchEvent方法监听手指的触摸事件,而后再根据手指移动的位置作各类状态的切换处理,细节能够看源码,注释都很是清晰了的,至少我自觉得是很清晰。spa
RecyclerView不用多说,头部RelativeLayout和尾部RelativeLayout底下均包含了四个RelativeLayout用于表示四种不一样的状态,分别是:(1)下拉或上拉的时候未达到松开刷新加载的状态(2)松开刷新或者加载(3)正在刷新或者加载(4)刷子、加载完成,这个状态能够设置延迟播放收起动画的时间code
重写UI的方法(后续会写个博客介绍):xml
(1)、重写一个refresh_relative_layout.xml,总体结构不能变,三大部件、4*2中状态的RelativeLayout都不能动,可是能够改变里面的内容,以达到不一样的状态显示不一样的UI的效果。
(2)。继承RefreshRelativeLayout并重写里面的一些方法,具体那些方法重写能够达到相关的功能,能够看源码,我经过分隔线进行了分类,另外提供了一个回调接口,用于回调当前手指拖动的距离,这样方便制做下拉或者上拉时候的某种拖动动效(例如朋友圈的彩色圆圈,拖动的时候就转,按着不动的时候就不转)。
import android.content.Context; import android.graphics.Rect; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.animation.Interpolator; import android.view.animation.TranslateAnimation; import android.widget.RelativeLayout; import com.imxiaoyu.common.R; /** * 下拉刷新以及上啦加载更多 * Created by 她叫我小渝 on 2016/12/22. */ public class RefreshRelativeLayout extends RelativeLayout { /** * 常量 */ //pullDownType下拉类型的值;1-正常能够下拉刷新 2-不能够下拉刷新(有阻尼效果 ) public static final int PULL_DOWN_TYPE_REFRESH = 1; public static final int PULL_DOWN_TYPE_NOT_PULL = 2; //pullUpType上拉类型的值;1-能够上拉加载 2-到了底部自动加载更多 3-不能够上拉刷新(有阻尼效果) public static final int PULL_UP_TYPE_LOAD_PULL = 1; public static final int PULL_UP_TYPE_LOAD_AUTO = 2; public static final int PULL_UP_TYPE_NOT_PULL = 3; //pullDownState下拉状态的值;1-下拉 2-松开刷新 3-正在刷新 4-刷新完成 public static final int PULL_DOWN_STATE_1 = 1; public static final int PULL_DOWN_STATE_2 = 2; public static final int PULL_DOWN_STATE_3 = 3; public static final int PULL_DOWN_STATE_4 = 4; //pullDownState上拉状态的值;1-上拉 2-松开加载 3-正在加载 4-加载完成 public static final int PULL_UP_STATE_1 = 1; public static final int PULL_UP_STATE_2 = 2; public static final int PULL_UP_STATE_3 = 3; public static final int PULL_UP_STATE_4 = 4; /** * UI */ private RecyclerView recyclerView; private RelativeLayout rlyHead; private RelativeLayout rlyFoot; private RelativeLayout rlyHeadState1; private RelativeLayout rlyHeadState2; private RelativeLayout rlyHeadState3; private RelativeLayout rlyHeadState4; private RelativeLayout rlyFootState1; private RelativeLayout rlyFootState2; private RelativeLayout rlyFootState3; private RelativeLayout rlyFootState4; /** * 变量 */ private int pullDownType = PULL_DOWN_TYPE_REFRESH;//下拉类型; private int pullUpType = PULL_UP_TYPE_LOAD_PULL;//上拉类型; private int pullDownState = PULL_DOWN_STATE_1;//下拉状态 private int pullUpState = PULL_UP_STATE_1;//上拉状态 private boolean isRefreshing = false;//正在刷新 private boolean isLoading = false;//正在加载更多 private int afterRefreshDelayTime = 200;//刷新完成以后,延迟收起头部视图的时间 private boolean isTouching = false;//是否正在按压着屏幕 // y方向上当前触摸点的前一次记录位置 private int previousY = 0; // y方向上的触摸点的起始记录位置 private int startY = 0; // y方向上的触摸点当前记录位置 private int currentY = 0; // y方向上两次移动间移动的相对距离 private int deltaY = 0; // 用于记录childView的初始位置 private Rect rectRlv = new Rect();//recyclerView的初始位置 private Rect rectRlyHead = new Rect();//头部的初始位置 private Rect rectRlyFoot = new Rect();//尾部的初始位置 //水平移动的距离 private float moveHeight; /** * 接口 */ private OnRefreshListener onRefreshListener;//刷新回调 private OnLoadListener onLoadListener;//加载回调 private OnTouchHeightListener onTouchHeightListener;//拖动的高度监听,正数是下拉,负数是上啦(不会为0) public RefreshRelativeLayout(Context context) { this(context, null); } public RefreshRelativeLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RefreshRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); inflate(getContext(), getLayoutId(), this); initView(); } private void initView() { recyclerView = (RecyclerView) findViewById(R.id.rlv); rlyHead = getHeadLayout((RelativeLayout) findViewById(R.id.rly_refresh_head)); rlyFoot = getFootLayout((RelativeLayout) findViewById(R.id.rly_refresh_foot)); rlyHeadState1 = getHeadState1Layout((RelativeLayout) findViewById(R.id.rly_head_state_1)); rlyHeadState2 = getHeadState2Layout((RelativeLayout) findViewById(R.id.rly_head_state_2)); rlyHeadState3 = getHeadState3Layout((RelativeLayout) findViewById(R.id.rly_head_state_3)); rlyHeadState4 = getHeadState4Layout((RelativeLayout) findViewById(R.id.rly_head_state_4)); rlyFootState1 = getFootState1Layout((RelativeLayout) findViewById(R.id.rly_foot_state_1)); rlyFootState2 = getFootState2Layout((RelativeLayout) findViewById(R.id.rly_foot_state_2)); rlyFootState3 = getFootState3Layout((RelativeLayout) findViewById(R.id.rly_foot_state_3)); rlyFootState4 = getFootState4Layout((RelativeLayout) findViewById(R.id.rly_foot_state_4)); //初始化一下三大件的位置 initLayoutRect(); recyclerView.setOnScrollChangeListener(new OnScrollChangeListener() { @Override public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { //四个断定条件,1-不是正在加载 2-处于自动加载更多模式 3-列表已经到底部了 4-列表没有在顶部(3-4一块儿的意思是列表到底部了,且列表的数据必须大于一页) if (!isLoading && pullUpType == PULL_UP_TYPE_LOAD_AUTO && !recyclerView.canScrollVertically(1) && recyclerView.canScrollVertically(-1)) { setPullUpState(PULL_UP_STATE_3);//到底部自动加载 } } }); recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));//recyclerView默认是ListView同样的列表 } //供外部调用的功能性方法↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓分隔线↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ /** * 返回RecyclerView,做为数据操做使用 * @return */ public RecyclerView getRecyclerView() { return recyclerView; } /** * 设置下拉类型 1-正常能够下拉刷新(默认) 2-不能够下拉刷新(有阻尼效果 ) * ( 最好是在刚初始化的时候就调用) * * @param type */ public void setPullDownType(int type) { this.pullDownType = type; if (type == PULL_DOWN_TYPE_NOT_PULL) { rlyHead.setVisibility(GONE); } else { rlyHead.setVisibility(VISIBLE); } initLayoutRect(); } /** * 设置上啦类型 1-能够下拉刷新(默认) 2-到了底部自动加载更多 3-不能够上拉刷新(有阻尼效果) * ( 最好是在刚初始化的时候就调用) * * @param type */ public void setPullUpType(int type) { this.pullUpType = type; if (type == PULL_UP_TYPE_NOT_PULL) { rlyFoot.setVisibility(GONE); } else { rlyFoot.setVisibility(VISIBLE); } initLayoutRect(); } /** * 设置正在刷新或者刷新完成 * * @param bln */ public void setRefreshing(final boolean bln) { if (bln) { setPullDownState(PULL_DOWN_STATE_3); } else { setPullDownState(PULL_DOWN_STATE_4); } } /** * 设置正在刷新或者刷新完成 * * @param bln */ public void setLoading(final boolean bln) { if (bln) { setPullUpState(PULL_UP_STATE_3); } else { setPullUpState(PULL_UP_STATE_4); } } /** * 监听下拉刷新状态 * * @param listener */ public void setOnRefreshListener(OnRefreshListener listener) { this.onRefreshListener = listener; } /** * 监听上啦或者自动加载状态 * * @param listener */ public void setOnLoadListener(OnLoadListener listener) { this.onLoadListener = listener; } /** * 拖动的高度监听,正数是下拉,负数是上啦(不会为0,且只监听拖动事件,按下和抬起均不回调) * * @param listener true-正在加载 false-加载完成 */ public void setOnLoadListener(OnTouchHeightListener listener) { this.onTouchHeightListener = listener; } /** * 设置刷新完成以后收起视图的时间,毫秒单位 * * @param time */ public void setAfterRefreshDelayTime(int time) { this.afterRefreshDelayTime = time; } //供外部调用的功能性方法↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑分隔线↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //如需自定义样式,能够继承后重写下方的方法↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓分隔线↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ /** * 使用的布局 * * @return */ public int getLayoutId() { return R.layout.refresh_relative_layout; } /** * 头部容器(若是须要特殊定制,能够作些修改,但建议不要改动头、尾的容器) * * @param rlyHead * @return */ public RelativeLayout getHeadLayout(RelativeLayout rlyHead) { return rlyHead; } /** * 下拉刷新的4种状态的视图 * * @param rlyHead * @return */ public RelativeLayout getHeadState1Layout(RelativeLayout rlyHead) { return rlyHead; } public RelativeLayout getHeadState2Layout(RelativeLayout rlyHead) { return rlyHead; } public RelativeLayout getHeadState3Layout(RelativeLayout rlyHead) { return rlyHead; } public RelativeLayout getHeadState4Layout(RelativeLayout rlyHead) { return rlyHead; } /** * 上拉刷新的4种状态的视图 * * @param rlyHead * @return */ public RelativeLayout getFootState1Layout(RelativeLayout rlyHead) { return rlyHead; } public RelativeLayout getFootState2Layout(RelativeLayout rlyHead) { return rlyHead; } public RelativeLayout getFootState3Layout(RelativeLayout rlyHead) { return rlyHead; } public RelativeLayout getFootState4Layout(RelativeLayout rlyHead) { return rlyHead; } /** * 尾部容器(若是须要特殊定制,能够作些修改,但建议不要改动头、尾的容器) * * @param rlyFoot * @return */ public RelativeLayout getFootLayout(RelativeLayout rlyFoot) { return rlyFoot; } /** * 回调动画的动画时长,能够根据需求调节快一点慢一点 * @return */ public int getAnimTime(){ return 760; } //如需自定义样式,能够继承后重写上方的方法↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑分隔线↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ /** * 设置下拉的状态 * * @param state 下拉状态的值;1-下拉 2-松开刷新 3-正在刷新 4-刷新完成 */ private void setPullDownState(int state) { if (state < 1 || state > 4) { Log.e("错误","下拉状态的值越界"); return; } pullDownState = state; if (onRefreshListener != null && state == PULL_DOWN_STATE_3) { //下拉刷新 onRefreshListener.onRefresh(); } changePullDownState(); } /** * 下拉状态改变 */ private void changePullDownState() { isRefreshing = false; rlyHeadState1.setVisibility(INVISIBLE); rlyHeadState2.setVisibility(INVISIBLE); rlyHeadState3.setVisibility(INVISIBLE); rlyHeadState4.setVisibility(INVISIBLE); switch (pullDownState) { case PULL_DOWN_STATE_1: //下拉刷新 if (pullDownType != PULL_DOWN_TYPE_NOT_PULL) { rlyHeadState1.setVisibility(VISIBLE); } break; case PULL_DOWN_STATE_2: //松开刷新 if (pullDownType != PULL_DOWN_TYPE_NOT_PULL) { rlyHeadState2.setVisibility(VISIBLE); } break; case PULL_DOWN_STATE_3: //正在刷新 isRefreshing = true;//除了正在刷新以外,其余状态都不在刷新 if (pullDownType != PULL_DOWN_TYPE_NOT_PULL) { rlyHeadState3.setVisibility(VISIBLE); } //不管当前再什么位置,都跳到正在刷新的地方 moveViewAnimation(rlyHead, 0); moveViewAnimation(recyclerView, rlyHead.getHeight()); break; case PULL_DOWN_STATE_4: //刷新成功 if (pullDownType != PULL_DOWN_TYPE_NOT_PULL) { rlyHeadState4.setVisibility(VISIBLE); } //不管当前再什么位置,都要跳到初始的位置 postDelayed(new Runnable() { @Override public void run() { moveViewAnimation(rlyHead, -1 * rlyHead.getHeight()); moveViewAnimation(recyclerView, 0); } }, afterRefreshDelayTime); break; } } /** * 设置下拉的状态 * * @param state 下拉状态的值;1-下拉 2-松开刷新 3-正在刷新 4-刷新完成 */ private void setPullUpState(int state) { if (state < 1 || state > 4) { Log.e("错误","上拉状态的值越界"); return; } pullUpState = state; if (onLoadListener != null && state == PULL_UP_STATE_3) { //下拉刷新 onLoadListener.onLoad(); } changePullUpState(); } /** * 下拉状态改变 */ private void changePullUpState() { isLoading = false; rlyFootState1.setVisibility(INVISIBLE); rlyFootState2.setVisibility(INVISIBLE); rlyFootState3.setVisibility(INVISIBLE); rlyFootState4.setVisibility(INVISIBLE); switch (pullUpState) { case PULL_UP_STATE_1: //下拉刷新(自动加载更多的模式下禁止显示) if (pullUpType != PULL_UP_TYPE_LOAD_AUTO && pullUpType != PULL_UP_TYPE_NOT_PULL) { rlyFootState1.setVisibility(VISIBLE); } break; case PULL_UP_STATE_2: //松开刷新(自动加载模式下禁止显示) if (pullUpType != PULL_UP_TYPE_LOAD_AUTO && pullUpType != PULL_UP_TYPE_NOT_PULL) { rlyFootState2.setVisibility(VISIBLE); } break; case PULL_UP_STATE_3: //正在刷新 isLoading = true;//除了正在刷新以外,其余状态都不在刷新 if (pullUpType != PULL_UP_TYPE_NOT_PULL) { rlyFootState3.setVisibility(VISIBLE); } //不管当前再什么位置,都跳到正在刷新的地方 moveViewAnimation(rlyFoot, getHeight() - rlyFoot.getHeight()); moveViewAnimation(recyclerView, rlyFoot.getHeight() * -1); break; case PULL_UP_STATE_4: //刷新成功 if (pullUpType != PULL_UP_TYPE_NOT_PULL) { rlyFootState4.setVisibility(VISIBLE); } //不管当前再什么位置,都要跳到初始的位置 postDelayed(new Runnable() { @Override public void run() { moveViewAnimation(rlyFoot, getHeight()); moveViewAnimation(recyclerView, 0); } }, afterRefreshDelayTime); break; } } /** * 记录三大控件的初始位置 */ private void recordLayoutRect() { // 记录三大控件的初始位置 rectRlv.set(recyclerView.getLeft(), 0, recyclerView.getRight(), getHeight()); rectRlyHead.set(rlyHead.getLeft(), -1 * rlyHead.getHeight(), rlyHead.getRight(), 0); rectRlyFoot.set(rlyFoot.getLeft(), getHeight(), rlyFoot.getRight(), getHeight() + rlyFoot.getHeight()); } /** * 初始化三大控件的位置 */ private void initLayoutRect() { post(new Runnable() { @Override public void run() { //初始化位置 recyclerView.layout(recyclerView.getLeft(), 0, recyclerView.getRight(), getHeight()); rlyHead.layout(rlyHead.getLeft(), -1 * rlyHead.getHeight(), rlyHead.getRight(), 0); rlyFoot.layout(rlyFoot.getLeft(), getHeight(), rlyFoot.getRight(), getHeight() + rlyFoot.getHeight()); //绑定一下位置,以避免页面重绘的时候位置发生错乱 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) recyclerView.getLayoutParams(); params.topMargin=0; recyclerView.setLayoutParams(params); recyclerView.requestLayout(); params = (RelativeLayout.LayoutParams) rlyHead.getLayoutParams(); params.topMargin=-1*rlyHead.getHeight(); rlyHead.setLayoutParams(params); rlyHead.requestLayout(); params = (RelativeLayout.LayoutParams) rlyFoot.getLayoutParams(); params.topMargin=getHeight(); params.bottomMargin=getHeight()+rlyFoot.getHeight(); rlyFoot.setLayoutParams(params); rlyFoot.requestLayout(); //初始化状态 setPullDownState(PULL_DOWN_STATE_1); setPullUpState(PULL_UP_STATE_1); } }); } @Override public boolean dispatchTouchEvent(MotionEvent event) { boolean isPullRecyclerView = false;//若是把头拉下来了而后再推回上去的时候,必须把recyclerView的触摸事件屏蔽掉,以避免列表上移 switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isTouching = true; startY = (int) event.getY(); previousY = startY; moveHeight = 0; recordLayoutRect(); break; case MotionEvent.ACTION_MOVE: currentY = (int) event.getY(); deltaY = currentY - previousY; previousY = currentY; //断定是否在顶部或者滑到了底部;第二类断定是,正在刷新什么的,禁止拖动列表 if ((!recyclerView.canScrollVertically(-1) && (currentY - startY) > 0) || (!recyclerView.canScrollVertically(1) && (currentY - startY) < 0) || (rlyHead.getTop() > rectRlyHead.top && (currentY - startY) > 0) || (rlyFoot.getTop() < rectRlyFoot.top && (currentY - startY) < 0)) { isPullRecyclerView = true;//下拉或者上啦的时候把recyclerView的触摸事件屏蔽掉 //计算阻尼 float distance = currentY - startY; if (distance < 0) { distance *= -1; } float damping = 0.5f;//阻尼值 float height = getHeight(); if (height != 0) { if (distance > height) { damping = 0; } else { damping = (height - distance) / height; } } if (currentY - startY < 0) { damping = 1 - damping; } //阻力值限制再0.3-0.5之间,平滑过分 damping *= 0.25; damping += 0.25; moveHeight = moveHeight + (deltaY * damping); recyclerView.layout(rectRlv.left, (int) (rectRlv.top + moveHeight), rectRlv.right, (int) (rectRlv.bottom + moveHeight)); rlyHead.layout(rectRlyHead.left, (int) (rectRlyHead.top + moveHeight), rectRlyHead.right, (int) (rectRlyHead.bottom + moveHeight)); rlyFoot.layout(rectRlyFoot.left, (int) (rectRlyFoot.top + moveHeight), rectRlyFoot.right, (int) (rectRlyFoot.bottom + moveHeight)); //断定是不是下拉动做并处于能够下拉刷新状态 if (pullDownType == PULL_DOWN_TYPE_REFRESH && moveHeight > 0) { if (moveHeight > rlyHead.getHeight()) { setPullDownState(PULL_DOWN_STATE_2); } else { setPullDownState(PULL_DOWN_STATE_1); } } //断定是不是上拉动做而且处于上啦刷新状态 if (pullUpType == PULL_UP_TYPE_LOAD_PULL && moveHeight < 0) { if (moveHeight * -1 > rlyFoot.getHeight()) { setPullUpState(PULL_UP_STATE_2); } else { setPullUpState(PULL_UP_STATE_1); } } //将当前拖动的高度回调 if (onTouchHeightListener != null) { //须要列表处于到顶的状态 if (!recyclerView.canScrollVertically(-1) && moveHeight >= 1) { onTouchHeightListener.onTouchHeight((int) moveHeight); } //须要列表处于到底的状态 if (!recyclerView.canScrollVertically(1) && moveHeight <= -1) { onTouchHeightListener.onTouchHeight((int) moveHeight); } } } break; case MotionEvent.ACTION_UP: isTouching = false; //断定是不是下拉动做并处于能够下拉刷新状态 if (pullDownType == PULL_DOWN_TYPE_REFRESH && moveHeight > rlyHead.getHeight()) { //达到了松开刷新的条件 setPullDownState(PULL_DOWN_STATE_3); } else if (pullUpType == PULL_UP_TYPE_LOAD_PULL && moveHeight * -1 > rlyFoot.getHeight()) { //达到了松开加载的条件 setPullUpState(PULL_UP_STATE_3); } else { //开始回移动画 moveViewAnimation(recyclerView, rectRlv.top); moveViewAnimation(rlyHead, rlyHead.getTop() + rlyHead.getHeight(), 0, rectRlyHead); moveViewAnimation(rlyFoot, rlyFoot.getTop() - rectRlyFoot.top, 0, rectRlyFoot); } //重置一些参数 startY = 0; currentY = 0; break; } if (isPullRecyclerView) { return isPullRecyclerView; } return super.dispatchTouchEvent(event); } /** * 控件移动动画效果,从当前位置,移动到目标位置 * * @param view 待移动的控件 * @param stopY 移动到的目标位置 */ private void moveViewAnimation(View view, int stopY) { moveViewAnimation(view, view.getTop() - stopY, 0, new Rect(view.getLeft(), stopY, view.getRight(), stopY + view.getHeight())); } /** * 控件移动动画效果 * * @param view 待移动的控件 * @param startY 移动开始的位置(相对控件自己) * @param stopY 移动结束的位置(相对控件自己) * @param top 动画结束后的位置,即设置控件自己Top的位置 * @param bottom 动画结束后的位置,即设置控件自己bottom的位置 */ private void moveViewAnimation(View view, int startY, int stopY, int top, int bottom) { moveViewAnimation(view, startY, stopY, new Rect(view.getLeft(), top, view.getRight(), bottom)); } /** * 控件移动动画效果 * * @param view 待移动的控件 * @param startY 移动开始的位置(相对控件自己) * @param stopY 移动结束的位置(相对控件自己) * @param rect 动画结束后的位置,即设置控件自己的位置 */ private void moveViewAnimation(final View view, int startY, int stopY, Rect rect) { if (isTouching) { return;//若是还按压着屏幕,则不播听任何动画 } TranslateAnimation animation = new TranslateAnimation(0.0f, 0.0f, startY, stopY); animation.setDuration(getAnimTime());//动画的持续时间 animation.setFillAfter(true); //设置阻尼动画效果 animation.setInterpolator(new DampInterpolator()); view.setAnimation(animation); view.layout(rect.left, rect.top, rect.right, rect.bottom); recordLayoutRect();//记录位置,用于重绘 } public class DampInterpolator implements Interpolator { @Override public float getInterpolation(float input) { //没看过源码,猜想是input是时间(0-1),返回值应该是进度(0-1) //先快后慢,为了更快更慢的效果,多乘了几回,如今这个效果比较满意 return 1 - (1 - input) * (1 - input) * (1 - input) * (1 - input); } } public void requestLayout() { if (isRefreshing||isLoading) { //刷新recyclerView里面的数据的时候,会调用requestLayout()方法刷新控件,会导刷新刷新完数据以后没有三大部件显示动画就复位了,因此这里屏蔽掉requestLayout方法换成invalidate()刷新页面 invalidate(); } else { super.requestLayout(); } } /** * 接口 */ public interface OnRefreshListener { void onRefresh(); } public interface OnLoadListener { void onLoad(); } public interface OnTouchHeightListener { void onTouchHeight(int num); } }
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rly_bg" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="@+id/rly_refresh_head" android:layout_width="match_parent" android:layout_height="60dp"> <RelativeLayout android:id="@+id/rly_head_state_1" android:layout_width="match_parent" android:layout_height="match_parent"> <!--下拉但还未到头部的高度--> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="下拉刷新" /> </RelativeLayout> <RelativeLayout android:id="@+id/rly_head_state_2" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible"> <!--下拉且超过了头部的高度,可松开刷新--> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="松开刷新" /> </RelativeLayout> <RelativeLayout android:id="@+id/rly_head_state_3" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible"> <!--正在刷新--> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="正在刷新" /> </RelativeLayout> <RelativeLayout android:id="@+id/rly_head_state_4" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible"> <!--刷新成功--> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="刷新成功" /> </RelativeLayout> </RelativeLayout> <android.support.v7.widget.RecyclerView android:id="@+id/rlv" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never" android:scrollbars="none" /> <RelativeLayout android:id="@+id/rly_refresh_foot" android:layout_width="match_parent" android:layout_height="60dp"> <RelativeLayout android:id="@+id/rly_foot_state_1" android:layout_width="match_parent" android:layout_height="match_parent"> <!--下拉但还未到头部的高度--> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="上拉加载" /> </RelativeLayout> <RelativeLayout android:id="@+id/rly_foot_state_2" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible"> <!--下拉且超过了头部的高度,可松开刷新--> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="松开加载" /> </RelativeLayout> <RelativeLayout android:id="@+id/rly_foot_state_3" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible"> <!--正在加载--> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="正在加载" /> </RelativeLayout> <RelativeLayout android:id="@+id/rly_foot_state_4" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible"> <!--刷新成功--> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="加载成功" /> </RelativeLayout> </RelativeLayout> </RelativeLayout>
最后,有些状态考虑的不必定周全,若是代码在使用的过程当中出现了某些问题,能够在下方评论,也能够给我发邮件:652698011@qq.com