Android開發(fā)之ListView列表刷新和加載更多實現(xiàn)方法
本文實例講述了Android開發(fā)之ListView列表刷新和加載更多實現(xiàn)方法。分享給大家供大家參考。具體如下:
上下拉實現(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;
/**
* 動態(tài)刷新和加載數(shù)據(jù)ListView
* @author RobinTang
*
*/
public class DynamicListView extends ListView implements OnScrollListener {
/**
* 監(jiān)聽器
* 監(jiān)聽控件的刷新或者加載更多事件
* 所有的條目事件都會有一個偏移量,也就是position應(yīng)該減1才是你適配器中的條目
* @author RobinTang
*
*/
public interface DynamicListViewListener {
/**
*
* @param dynamicListView
* @param isRefresh 為true的時候代表的是刷新,為false的時候代表的是加載更多
* @return true:刷新或者加載更多動作完成,刷新或者加載更多的動畫自動消失 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 平時的字符串
* @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;
// 兩個監(jiān)聽器
private DynamicListViewListener onRefreshListener;
private DynamicListViewListener onMoreListener;
// 滾動到低端的時候是否自動加載更多
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)聽器操作
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)用,用于取消刷新的動畫
*/
public void doneRefresh() {
// log("刷新完成!");
refreshView.setRefreshStatus(RefreshStatus.normal);
refreshView.setPadding(0, -1 * refreshView.height, 0, 0);
}
/**
* 加載更多完成之后調(diào)用,用于取消加載更多的動畫
*/
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); // 滾動到低端的時候不自己加載更多
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;
}
}
運行截圖如下:




希望本文所述對大家的Android程序設(shè)計有所幫助。
相關(guān)文章
Android中解決WebView上下滑動監(jiān)聽問題
本篇文章主要介紹了Android中解決WebView滑動監(jiān)聽問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04
Android Retrofit和Rxjava的網(wǎng)絡(luò)請求
這篇文章主要介紹了Android Retrofit和Rxjava的網(wǎng)絡(luò)請求的相關(guān)資料,需要的朋友可以參考下2017-03-03
基于Android FileProvider 屬性配置詳解及FileProvider多節(jié)點問題
這篇文章主要介紹了基于Android FileProvider 屬性配置詳解及FileProvider多節(jié)點問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android的TextView與Html相結(jié)合的具體方法
Android的TextView與Html相結(jié)合的具體方法,需要的朋友可以參考一下2013-06-06
Flutter開發(fā)之設(shè)置應(yīng)用名稱及圖標的教程
這篇文章主要介紹了Flutter設(shè)置應(yīng)用名稱及圖標的方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04

