Android開發筆記(一百二十三)下拉重新整理佈局SwipeRefreshLayout
SwipeRefreshLayout
下拉重新整理佈局SwipeRefreshLayout是Android又一與時俱進的控制元件,顧名思義它隨著使用者手勢向下滑動就會觸發重新整理操作。從實際的下拉效果來看,SwipeRefreshLayout秉承了Android一貫的簡潔介面,可定製性並不太好,遠不如開源的下拉重新整理框架PullToRefresh,但畢竟是原生的控制元件,用起來比較方便,所以我們還是好好了解了解它。SwipeRefreshLayout最早在19.1的support-v4庫中引入,所以要先確保sdk的“Android Support Library”版本不低於19.1。另外,SwipeRefreshLayout的原始碼多次升級,因此有新版與舊版之分,兩版之間不但支援的方法有區別,而且介面效果也有差異。
下面是SwipeRefreshLayout的常用方法說明:
setColorScheme : 設定進度條/圓圈的顏色。(該方法在新版中已被廢棄)
setOnRefreshListener : 設定重新整理監聽器。在下拉鬆開時觸發該監聽器,需要重寫該監聽器的onRefresh方法。
setRefreshing : 設定重新整理的狀態。true表示正在重新整理,false表示結束重新整理。
isRefreshing : 判斷是否正在重新整理。
下面是新版增加的方法說明:
setColorSchemeColors : 設定進度圓圈的圓環顏色。
setProgressBackgroundColorSchemeColor : 設定進度圓圈的背景顏色。
setProgressViewOffset : 設定進度圓圈的偏移量。第一個參數列示進度圈是否縮放,第二個參數列示進度圈開始出現時距頂端的偏移,第三個參數列示進度圈拉到最大時距頂端的偏移。
setDistanceToTriggerSync : 設定手勢向下滑動多少距離才會觸發重新整理操作。
SwipeRefreshLayout的舊版與新版之間的介面區別主要有:
1、舊版的進度條是佈局頂部的一條橫線,而新版的佈局頂部的一個圓圈。
2、舊版在下拉時,進度條不動,頁面會隨著向下滑動;而新版在下拉時,頁面不再向下滑動,進度圓圈會向下滑動。
這兩種顯示效果各有千秋,開發者可按照個人喜好決定採用哪種效果。需要注意的是,想要舊版的效果,就得使用舊版的android-support-v4.jar;想要新版的效果,就得使用新版的android-support-v4.jar。新舊兩版的v4包見本文末尾的程式碼工程。
下面是舊版SwipeRefreshLayout的下拉重新整理效果截圖:
下面是新版SwipeRefreshLayout的下拉重新整理效果截圖:
下面是簡單下拉重新整理的示例程式碼(新舊版通用,只需更換v4包即可):
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.widget.TextView;
public class SimpleActivity extends Activity implements OnRefreshListener {
private TextView tv_simple;
private SwipeRefreshLayout srl_simple;
private Handler mHandler = new Handler();
@SuppressLint("ResourceAsColor")
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
tv_simple = (TextView) findViewById(R.id.tv_simple);
srl_simple = (SwipeRefreshLayout) findViewById(R.id.srl_simple);
srl_simple.setOnRefreshListener(this);
//舊版用下面的setColorScheme設定進度條顏色
srl_simple.setColorScheme(R.color.red, R.color.orange, R.color.green, R.color.blue);
//新版用下面的setColorSchemeResources設定進度圓圈顏色
// srl_simple.setColorSchemeResources(
// R.color.red, R.color.orange, R.color.green, R.color.blue );
//舊版v4包中無下面三個方法
// srl_simple.setProgressBackgroundColorSchemeResource(R.color.black);
// srl_simple.setProgressViewOffset(true, 0, 50);
// srl_simple.setDistanceToTriggerSync(100);
}
@Override
public void onRefresh() {
tv_simple.setText("正在重新整理");
mHandler.postDelayed(mRefresh, 3000);
}
private Runnable mRefresh = new Runnable() {
@Override
public void run() {
tv_simple.setText("重新整理完成");
srl_simple.setRefreshing(false);
}
};
}
SwipeRefreshLayout+ListView下拉重新整理
SwipeRefreshLayout搭配ListView可實現簡單的列表資料下拉重新整理。首先要注意:在佈局檔案中,android.support.v4.widget.SwipeRefreshLayout下面只能有一個直接子檢視,如果有多個子檢視,那麼將只展示第一個子檢視,後面的子檢視將不予展示。如下面這種寫法,只會展示名為tv_listview的TextView資料,而不會展示名為lv_content的ListView資料。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/srl_listview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/tv_listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="10dp"
android:textColor="#000000"
android:textSize="17sp"
android:visibility="gone" />
<ListView
android:id="@+id/lv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
下面這個才是正確的寫法:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/srl_listview"
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/tv_listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingBottom="10dp"
android:textColor="#000000"
android:textSize="17sp"
android:visibility="gone" />
<ListView
android:id="@+id/lv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
SwipeRefreshLayout自帶的重新整理提示只有一個進度圓圈,顯然不能滿足多變的定製化需求,比如我們常常需要展示不同的提示文字和提示圖片,這時就要在ListView控制元件上面增加一塊提示區域,用來存放個性化的提示內容。這裡我們先在提示區域放置一個TextView控制元件,用來展示最基本的提示文字,在重新整理開始時顯示該提示,重新整理結束時移除該提示。
下面是SwipeRefreshLayout+ListView的下拉重新整理效果截圖:
下面是SwipeRefreshLayout+ListView的頁面程式碼示例:
import com.example.exmswipe.adapter.TitleListAdapter;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
public class ListviewActivity extends Activity implements OnRefreshListener {
private TextView tv_listview;
private SwipeRefreshLayout srl_listview;
private Handler mHandler = new Handler();
private ListView lv_content;
private String[] yearArray = {"鼠年", "牛年", "虎年", "兔年", "龍年", "蛇年",
"馬年", "羊年", "猴年", "雞年", "狗年", "豬年"};
private void refreshView() {
TitleListAdapter adapter = new TitleListAdapter(this, yearArray);
lv_content.setAdapter(adapter);
lv_content.setOnItemClickListener(adapter);
lv_content.setOnItemLongClickListener(adapter);
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listview);
tv_listview = (TextView) findViewById(R.id.tv_listview);
srl_listview = (SwipeRefreshLayout) findViewById(R.id.srl_listview);
srl_listview.setOnRefreshListener(this);
//舊版用下面的setColorScheme設定進度條顏色
srl_listview.setColorScheme(R.color.red, R.color.orange, R.color.green, R.color.blue);
//新版用下面的setColorSchemeResources設定進度圓圈顏色
// srl_listview.setColorSchemeResources(
// R.color.red, R.color.orange, R.color.green, R.color.blue );
lv_content = (ListView) findViewById(R.id.lv_content);
refreshView();
}
@Override
public void onRefresh() {
tv_listview.setVisibility(View.VISIBLE);
tv_listview.setText("正在重新整理");
mHandler.postDelayed(mRefresh, 3000);
}
private Runnable mRefresh = new Runnable() {
@Override
public void run() {
refreshView();
tv_listview.setText("重新整理完成");
srl_listview.setRefreshing(false);
mHandler.postDelayed(mComplete, 500);
}
};
private Runnable mComplete = new Runnable() {
@Override
public void run() {
tv_listview.setVisibility(View.GONE);
}
};
}
SwipeRefreshLayout+RecyclerView下拉重新整理
看過了搭配ListView的下拉重新整理,再來看看搭配RecyclerView會是什麼效果。上面我們看到搭配ListView的情況下,在重新整理開始與重新整理結束時,提示文字的展示與隱藏過程有點突兀,都是一下子展示和一下子隱藏,缺乏動畫效果,使人覺得生硬呆板。那麼搭配RecyclerView進行下拉重新整理有沒有辦法改善這種情況呢?下面是SwipeRefreshLayout+RecyclerView的下拉重新整理效果截圖:
從上面截圖可以發現,提示文字的出現和消失都伴隨著動畫,整體效果顯得柔和許多,而這有賴於RecyclerView的區域性更新特性。複習一下前篇博文《Android開發筆記(一百二十二)迴圈器檢視RecyclerView》,當時我們提到RecyclerView的幾個方法,卻沒有實際運用的例子,現在正好派上用場了。它們是:
1、RecyclerView.Adapter的notify相關方法,如notifyItemInserted、notifyItemRemoved、notifyItemChanged,用於在個別專案發生變化時單獨通知介面卡調整。
2、GridLayoutManager的setSpanSizeLookup方法,對於第一個元素,可指定讓它佔滿第一行作為頭部區域,從而把提示區域納入整個列表檢視的統一管理。
3、GridLayoutManager的setLayoutManager方法,在佈局管理資訊發生變化時,隨時呼叫該方法生效最新的佈局配置,這樣列表項的增刪操作就能顯示動畫效果。
下面是SwipeRefreshLayout+RecyclerView的頁面程式碼示例:
import java.util.LinkedList;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import com.example.exmswipe.adapter.RecyclerAdapter;
public class RecyclerActivity extends Activity implements OnRefreshListener {
private SwipeRefreshLayout srl_recycler;
private Handler mHandler = new Handler();
private int mColumnCount = 3;
private RecyclerView rv_content;
private GridLayoutManager mLayoutManager;
private RecyclerAdapter mAdapter;
private String[] yearArray = {"鼠年", "牛年", "虎年", "兔年", "龍年", "蛇年",
"馬年", "羊年", "猴年", "雞年", "狗年", "豬年"};
private LinkedList<String> mYearList = new LinkedList<String>();
private void refreshView() {
mAdapter = new RecyclerAdapter(this, 2, mYearList);
rv_content.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(mAdapter);
mAdapter.setOnItemLongClickListener(mAdapter);
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
srl_recycler = (SwipeRefreshLayout) findViewById(R.id.srl_recycler);
srl_recycler.setOnRefreshListener(this);
//舊版用下面的setColorScheme設定進度條顏色
srl_recycler.setColorScheme(R.color.red, R.color.orange, R.color.green, R.color.blue);
//新版用下面的setColorSchemeResources設定進度圓圈顏色
// srl_recycler.setColorSchemeResources(
// R.color.red, R.color.orange, R.color.green, R.color.blue );
rv_content = (RecyclerView) findViewById(R.id.rv_content);
mLayoutManager = new GridLayoutManager(this, mColumnCount);
mLayoutManager.setSpanSizeLookup(new MySpanRule(-1));
rv_content.setLayoutManager(mLayoutManager);
for (int i=0; i<yearArray.length; i++) {
mYearList.add(yearArray[i]);
}
refreshView();
}
@Override
public void onRefresh() {
mYearList.addFirst("正在重新整理");
mAdapter.notifyItemInserted(0);
mLayoutManager.setSpanSizeLookup(new MySpanRule(0));
rv_content.setLayoutManager(mLayoutManager);
mHandler.postDelayed(mRefresh, 3000);
}
private Runnable mRefresh = new Runnable() {
@Override
public void run() {
mYearList.set(0, "重新整理完成");
mAdapter.notifyItemChanged(0);
srl_recycler.setRefreshing(false);
mHandler.postDelayed(mComplete, 500);
}
};
private Runnable mComplete = new Runnable() {
@Override
public void run() {
mYearList.removeFirst();
mAdapter.notifyItemRemoved(0);
mLayoutManager.setSpanSizeLookup(new MySpanRule(-1));
rv_content.setLayoutManager(mLayoutManager);
}
};
private class MySpanRule extends GridLayoutManager.SpanSizeLookup {
private int mPosition;
public MySpanRule(int position) {
mPosition = position;
}
@Override
public int getSpanSize(int position) {
if (mPosition == -1) {
return 1;
} else if (position == mPosition) {
return mColumnCount;
} else {
return 1;
}
}
}
}
SwipeRefreshLayout實現上拉載入
SwipeRefreshLayout預設只實現下拉重新整理功能,沒有上拉載入功能;如果我們要用它來做上拉載入,就得想辦法自定義控制元件了。從網上資料來看,大家給SwipeRefreshLayout新增上拉載入主要有兩種思路:1、重寫SwipeRefreshLayout,在dispatchTouchEvent方法中捕獲上拉事件,並進行合理性校驗之後,觸發上拉載入操作。
2、呼叫RecyclerView的setOnTouchListener方法,並實現一個觸控監聽器傳給該方法,監聽器中也是一樣捕獲上拉事件並進行後續處理。但是該方法不能與SwipeRefreshLayout直接共存,因為SwipeRefreshLayout與ScrollView一樣,都會自動攔截上下滑動的手勢,如此一來,上下滑動事件都被SwipeRefreshLayout先攔截了,哪裡還會傳給下面的RecyclerView呢?所以要麼只用RecyclerView不用SwipeRefreshLayout,要麼就是重寫SwipeRefreshLayout讓它放過上拉事件。
上面兩種思路都有對應的實現程式碼,可是我覺得,SwipeRefreshLayout作為Android的原生控制元件,就應該讓它去做它擅長的事情。如果要它實現上拉載入還得大動干戈的話,不如直接使用下拉重新整理的開源框架PullToRefresh,因為PullToRefresh能夠實現的功能更加強大,如果都要大費周章,為什麼我們不用更好的呢?所以我以為上拉載入功能最好還是用PullToRefresh,有關PullToRefresh的詳細介紹參見《Android開發筆記(十二)測量尺寸與下拉重新整理》。
點選下載本文用到的下拉重新整理的工程程式碼
點此檢視Android開發筆記的完整目錄
相關文章
- Android開發之SwipeRefreshLayout實現下拉重新整理Android
- android筆記二(水平佈局與垂直佈局)Android筆記
- Android開發筆記(一百二十)兩種側滑佈局Android筆記
- Android 程式設計下如何調整 SwipeRefreshLayout 的下拉重新整理距離Android程式設計
- 直播平臺製作,SwipeRefreshLayout下拉重新整理的用法
- 超簡單!原生SwipeRefreshLayout實現首頁下拉重新整理
- Android開發之常用佈局Android
- flex佈局筆記Flex筆記
- 寫給 Android 開發的小程式佈局指南,Flex 佈局!AndroidFlex
- iOS 全屏佈局筆記iOS筆記
- android開發(3):列表listview的實現 | 下拉重新整理AndroidView
- 【安卓筆記】RecyclerView+SwipeRefreshLayout示例安卓筆記View
- SwipeRefreshLayout,用最少的程式碼定製最美的上下拉重新整理樣式
- Flex佈局學習筆記Flex筆記
- 阿里Android開發規範:UI 與佈局阿里AndroidUI
- Android開發 - 檢視佈局屬性解析Android
- java開發俄羅斯方塊學習筆記 Day-6 佈局Java筆記
- Android開發筆記Android筆記
- Xamarin 學習筆記 - Layout(佈局)筆記
- CSS學習筆記:flex佈局CSS筆記Flex
- Android SwipeRefreshLayout教程Android
- 【安卓筆記】下拉重新整理元件的使用及實現安卓筆記元件
- Android個人開發筆記Android筆記
- Windows phone應用開發[18]-下拉重新整理Windows
- Android 佈局Android
- Ext學習筆記11-佈局筆記
- 寒假小軟體開發記錄02--佈局
- Android學習筆記之檔案分類和線性佈局Android筆記
- 前端開發常見佈局前端
- Android 開發學習筆記Android筆記
- 移動 WEB 開發的佈局方式 ---- 響應式佈局Web
- [筆記]關於blade佈局的使用筆記
- flutter 學習筆記-容器與佈局(1)Flutter筆記
- 原生 CSS 網格佈局學習筆記CSS筆記
- 原生CSS網格佈局學習筆記CSS筆記
- 學習筆記|AS入門(三) 佈局篇筆記
- Android佈局概述Android
- Android xml 佈局AndroidXML