首先先看一下效果图吧==


刷新动画都很熟悉吧...so 本项目并不是刷新控件,而是一个框架,定义了一个标准,可以集成实现自己想要的效果! 源码地址:https://github.com/tohodog/QSRefreshLayout 框架内置4个刷新view CircleImageView 小圆球 BarRefreshView 变色的细条 IOSRefreshView ios上的一款刷新view XMLRefreshView 就是那款经典的上下拉刷新,不过很简陋,有需要的同学可以修改 其他的饿了么京东等均在demo里 一、简介
- 刷新view模块化,可自由更换扩展,head foot可通用
- 轻松实现各种刷新效果,不用自己处理触摸事件
- 支持任意可滑动的控件
- 更多效果更新中...
二、框架使用
##1. XML 可以在xml设置head foot控件
<org.song.refreshlayout.QSRefreshLayout
android:id="@+id/qs"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--放在RecyclerView上面就是head-->
<org.song.refreshlayout.refreshview.CircleImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff" />
<!--foot-->
<org.song.refreshlayout.refreshview.BarRefreshView
android:layout_width="match_parent"
android:layout_height="2dp" />
</org.song.refreshlayout.QSRefreshLayout>
2.JAVA
一些基本的控制
QSRefreshLayout qsRefreshLayout = (QSRefreshLayout) findViewById(R.id.qs);
//qsRefreshLayout.setHeadRefreshView(new CircleImageView(this));
//qsRefreshLayout.setFootRefreshView(new BarRefreshView(this));
//自动进入头部刷新
qsRefreshLayout.enterHeadRefreshing(true);
//监听
qsRefreshLayout.setRefreshListener(new QSRefreshLayout.RefreshListener() {
@Override
public void changeStatus(boolean isHead, int status) {
if (status == QSRefreshLayout.STATUS_REFRESHING) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
qsRefreshLayout.refreshComplete();
}
}, 3000);
}
}
});
//refreshview setting
CircleImageView circleImageView= (CicleImageView) qsRefreshLayout.getHeadRefreshView();
circleImageView.setColorScheme(R.color.xxx,...);
三、如何DIY一个自己的刷新view
需要view实现IRefreshView接口,定义如下
``` View getView();void updateStatus(int status);//更新刷新状态
void updateProgress(float progress);//刷新进度 0 ~ 1(触发刷新)~ 更大
boolean isBringToFront();//是否view放在顶层
float dragRate();//滑动速度控制
int triggerDistance();//触发刷新的距离 [实际触摸距离*dragRate()>triggerDistance() 触发刷新
int maxDistance();//最大滑动距离 <=0不限制
int getThisViewOffset(int offset);//根据触摸位移 确定该view的位移 大于0=headview 小于0=footview
int getTargetOffset(int offset);//根据触摸位移 确定滚动view的位移 大=headview 小于0=footview
int completeAnimaDuration();//完成刷新后到消失的动画时间, <=0使用默认时间
void isHeadView(boolean isHead);//是否顶部刷新view
<h3>下面就来一起实现一个刷新demo</h3>
public class DemoRefreshView extends FrameLayout implements IRefreshView {
private int h;
public DemoRefreshView(@NonNull Context context) {
this(context, null);
}
public DemoRefreshView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
float density = context.getResources().getDisplayMetrics().density;
h = (int) (density * 50);
//todo 如果在xml配置view 则此参数无效 会被xml的参数覆盖
//设置这个控件的大小 目前不支持margin gravity等参数,默认居中
setLayoutParams(new ViewGroup.LayoutParams(h, h));
setBackgroundColor(Color.BLUE);
}
private void init() {
}
public void setH(int h) {
this.h = h;
requestLayout();
}
@Override//确定view大小,你可以在这里强制配置自己的view大小
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//如我的view需要长宽都锁死,不被setLayoutParams所修改
//则可以这样,然后再提供setH(int h)给外部
setMeasuredDimension(h, h);
}
//返回当前view的实例即可
@Override
public View getView() {
return this;
}
/**
* 刷新的状态回调
* 刷新控件共有5种状态
* STATUS_NORMAL = 0;//普通状态
* STATUS_DRAGGING = 1;//手指拖曳时(未到触发距离)
* STATUS_DRAGGING_REACH = 2;//手指拖曳(可以触发刷新的距离)
* STATUS_REFRESHING = 3;//刷新中
* STATUS_REFRESHED = 4;//刷新完成后到view隐藏的这一段状态
* 开发者可以根据状态来设置view
*/
private int status;
@Override
public void updateStatus(int status) {
this.status = status;
switch (status) {
//就只是变下颜色
case QSRefreshLayout.STATUS_DRAGGING_REACH:
setBackgroundColor(Color.RED);
break;
case QSRefreshLayout.STATUS_REFRESHING:
setBackgroundColor(Color.GREEN);
break;
case QSRefreshLayout.STATUS_DRAGGING:
case QSRefreshLayout.STATUS_REFRESHED:
case QSRefreshLayout.STATUS_NORMAL:
setBackgroundColor(Color.BLUE);
break;
}
}
/**
* 刷新的进度
* 刷新进度 0 ~ 1(触发刷新)~ 更大
* 一些特效动画就可以根据这个值来更新状态
*/
@Override
public void updateProgress(float progress) {
//不是拖曳状态忽略
if (status != QSRefreshLayout.STATUS_DRAGGING && status != QSRefreshLayout.STATUS_DRAGGING_REACH)
return;
if (progress > 1)
progress = 1;
//这里就实现一个颜色渐变吧
int startColor = Color.BLUE;
int a1 = (startColor >> 24) & 0x000000FF;
int r1 = (startColor >> 16) & 0x000000FF;
int g1 = (startColor >> 8) & 0x000000FF;
int b1 = startColor & 0x000000FF;
int endColor = Color.RED;
int a2 = (endColor >> 24) & 0x000000FF;
int r2 = (endColor >> 16) & 0x000000FF;
int g2 = (endColor >> 8) & 0x000000FF;
int b2 = endColor & 0x000000FF;
int r = (int) (r1 + (r2 - r1) * progress);
int g = (int) (g1 + (g2 - g1) * progress);
int b = (int) (b1 + (b2 - b1) * progress);
int a = (int) (a1 + (a2 - a1) * progress);
int newColor = Color.argb(a, r, g, b);
setBackgroundColor(newColor);
}
/**
* 是否view在顶层
* 比如饿了么刷新就需要在底层 返回false
* 谷歌的小圆球刷新就需要在顶层 返回true
*/
@Override
public boolean isBringToFront() {
return false;//显示在目标的下方
}
/**
* 控制拖曳的速率
* 比如返回.5f,手指拖动100像素,本框架会认为是50像素
*/
@Override
public float dragRate() {
return .5f;
}
/**
* 触发刷新的距离
*/
@Override
public int triggerDistance() {
return getMeasuredHeight();//触发距离为本view的高度
}
/**
* 最大拖动的距离
* <=0不限制
*/
@Override
public int maxDistance() {
return 0;//不限制
}
/**
* 根据触摸位移 确定该view的位移
*
* @param offset 当前的拖动距离(实际触摸距离*dragRate()), headview大于0, footview小于0
* @return 返回这个view的移动值 这个值将会确定view的位置
*/
@Override
public int getThisViewOffset(int offset) {
//这里我们实现一个视差移动
offset = Math.abs(offset);
int t = triggerDistance();
int i;
if (offset > t)
i = offset;
else
i = t / 2 + offset / 2;
return isHead ? i : -i;//顶部和底部view 移动值是相反的
}
/**
* 根据触摸位移 确定目标view的位移
*
* @param offset 当前的拖动距离(实际触摸距离*dragRate()), headview大于0, footview小于0
* @return 返回目标view(就是listview, 等)的移动值 这个值将会确定view的位置
* 这个返回值一般要么是
* 0不会动
* offset 原值返回
*/
@Override
public int getTargetOffset(int offset) {
return offset;//返回原值,会跟随手指而移动
}
/**
* 完成刷新后到消失的动画时间, <=0使用默认时间300ms
* 如果有一些动画刷新完成后执行时间较长或需要调慢 可以这里返回时间ms
* (BarRefreshView使用了)
*/
@Override
public int completeAnimaDuration() {
return 0;
}
private boolean isHead;
//标记这个view是拿去做head还是foot,用变量记录下来,也可以在这里实现一些初始化
@Override
public void isHeadView(boolean isHead) {
this.isHead = isHead;
}
}
运行效果如下,recycle设置半透明了,方便看效果
