Android智慧下拉重新整理框架-SmartRefreshLayout
框架?下拉重新整理控制元件還能框架化?智慧又怎麼回事?二話不多少先上Demo效果圖,咱們再來探個究竟。
Github 傳送門
注意:本文僅僅是部落格文章,主要用於專案介紹和宣傳,由於釋出時間關係,部分內容已經過期,詳細使用文件請跳轉 github
Demo
如果手機上看不到圖片,可以嘗試
- 點選瀏覽器檢視
- 使用電腦瀏覽
專案演示
風格演示
框架
如果你看完了效果圖,或許框架的意思應該有所瞭解了~~SmartRefreshLayout對下拉重新整理功能進行系統的拆分、組合,主要由四個部分組成:
- RefreshLayout 下拉的基本功能,包括佈局測量、滑動事件處理、引數設定等等
- RefreshContent 對不同內容的統一封裝,包括判斷是否可滾動、回彈判斷、智慧識別
- RefreshHeader 下拉頭部的實現和顯示
- RefreshFooter 上拉底部的實現和顯示
下面是UML關係類圖
通過SmartRefreshLayout框架,你可以在一個穩定強大的下拉布局中實現自己專案需求的 Header ,不用去關心滑動事件處理,不用關心子控制元件的回彈和滾動邊界,只需關注自己真正的專案需求Header的樣子和動畫。
特點
這時你會問:網上其他的開源下拉控制元件一樣的可以自定義 Header 和 Footer ,SmartRefreshLayout 和它們比起來有什麼優勢?
變換方式
- Translate 平行移動 特點: 最常見,HeaderView高度不會改變,
- Scale 拉伸形變 特點:在下拉和上彈(HeaderView高度改變)時候,會自動觸發OnDraw事件
- FixedFront 固定在前面 特點:不會上下移動,HeaderView高度不會改變
- FixedBehind 固定在後面 特點:不會上下移動,HeaderView高度不會改變(類似微信瀏覽器效果)
- Screen 全螢幕 特點:固定在前面,尺寸充滿整個佈局
SmartRefreshLayout 的Header和Footer都有多種變換方式,適應不同風格的 Header 和 Footer,下面是不同變換方式Header的Demo
FixedBehind 固定在後面 和 Scale 拉伸形變
Screen 全螢幕 和 Translate 平行移動
獨立事件
Header和Footer 可以獨立的處理手指滑動事件來為動畫提供操作指令,也可以使用RefreshLayout的核心介面來完成一些不尋常的操作指令。
下面的打磚塊 Header中 ,Header可以獨立的使用滑動事件來為遊戲擋板提供指令,並同時可以呼叫核心介面來通知RefreshLayout上下滾動列表
智慧
智慧是什麼玩意?有什麼用?智慧主要體現 SmartRefreshLayout 對未知佈局的自動識別上,這樣可以讓我們更高效的實現我們所需的功能,也可以實現一些非尋常的功能。下面通過自定義Header 和 巢狀Layout作為內容 來解釋 SmartRefreshLayout 的智慧之處。
自定義Header
我們來看這一下這個虛擬碼例子:
<SmartRefreshLayout>
<ClassicsHeader/>
<TextView/>
<ClassicsFooter/>
</SmartRefreshLayout>
在Android Studio 中的預覽效果圖
對比程式碼和我們預想的一樣,那我們來對程式碼做一些改動,ClassicsHeader換成一個簡單的TextView,看看會發生什麼?
<SmartRefreshLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:background="#444"
android:textColor="#fff"
android:text="看看我會不會變成Header"/>
<TextView/>
<ClassicsFooter/>
</SmartRefreshLayout>
在Android Studio 中的預覽效果圖 和 執行效果圖
這時發現我們我們替換的 TextView 自動就變成了Header,只是它還不會動。要動起來?那麼太簡單啦,網上隨便一搜索就一大堆的 gif 。如這裡:拖拖拖 ~~垃機C4D,類似的我們還可以找到很多,又如:環遊東京30天:GIF版旅行指南
接著我們來改程式碼:
compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.3'//一個開源gif控制元件
<SmartRefreshLayout>
<pl.droidsonroids.gif.GifImageView
android:layout_width="match_parent"
android:layout_height="150dp"
android:scaleType="centerCrop"
android:src="@mipmap/gif_header_repast"/>
<ListView/>
<ClassicsFooter/>
</SmartRefreshLayout>
在 Android Studio 中的預覽效果圖 和 執行效果圖
哈哈!一行Java程式碼都不用寫,就完成了一個自定義的Header
巢狀Layout作為內容
如果boos要求在列表的前面固定一個廣告條怎麼辦?這好辦呀,一般我們會開開心心的下下這樣的程式碼:
<LinearLayout
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:text="我就是boos要求加上的廣告條啦"/>
<SmartRefreshLayout>
<ListView/>
</SmartRefreshLayout>
</LinearLayout>
但是在執行下拉重新整理的時候,我們發現 Header是在廣告條之下的,看著會彆扭~,其實我們可以試試另一種方式,把廣告條寫到 RefreshLayout內部,看看會發生什麼?
<SmartRefreshLayout>
<LinearLayout
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:text="我就是boos要求加上的廣告條啦"/>
<ListView/>
</LinearLayout>
</SmartRefreshLayout>
由於虛擬碼過於簡單,而且執行效果過於醜陋,這裡還是貼出在實際專案中的實際情況吧~
我們注意看右邊的圖,仔細觀察手指觸控的位置和下拉效果。可以看到在列表已經滾動到中部時,輕微下拉列表是不會觸發重新整理的,但是如果是觸控固定的佈局,則可以觸發下拉。從這裡可以看出 SmartRefreshLayout 對滾動邊界的判斷是動態的,智慧的!當然如果 SmartRefreshLayout 的智慧還是不能滿足你,可以通過 setListener 自己實現滾動邊界的判斷,更為準確!
功能
簡單的介紹了兩大特點框架和智慧,接下來也說說SmartRefreshLayout還具有的其他常用功能吧~
- 支援所有的 View(AbsListView、RecyclerView、WebView….View) 和多層巢狀的 Layout
- 支援自定義並且已經集成了很多炫酷的 Header 和 Footer
- 支援和ListView的同步滾動 和 RecyclerView、AppBarLayout、CoordinatorLayout 的巢狀滾動 NestedScrolling.
- 支援在Android Studio Xml 編輯器中預覽 效果
- 支援分別在 Default(預設)、Xml、JavaCode 等三個地方設定 Header 和 Footer.
- 支援自動重新整理、自動上拉載入(自動檢測列表滾動到底部,而不用手動上拉).
- 支援通用的重新整理監聽器 OnRefreshListener 和更詳細的滾動監聽 OnMultiPurposeListener.
- 支援自定義回彈動畫的插值器,實現各種炫酷的動畫效果.
- 支援設定主題來適配任何場景的App,不會出現炫酷但很尷尬的情況.
- 支援設定多種滑動方式來適配各種效果的Header和Footer:位置平移、尺寸拉伸、背後固定、頂層固定、全屏
- 支援內容尺寸自適應 Content-wrap_content
- 支援繼承重寫和擴充套件功能,內部實現沒有 private 方法和欄位,繼承之後都可以重寫覆蓋
- 支援越界回彈(Listview、RecyclerView、ScrollView、WebView…View)
使用
簡單用例
1.在 buld.gradle 中新增依賴
compile 'com.android.support:appcompat-v7:25.3.1'//版本隨意
compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.0.4'
compile 'com.scwang.smartrefresh:SmartRefreshHeader:1.0.4'//沒有使用特殊Header,可以不加這行
2.在XML佈局檔案中新增 SmartRefreshLayout
<?xml version="1.0" encoding="utf-8"?>
<com.scwang.smartrefresh.layout.SmartRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:background="#fff" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
3.在 Activity 或者 Fragment 中新增程式碼
RefreshLayout refreshLayout = (RefreshLayout)findViewById(R.id.refreshLayout);
refreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshlayout) {
refreshlayout.finishRefresh(2000);
}
});
refreshLayout.setOnLoadmoreListener(new OnLoadmoreListener() {
@Override
public void onLoadmore(RefreshLayout refreshlayout) {
refreshlayout.finishLoadmore(2000);
}
});
使用指定的 Header 和 Footer
1.方法一 全域性設定
public class App extends Application {
static {//static 程式碼段可以防止記憶體洩露
//設定全域性的Header構建器
SmartRefreshLayout.setDefaultRefreshHeaderCreater(new DefaultRefreshHeaderCreater() {
@Override
public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {
layout.setPrimaryColorsId(R.color.colorPrimary, android.R.color.white);//全域性設定主題顏色
return new ClassicsHeader(context).setSpinnerStyle(SpinnerStyle.Translate);//指定為經典Header,預設是 貝塞爾雷達Header
}
});
//設定全域性的Footer構建器
SmartRefreshLayout.setDefaultRefreshFooterCreater(new DefaultRefreshFooterCreater() {
@Override
public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) {
//指定為經典Footer,預設是 BallPulseFooter
return new ClassicsFooter(context).setSpinnerStyle(SpinnerStyle.Translate);
}
});
}
}
注意:方法一 設定的Header和Footer的優先順序是最低的,如果同時還使用了方法二、三,將會被其他方法取代
2.方法二 XML佈局檔案指定
<com.scwang.smartrefresh.layout.SmartRefreshLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/smartLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#444444"
app:srlPrimaryColor="#444444"
app:srlAccentColor="@android:color/white"
app:srlEnablePreviewInEditMode="true">
<!--srlAccentColor srlPrimaryColor 將會改變 Header 和 Footer 的主題顏色-->
<!--srlEnablePreviewInEditMode 可以開啟和關閉預覽功能-->
<com.scwang.smartrefresh.layout.header.ClassicsHeader
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/padding_common"
android:background="@android:color/white"
android:text="@string/description_define_in_xml"/>
<com.scwang.smartrefresh.layout.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
注意:方法二 XML設定的Header和Footer的優先順序是中等的,會被方法三覆蓋。而且使用本方法的時候,Android Studio 會有預覽效果,如下圖:
不過不用擔心,只是預覽效果,執行的時候只有下拉才會出現~
3.方法三 Java程式碼設定
final RefreshLayout refreshLayout = (RefreshLayout) findViewById(R.id.smartLayout);
//設定 Header 為 Material風格
refreshLayout.setRefreshHeader(new MaterialHeader(this).setShowBezierWave(true));
//設定 Footer 為 球脈衝
refreshLayout.setRefreshFooter(new BallPulseFooter(this).setSpinnerStyle(SpinnerStyle.Scale));