一個簡潔而不簡單的安卓上下拉重新整理框架
阿新 • • 發佈:2019-01-28
首先先看一下效果圖吧==
重新整理動畫都很熟悉吧…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">
<!--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
一個詳細的demo實現
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設定半透明瞭,方便看效果