下拉更新已被很多 App 使用,在 iOS 較新的版中已是內建的套件,使用上很方便。那 Android 是否也有呢?有,被新增在 support v4 的支援套件裡面,類別名稱是 SwipeRefreshLayout。
因為最近有用到下拉更新,所以找了一下怎麼製作,基本上不難。它的更新顯示方式不是一般常見的圓形旋轉圖示,而是在最上方以動態的橫條來顯示。在不指定顏色的方式下,預設是黑色的,看起來不太明顯,指定顏色後,還滿繽紛的。
因為最近有用到下拉更新,所以找了一下怎麼製作,基本上不難。它的更新顯示方式不是一般常見的圓形旋轉圖示,而是在最上方以動態的橫條來顯示。在不指定顏色的方式下,預設是黑色的,看起來不太明顯,指定顏色後,還滿繽紛的。
SwipeRefreshLayout 使用說明
SwipeRefreshLayout (之後以 SRL 簡稱) 被設計為執行下拉手勢時更新內容之用。Activity 透過實作 OnRefreshListener 來接收更新通知。當收到更新通知時,使用 setRefreshing(boolean refreshing) 來顯示或取消更新狀態,在"正在更新"狀態下,setRefreshing(true),畫面上方會出現動態的橫條提示,當資料更新完成,使用 setRefreshing(false) 取消後則消失。若要暫時取消"下拉更新手勢"的偵聽,只要呼叫 setEnabled(false) 即可,開啟則呼叫 setEnabled(true),在某些時候必須使用,後面提到的範例中會說明。
重要!
2016/9/19 修正如下:
官方文件的說明是
This layout should be made the parent of the view that will be refreshed as a result of the gesture and can only support one direct child.意思是,SRL 必須是「你想要使用下滑手勢來更新內容的 view 的父層,而且 SRL 只支援一個直接子元件」。
實作 Layout xml
通常我們會用 Graphical Layout 界面拖拉元件來設計畫面,但當你使用 SRL 時,在屬性清單中有些屬性會無法顯示,以拖拉的方式新增元件也會看不到,這在設計複雜的畫面時會很麻煩。我的解決方法是,先建一個 Layout,當成 SRL 的暫時替代品,佔滿全畫面,它之下只會有一個 Layout,也是佔滿全畫面,我們設計的所有元件都是放在這個 Layout 底下。當全部設計完成了,在切換到 xml 文字模式,把最外層的 Layout 的標籤名稱換成
android.support.v4.widget.SwipeRefreshLayout
記得開始及結尾都要換掉,這樣就完成了。
activity_main.xml
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/laySwipe"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/txtTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="#95ea53"
android:padding="10dp"
android:text="Pull to Refresh Demo"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ListView
android:id="@+id/lstData"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/txtTitle" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
接下來在 Activity 中偵聽下拉手勢。
MainActivity.java
public class MainActivity extends Activity {
private SwipeRefreshLayout laySwipe;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
laySwipe = (SwipeRefreshLayout) findViewById(R.id.laySwipe);
laySwipe.setOnRefreshListener(onSwipeToRefresh);
laySwipe.setColorSchemeResources(
android.R.color.holo_red_light,
android.R.color.holo_blue_light,
android.R.color.holo_green_light,
android.R.color.holo_orange_light);
ListView lstData = (ListView) findViewById(R.id.lstData);
lstData.setAdapter(getAdapter());
lstData.setOnScrollListener(onListScroll);
}
private OnRefreshListener onSwipeToRefresh = new OnRefreshListener() {
@Override
public void onRefresh() {
laySwipe.setRefreshing(true);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
laySwipe.setRefreshing(false);
Toast.makeText(getApplicationContext(), "Refresh done!", Toast.LENGTH_SHORT).show();
}
}, 3000);
}
};
private ArrayAdapter<String> getAdapter(){
//fake data
String[] data = new String[20];
int len = data.length;
for (int i = 0; i < len; i++) {
data[i] = Double.toString(Math.random() * 1000);
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1 , data);
return adapter;
}
private OnScrollListener onListScroll = new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (firstVisibleItem == 0) {
laySwipe.setEnabled(true);
}else{
laySwipe.setEnabled(false);
}
}
};
}
程式碼說明:首先,建立一個 SRL 成員變數:
private SwipeRefreshLayout laySwipe;
對 laySwipe 設定更新手勢(即下拉)的偵測:
laySwipe.setOnRefreshListener(onSwipeToRefresh);
private OnRefreshListener onSwipeToRefresh = new OnRefreshListener() {
@Override
public void onRefresh() {
laySwipe.setRefreshing(true);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
laySwipe.setRefreshing(false);
Toast.makeText(getApplicationContext(), "Refresh done!", Toast.LENGTH_SHORT).show();
}
}, 3000);
}
};
當你在螢幕上按住往下滑動,到達一定的距離,就會完成下拉手勢,此時就會觸發 OnRefreshListener 偵聽器的 onRefresh() 方法。在方法的一開始,我們要讓使用者看到現在要開始更新的動作了,因此設定:
laySwipe.setRefreshing(true);
這時螢幕上方會出現更新的橫條動畫。這裡使用 Handler() 來模擬更新,時間為 3 秒。完成後會顯示 Toast 訊息。這裡必須把橫條動畫結束掉:
laySwipe.setRefreshing(false);
到這裡,你已經可以在模擬器中執行,體驗看看下拉更新的效果。為了讓 demo 看起來符合實際需求,範例建立了一些假資料到 ListView 中。另外還有一個可能會遇到的問題,當你的畫面中,不是只有一個 ListView 的時候,例如,此範例故意在 ListView 上面加了一個 TextView。這時候會發生當你只是要捲動 ListView 中的內容,卻觸發了更新。
為了解決這個問題,你必須去偵聽 ListView 的捲動事件,判斷只有當第一個可視項目 (列) 為 0 的時候,表示已經捲到頂了,這時才去偵聽下拉更新手勢。開啟及關閉偵聽下拉手勢的方法:
if (firstVisibleItem == 0) {
laySwipe.setEnabled(true);
}else{
laySwipe.setEnabled(false);
}
到頂時才開啟,不然就關閉。
更新時顯示的動態橫條顏色
laySwipe.setColorSchemeResources(
android.R.color.holo_red_light,
android.R.color.holo_blue_light,
android.R.color.holo_green_light,
android.R.color.holo_orange_light);
如果你沒有指定顏色,預色會是以黑色顯示。可以同時指定 4 種顏色,更新橫條會自動以動畫顯示。這裡取用 Android 內建的顏色。
備註
範例使用的 SDK 版本 (AndroidManifest.xml)<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="21" />
參考資料
- https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html
- http://www.survivingwithandroid.com/2014/05/android-swiperefreshlayout-tutorial.html
本文網址:http://blog.tonycube.com/2014/09/android-swiperefreshlayout-pull-to.html
由 Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀
由 Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀
建議可以加上這些,提醒大家先加在 Java 檔裡面
回覆刪除import android.support.v4.widget.SwipeRefreshLayout;
import android.widget.ListView;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.os.Handler;
import android.widget.Toast;
import android.widget.ArrayAdapter;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AbsListView;
"重要!這個 SRL 必須是整個 layout 的父元件,也就是在 layout xml 中,必須是最上層的,而且只能有一個子元件,也就是說如果要有多個子元作,就要先加入一個 layout,然後才能在其中加入子元件。"這句話是錯的,可以包在其他layout裡面,google應該沒傻到設計出只能包在最外層的layout,太沒彈性了
回覆刪除內容已修改,感謝指正。
刪除請問一下 !要怎麼判斷到頂部才重新整理
回覆刪除條件要怎麼寫
if (firstVisibleItem == 0) {
laySwipe.setEnabled(true);
}else{
laySwipe.setEnabled(false);
}
這個部分不是很懂
你可以把這幾行註解掉試看看,就應該知道它是做什麼的。
刪除原本的 ListView 是可以往上滑或往下滑,
而 laySwipe 是它的父層,所以它也會收到滑動的事件,
而 laySwipe 在收到往下滑的事件時,就會執行「下滑更新」的判斷,
那這樣這個 ListView 將永逺收不到往下滑的事件,因為被 laySwipe 吃掉了,
所以我們把它限制成,當我滑到 ListView 的最上面,
已經沒有項目了,
也就是 firstVisibleItem == 0 (當第一個可見的項目它的索引是 0) 的時候,
我才啟動 laySwipe 的「下滑更新」判斷。
我手機裡面沒有SwipeRefreshLayout, https://www.youtube.com/watch?v=6gNiyhU7h5k ,那白色圓形圖案要怎麼製作呢?觸碰一下就出現。
回覆刪除去手機的設定,開發人員選項中找一下觸碰相關的設定
刪除