通過SwipeRefreshLayout實現ListView的上拉載入下拉重新整理
上拉重新整理下拉載入相信是在日常的開發中使用的最頻繁的一個元件了,大量資料的展示一定會使用到分頁的功能以提升使用者體驗,目前可以看到的市面上的應用的下拉重新整理也都是配合的SwipeRefreshLayout來實現的,看起來比較美觀,相比自定義的下拉重新整理的動畫效果,這個就顯得比較簡潔大方了。
下面看一下執行效果:
由於ListView沒有提供預設的分頁載入的功能,因此這裡就需要我們自定了,實現起來也是比較簡單的,大致的思路就是:給ListView新增一個FootView用來顯示正在載入的等待動畫,以及滑動到listview最底部的Item的監聽,然後通過回撥將事件的處理交給外部進行。
LoadListView.Java
/**
* Created by 春水碧於天 on 2017/1/29.
*/
public class LoadListView extends ListView implements AbsListView.OnScrollListener {
private int mFootViewHeight;
private View mFootView;
private int LOADSTATE = 0; //載入的狀態
public LoadListView(Context context) {
super (context);
InitFootView(context);
setOnScrollListener(this);
}
public LoadListView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化腳佈局並新增到當前的ListView
InitFootView(context);
setOnScrollListener(this);
}
public LoadListView (Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void InitFootView(Context context) {
mFootView = View.inflate(context, R.layout.foot_load_item, null);
mFootView.measure(0, 0); //測量
mFootViewHeight = mFootView.getMeasuredWidth();
addFooterView(mFootView);
}
//載入完成呼叫隱藏腳佈局,並把mLoadState的狀態設定為0,表示未重新整理狀態
public void setLoadComplete() {
LOADSTATE = 0;
//載入完成後隱藏腳佈局
mFootView.setPadding(0, -mFootViewHeight, 0, 0);
}
//滑動狀態改變的監聽
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/**
* 滑動時一直呼叫
* @param view
* @param firstVisibleItem 當前能看見的第一條item的Id
* @param visibleItemCount 當前能看見的item的總數
* @param totalItemCount 所有的item
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
Log.i("wk","firstVisibleItem: "+firstVisibleItem+"visibleItemCount: "+visibleItemCount+"totalItemCount: "+totalItemCount);
//判斷是否滑動到當前listview的最後一個條目
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
if (LOADSTATE == 0) {
//取消隱藏
mFootView.setPadding(0, 0, 0, 0);
onLoadListener.onLoading();
LOADSTATE = 1; //設定狀態為載入中,放置多次呼叫onLoading
}
}
}
//載入更多的回撥介面
private OnLoadListener onLoadListener;
public void setOnLoadlistener(OnLoadListener onLoadListener) {
this.onLoadListener = onLoadListener;
}
public interface OnLoadListener {
void onLoading();
}
}
這裡記錄一下OnScrollListener中的兩個回撥方法的作用:
1.onScrollStateChanged
//滑動狀態改變的監聽
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
//根據手指離開後的慣性滑動時呼叫
case OnScrollListener.SCROLL_STATE_FLING:
Log.i("wk","慣性滑動");
break;
//滾動停止時呼叫
case OnScrollListener.SCROLL_STATE_IDLE:
Log.i("wk","滾動停止");
break;
//正在滾動時呼叫
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
Log.i("wk","正在滾動");
break;
}
}
這個方法根據第二個引數 scrollState 來決定回撥的次數
2.onScroll
/**
* 滑動時一直呼叫
*
* @param view
* @param firstVisibleItem 當前能看見的第一條item的Id
* @param visibleItemCount 當前能看見的item的總數
* @param totalItemCount 所有的item
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
它在ListView滑動時一直呼叫,通過onScroll中的三個引數,非常精確的描述了ListView的當前狀態
firstVisibleItem 當前能看見的第一條item的Position
visibleItemCount 當前能看見的item的總數(包括沒有完全顯示的條目)
totalItemCount 所有的item
判斷顯示到了最後一行:
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
}
判斷ListView滑動的方向:
private int lastVisibleItem = 0;
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
Log.i("wk","lastVisibleItem=> "+lastVisibleItem+"firstVisibleItem=> "+firstVisibleItem);
if(lastVisibleItem>firstVisibleItem){
Log.i("wk","下滑");
}else if (lastVisibleItem<firstVisibleItem){
Log.i("wk","上滑");
}
lastVisibleItem = firstVisibleItem;
foot_load_item.Java
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal">
<ProgressBar
android:layout_margin="10dp"
android:layout_width="50dp"
android:layout_height="50dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在載入中……"
android:layout_margin="10dp"
android:textSize="20dp"
android:layout_gravity="center"
/>
</LinearLayout>
這樣一個支援上拉載入更多的ListView就實現了。
下面通過配合SwipeRefreshLayout來實現下拉重新整理:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.studyslide.MainActivity">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.studyslide.LoadListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.studyslide.LoadListView>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
MainActivity.Java
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
private LoadListView mListView;
private ArrayList<String> mDatas;
private SwipeRefreshLayout swipeRefreshLayout;
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InitData();
InitUI();
//設定載入顯示的顏色,可以設定顯示多種顏色
swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.RED, Color.GREEN, Color.GRAY);
//設定swipeRefreshLayout的背景顏色
//swipeRefreshLayout.setBackgroundColor(Color.CYAN);
//設定顯示的大小
swipeRefreshLayout.setSize(SwipeRefreshLayout.LARGE);
/*
//設定手指下拉多少出現重新整理
swipeRefreshLayout.setDistanceToTriggerSync(200);
//設定刷新出現的位置
swipeRefreshLayout.setProgressViewEndTarget(false,200);*/
//設定重新整理的監聽
swipeRefreshLayout.setOnRefreshListener(this);
final myAdapter myAdapter = new myAdapter();
/**
* 模擬網路資料載入
*/
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int tag = msg.what;
switch (tag) {
//重新整理
case 0:
for (int i = 0; i < 10; i++) {
mDatas.add(0, "刷新出的資料" + i);
}
swipeRefreshLayout.setRefreshing(false);
myAdapter.notifyDataSetChanged();
break;
//載入更多
case 1:
for (int i = 0; i < 10; i++) {
mDatas.add("加載出的資料" + i);
}
mListView.setLoadComplete();
myAdapter.notifyDataSetChanged();
break;
}
}
};
mListView.setAdapter(myAdapter);
mListView.setOnLoadlistener(new LoadListView.OnLoadListener() {
@Override
public void onLoading() {
Toast.makeText(MainActivity.this, "載入更多", Toast.LENGTH_SHORT).show();
//模擬網路載入資料延遲
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
mHandler.sendEmptyMessage(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
}
}
}).start();
}
});
}
private void InitUI() {
mListView = (LoadListView) findViewById(R.id.listView);
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
}
private void InitData() {
mDatas = new ArrayList<String>();
for (int i = 0; i < 40; i++) {
mDatas.add("這是" + i + "條資料");
}
}
@Override
public void onRefresh() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
mHandler.sendEmptyMessage(0);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
}
}
}).start();
}
//ListView的介面卡
class myAdapter extends BaseAdapter {
@Override
public int getCount() {
return mDatas.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = View.inflate(MainActivity.this, R.layout.item_listview, null);
viewHolder.tv = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tv.setText(mDatas.get(position));
return convertView;
}
final class ViewHolder {
public TextView tv;
}
}
}
下面記錄一下SwipeRefreshLayout的使用:
常用的方法:
setOnRefreshListener(this):新增一個重新整理的監聽
setRefreshing(): 顯示或隱藏重新整理進度條
isRefreshing(): 檢查當前是否處於重新整理狀態
setColorScheme(): 設定進度條的顏色主題,最多能設定四種
swipeRefreshLayout.setBackgroundColor():設定SwipeRefreshLayout 的背景色
swipeRefreshLayout.setSize(SwipeRefreshLayout.LARGE):設定重新整理控制元件顯示大小,預設為small
swipeRefreshLayout.setDistanceToTriggerSync(200):設定手指下拉多少出現重新整理
swipeRefreshLayout.setProgressViewEndTarget(false,200):設定刷新出現的位置
這樣一個可以上拉載入下拉重新整理的ListView就完成了,呵呵,比較樸素的效果實現。