Android開發(fā)之ListView列表刷新和加載更多實(shí)現(xiàn)方法
本文實(shí)例講述了Android開發(fā)之ListView列表刷新和加載更多實(shí)現(xiàn)方法。分享給大家供大家參考。具體如下:
上下拉實(shí)現(xiàn)刷新和加載更多的ListView,如下:
package com.sin.android.ui; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; /** * 動(dòng)態(tài)刷新和加載數(shù)據(jù)ListView * @author RobinTang * */ public class DynamicListView extends ListView implements OnScrollListener { /** * 監(jiān)聽(tīng)器 * 監(jiān)聽(tīng)控件的刷新或者加載更多事件 * 所有的條目事件都會(huì)有一個(gè)偏移量,也就是position應(yīng)該減1才是你適配器中的條目 * @author RobinTang * */ public interface DynamicListViewListener { /** * * @param dynamicListView * @param isRefresh 為true的時(shí)候代表的是刷新,為false的時(shí)候代表的是加載更多 * @return true:刷新或者加載更多動(dòng)作完成,刷新或者加載更多的動(dòng)畫自動(dòng)消失 false:刷新或者加載更多為完成,需要在數(shù)據(jù)加載完成之后去調(diào)用控件的doneRefresh()或者doneMore()方法 */ public boolean onRefreshOrMore(DynamicListView dynamicListView, boolean isRefresh); } /** * 狀態(tài)控件(StatusView,列表頭上和底端的)的狀態(tài)枚舉 * @author RobinTang * */ enum RefreshStatus { none, normal, willrefresh, refreshing } /** * 狀態(tài)控件 * @author RobinTang * */ class StatusView extends LinearLayout { public int height; public int width; private ProgressBar progressBar = null; private TextView textView = null; private RefreshStatus refreshStatus = RefreshStatus.none; private String normalString = "下拉刷新"; private String willrefreshString = "松開刷新"; private String refreshingString = "正在刷新"; public StatusView(Context context, AttributeSet attrs) { super(context, attrs); initThis(context); } public StatusView(Context context) { super(context); initThis(context); } private void initThis(Context context) { this.setOrientation(LinearLayout.HORIZONTAL); this.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL); progressBar = new ProgressBar(context); progressBar.setLayoutParams(new LinearLayout.LayoutParams(30, 30)); textView = new TextView(context); textView.setPadding(5, 0, 0, 0); this.addView(progressBar); this.addView(textView); int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); this.measure(w, h); height = this.getMeasuredHeight(); width = this.getMeasuredWidth(); this.setRefreshStatus(RefreshStatus.normal); } public RefreshStatus getRefreshStatus() { return refreshStatus; } public void setRefreshStatus(RefreshStatus refreshStatus) { if (this.refreshStatus != refreshStatus) { this.refreshStatus = refreshStatus; if(refreshStatus == RefreshStatus.refreshing){ this.progressBar.setVisibility(View.VISIBLE); } else{ this.progressBar.setVisibility(View.GONE); } refreshStatusString(); this.invalidate(); } } private void refreshStatusString() { switch (refreshStatus) { case normal: textView.setText(normalString); progressBar.setProgress(0); break; case willrefresh: textView.setText(willrefreshString); break; case refreshing: textView.setText(refreshingString); break; default: break; } } /** * 設(shè)置狀態(tài)字符串 * @param normalString 平時(shí)的字符串 * @param willrefreshString 松開后刷新(或加載)的字符串 * @param refreshingString 正在刷新(或加載)的字符串 */ public void setStatusStrings(String normalString, String willrefreshString, String refreshingString){ this.normalString = normalString; this.willrefreshString = willrefreshString; this.refreshingString = refreshingString; this.refreshStatusString(); } } private StatusView refreshView; private StatusView moreView; private int itemFlag = -1; private boolean isRecorded = false; private int downY = -1; private final float minTimesToRefresh = 1.5f; private final static int ITEM_FLAG_FIRST = 1; private final static int ITEM_FLAG_NONE = 0; private final static int ITEM_FLAG_LAST = -1; // 兩個(gè)監(jiān)聽(tīng)器 private DynamicListViewListener onRefreshListener; private DynamicListViewListener onMoreListener; // 滾動(dòng)到低端的時(shí)候是否自動(dòng)加載更多 private boolean doMoreWhenBottom = false; public DynamicListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initThis(context); } public DynamicListView(Context context, AttributeSet attrs) { super(context, attrs); initThis(context); } public DynamicListView(Context context) { super(context); initThis(context); } private void initThis(Context context) { refreshView = new StatusView(context); moreView = new StatusView(context); refreshView.setStatusStrings("繼續(xù)下拉刷新數(shù)據(jù)...", "松開之后刷新數(shù)據(jù)...", "正在刷新數(shù)據(jù)..."); moreView.setStatusStrings("繼續(xù)上拉加載數(shù)據(jù)...", "松開之后加載數(shù)據(jù)...", "正在加載數(shù)據(jù)..."); this.addHeaderView(refreshView, null, false); this.addFooterView(moreView, null, false); this.setOnScrollListener(this); doneRefresh(); doneMore(); } // 監(jiān)聽(tīng)器操作 public DynamicListViewListener getOnRefreshListener() { return onRefreshListener; } public void setOnRefreshListener(DynamicListViewListener onRefreshListener) { this.onRefreshListener = onRefreshListener; } public DynamicListViewListener getOnMoreListener() { return onMoreListener; } public void setOnMoreListener(DynamicListViewListener onMoreListener) { this.onMoreListener = onMoreListener; } // 設(shè)置 public boolean isDoMoreWhenBottom() { return doMoreWhenBottom; } public void setDoMoreWhenBottom(boolean doMoreWhenBottom) { this.doMoreWhenBottom = doMoreWhenBottom; } @Override public void onScroll(AbsListView l, int t, int oldl, int count) { // log("%d %d %d", t, oldl, count); if (t == 0) itemFlag = ITEM_FLAG_FIRST; else if ((t + oldl) == count){ itemFlag = ITEM_FLAG_LAST; if(doMoreWhenBottom && onMoreListener != null && moreView.getRefreshStatus() != RefreshStatus.refreshing){ doMore(); } } else { itemFlag = ITEM_FLAG_NONE; // isRecorded = false; } } @Override public void onScrollStateChanged(AbsListView arg0, int arg1) { } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: if (isRecorded == false && (itemFlag == ITEM_FLAG_FIRST && onRefreshListener != null && refreshView.getRefreshStatus() == RefreshStatus.normal || itemFlag == ITEM_FLAG_LAST && onMoreListener != null && moreView.getRefreshStatus() == RefreshStatus.normal)) { downY = (int) ev.getY(0); isRecorded = true; // log("按下,記錄:%d flag:%d", downY, itemFlag); } break; case MotionEvent.ACTION_UP: { isRecorded = false; if (onRefreshListener != null && refreshView.getRefreshStatus() == RefreshStatus.willrefresh) { doRefresh(); } else if (refreshView.getRefreshStatus() == RefreshStatus.normal) { refreshView.setPadding(0, -1 * refreshView.height, 0, 0); } if (onMoreListener != null && moreView.getRefreshStatus() == RefreshStatus.willrefresh) { doMore(); } else if (moreView.getRefreshStatus() == RefreshStatus.normal) { moreView.setPadding(0, 0, 0, -1 * moreView.height); } break; } case MotionEvent.ACTION_MOVE: { if (isRecorded == false && (itemFlag == ITEM_FLAG_FIRST && onRefreshListener != null && refreshView.getRefreshStatus() == RefreshStatus.normal || itemFlag == ITEM_FLAG_LAST && onMoreListener != null && moreView.getRefreshStatus() == RefreshStatus.normal)) { downY = (int) ev.getY(0); isRecorded = true; // log("按下,記錄:%d flag:%d", downY, itemFlag); } else if (isRecorded) { int nowY = (int) ev.getY(0); int offset = nowY - downY; if (offset > 0 && itemFlag == ITEM_FLAG_FIRST) { // 下拉 setSelection(0); if (offset >= (minTimesToRefresh * refreshView.height)) { refreshView.setRefreshStatus(RefreshStatus.willrefresh); } else { refreshView.setRefreshStatus(RefreshStatus.normal); } refreshView.setPadding(0, -1 * (refreshView.height - offset), 0, 0); } else if(itemFlag == ITEM_FLAG_LAST){ // 上拉 setSelection(this.getCount()); if (offset <= -1 * (minTimesToRefresh * moreView.height)) { moreView.setRefreshStatus(RefreshStatus.willrefresh); } else { moreView.setRefreshStatus(RefreshStatus.normal); } moreView.setPadding(0, 0, 0, -1 * (moreView.height + offset)); } // log("位移:%d", offset); } break; } default: break; } return super.onTouchEvent(ev); } /** * 開始刷新 */ private void doRefresh(){ // log("開始刷新"); refreshView.setRefreshStatus(RefreshStatus.refreshing); refreshView.setPadding(0, 0, 0, 0); if(onRefreshListener.onRefreshOrMore(this, true)) doneRefresh(); } /** * 開始加載更多 */ private void doMore(){ // log("加載更多"); moreView.setRefreshStatus(RefreshStatus.refreshing); moreView.setPadding(0, 0, 0, 0); if(onMoreListener.onRefreshOrMore(this, false)) doneMore(); } /** * 刷新完成之后調(diào)用,用于取消刷新的動(dòng)畫 */ public void doneRefresh() { // log("刷新完成!"); refreshView.setRefreshStatus(RefreshStatus.normal); refreshView.setPadding(0, -1 * refreshView.height, 0, 0); } /** * 加載更多完成之后調(diào)用,用于取消加載更多的動(dòng)畫 */ public void doneMore() { // log("加載完成!"); moreView.setRefreshStatus(RefreshStatus.normal); moreView.setPadding(0, 0, 0, -1 * moreView.height); } /** * 獲取刷新的狀態(tài) * @return 一般 將要刷新 刷新完成 */ public RefreshStatus getRefreshStatus(){ return refreshView.getRefreshStatus(); } /** * 獲取加載更多的狀態(tài) * @return 一般 將要加載 加載完成 */ public RefreshStatus getMoreStatus(){ return moreView.getRefreshStatus(); } // private void log(Object obj) { // log("%s", obj.toString()); // } // // private void log(String format, Object... args) { // Log.i("DynamicListView", String.format(format, args)); // } }
使用例子:
package com.sin.android.ui; import java.util.ArrayList; import java.util.Date; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Toast; import com.sin.android.ui.DynamicListView.DynamicListViewListener; @SuppressLint("HandlerLeak") public class MainActivity extends Activity implements DynamicListViewListener { DynamicListView listView; ArrayList<String> data; ArrayAdapter<String> adapter; // 用于刷新控件狀態(tài) Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 0) { adapter.notifyDataSetChanged(); listView.doneRefresh(); Toast.makeText(MainActivity.this, "新加載"+msg.arg1+"條數(shù)據(jù)!", Toast.LENGTH_LONG).show(); } else if (msg.what == 1) { adapter.notifyDataSetChanged(); listView.doneMore(); } else { super.handleMessage(msg); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); listView = new DynamicListView(this); setContentView(listView); data = new ArrayList<String>(); for (int i = 1; i < 10; ++i) { data.add("原始數(shù)據(jù)" + i); } adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, data); listView.setAdapter(adapter); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Log.i("",data.get(arg2-1)); } }); listView.setDoMoreWhenBottom(false); // 滾動(dòng)到低端的時(shí)候不自己加載更多 listView.setOnRefreshListener(this); listView.setOnMoreListener(this); } @Override public boolean onRefreshOrMore(DynamicListView dynamicListView, boolean isRefresh) { if (isRefresh) { new Thread(new Runnable() { @Override public void run() { // 刷新 ArrayList<String> temp = new ArrayList<String>(); for (int i = 0; i < 3; ++i) { temp.add(0, new Date().toLocaleString()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (data) { data.addAll(0, temp); } Message message = new Message(); message.what = 0; message.arg1 = temp.size(); handler.sendMessage(message); } }).start(); } else { new Thread(new Runnable() { @Override public void run() { // 加載更多 ArrayList<String> temp = new ArrayList<String>(); for (int i = 0; i < 3; ++i) { temp.add(new Date().toLocaleString()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (data) { data.addAll(temp); } handler.sendEmptyMessage(1); } }).start(); } return false; } }
運(yùn)行截圖如下:
希望本文所述對(duì)大家的Android程序設(shè)計(jì)有所幫助。
相關(guān)文章
Android編程設(shè)計(jì)模式之訪問(wèn)者模式詳解
這篇文章主要介紹了Android編程設(shè)計(jì)模式之訪問(wèn)者模式,詳細(xì)分析了訪問(wèn)者模式的概念、功能、原理、使用場(chǎng)景并結(jié)合實(shí)例形式給出了Android訪問(wèn)者模式的具體實(shí)現(xiàn)技巧與相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2017-12-12Android中解決WebView上下滑動(dòng)監(jiān)聽(tīng)問(wèn)題
本篇文章主要介紹了Android中解決WebView滑動(dòng)監(jiān)聽(tīng)問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04Android Retrofit和Rxjava的網(wǎng)絡(luò)請(qǐng)求
這篇文章主要介紹了Android Retrofit和Rxjava的網(wǎng)絡(luò)請(qǐng)求的相關(guān)資料,需要的朋友可以參考下2017-03-03Android酷炫動(dòng)畫效果之3D星體旋轉(zhuǎn)效果
本文要實(shí)現(xiàn)的3D星體旋轉(zhuǎn)效果是從CoverFlow演繹而來(lái),不過(guò)CoverFlow只是對(duì)圖像進(jìn)行轉(zhuǎn)動(dòng),我這里要實(shí)現(xiàn)的效果是要對(duì)所有的View進(jìn)行類似旋轉(zhuǎn)木馬的轉(zhuǎn)動(dòng)2018-05-05基于Android FileProvider 屬性配置詳解及FileProvider多節(jié)點(diǎn)問(wèn)題
這篇文章主要介紹了基于Android FileProvider 屬性配置詳解及FileProvider多節(jié)點(diǎn)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03Android的TextView與Html相結(jié)合的具體方法
Android的TextView與Html相結(jié)合的具體方法,需要的朋友可以參考一下2013-06-06Android編程實(shí)現(xiàn)圖片拍照剪裁的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)圖片拍照剪裁的方法,涉及Android調(diào)用裁剪工具操作圖片的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-12-12Flutter開發(fā)之設(shè)置應(yīng)用名稱及圖標(biāo)的教程
這篇文章主要介紹了Flutter設(shè)置應(yīng)用名稱及圖標(biāo)的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04