如今網上關於封裝ListView,實現載入更多和下拉重新整理的文章已經鋪天蓋地的了,基本都是通過addHeaderView()和addFooterView(),設定下拉頭和上拉底部,然後通過OnScrollListener監聽器的onScroll方法中判斷是否滑動到底部。
判斷滑動到底部還是頭部:
if (firstVisibleItem == 0) {
Log.i("ListView", "滾動到頂部");
} else if ((firstVisibleItem + visibleItemCount) == totalItemCount) {
Log.i("ListView", "滾動到底部");
}
複製程式碼
理論都是萬變不離其宗。
這是我封裝之後得到的效果圖。
以下是封裝控制元件的實現。
public class LoadMoreListView extends ListView {
private RelativeLayout mFooterView;
private LinearLayout layout;
private ProgressBar progressBar;
private TextView textView;
private boolean mIsLoadingMore = false;
private boolean mHasMore = true;
private LoadMoreListener loadMoreListener;
private OnCustomScrollListener onCustomScrollListener;
public LoadMoreListView(Context context) {
super(context);
initlize(context);
}
public LoadMoreListView(Context context, AttributeSet attrs) {
super(context, attrs);
initlize(context);
}
public LoadMoreListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initlize(context);
}
private void initlize(Context context) {
initView(context);
initListener(context);
//新增footerview
addFooterView(mFooterView);
hideLoadingView();
}
private void initView(Context context) {
mFooterView = new RelativeLayout(context);
RelativeLayout.LayoutParams rParams;
LinearLayout.LayoutParams lParams;
rParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
rParams.addRule(RelativeLayout.CENTER_IN_PARENT);
layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER_VERTICAL);
mFooterView.addView(layout, rParams);
lParams = new LinearLayout.LayoutParams(60, 60);
lParams.weight = Gravity.CENTER_VERTICAL;
progressBar = new ProgressBar(context);
layout.addView(progressBar, lParams);
lParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
lParams.leftMargin = 10;
textView = new TextView(context);
textView.setText("正在載入...");
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
layout.addView(textView, lParams);
}
private void initListener(Context context) {
setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (onCustomScrollListener != null) {
onCustomScrollListener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (onCustomScrollListener != null) {
onCustomScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
if (mFooterView.getParent() != null && !mIsLoadingMore && mHasMore) {
layout.setVisibility(View.VISIBLE);
mFooterView.setVisibility(View.VISIBLE);
if (loadMoreListener != null) {
loadMoreListener.loadMore();
}
showLoadingView();
}
}
});
}
/**
* 設定OnCustomScrollListener回撥
*
* @param listener
*/
public void setOnCustomScrollListener(OnCustomScrollListener listener) {
this.onCustomScrollListener = listener;
}
/**
* OnScrollListener的回撥介面
*/
public interface OnCustomScrollListener {
void onScrollStateChanged(AbsListView view, int scrollState);
void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount);
}
/**
* 設定載入更多回撥介面
*
* @param listener
*/
public void setLoadMoreListener(LoadMoreListener listener) {
this.loadMoreListener = listener;
}
/**
* 載入更多回撥介面
*/
public interface LoadMoreListener {
void loadMore();
}
/**
* 是否還有更多
*
* @param hasMore
*/
public void setHasMore(boolean hasMore) {
mHasMore = hasMore;
}
/**
* 隱藏載入loading
*/
private void hideLoadingView() {
progressBar.setVisibility(View.GONE);
layout.setVisibility(View.GONE);
mFooterView.setVisibility(GONE);
}
/**
* 顯示loading
*/
private void showLoadingView() {
progressBar.setVisibility(View.VISIBLE);
layout.setVisibility(View.VISIBLE);
mFooterView.setVisibility(View.VISIBLE);
}
/**
* 載入更多結束
* 載入完成後呼叫
*/
public void loadMoreFinish() {
mIsLoadingMore = false;
hideLoadingView();
}
/**
* 正在載入更多
* 載入中呼叫
*/
public void isLoadingMore() {
mIsLoadingMore = true;
showLoadingView();
}
}
複製程式碼
LoadMoreListView是經過封裝的listview。initview函式:初始化footerview,然後通過addFooterView()將footerview加到listview中,而footerview的作用就是告訴使用者,正在載入資料。通過設定mIsLoadingMore和mHasMore,是否觸發回撥函式,如果觸發回撥函式就是需要載入資料。裡面設定了各種方法,大家可以看看註釋,都是比較簡單的封裝。
下面我們看看如何使用
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.lwj.loadmore.LoadMoreActivity">
<com.lwj.loadmore.LoadMoreListView
android:id="@+id/load_more_list"
android:layout_width="match_parent"
android:background="#ffffff"
android:dividerHeight="0dp"
android:divider="@null"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
複製程式碼
這是佈局檔案。
public class LoadMoreActivity extends BaseActivity {
private LoadMoreListView loadMoreListView;
private List<String> datas = new ArrayList<>();
private ListAdapter adapter;
private int page = 1;
private int pagesize = 30;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_load_more);
loadMoreListView = (LoadMoreListView)this.findViewById(R.id.load_more_list);
adapter = new ListAdapter(LoadMoreActivity.this,datas);
loadMoreListView.setAdapter(adapter);
initListener();
}
/**
* 初始化事件監聽
*/
private void initListener() {
/**
* 載入更多
*/
loadMoreListView.setLoadMoreListener(new LoadMoreListView.LoadMoreListener() {
@Override
public void loadMore() {
loadMoreListView.isLoadingMore();
getDataFromService();
}
});
}
private void getDataFromService(){
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
getDatas();
handler.post(new Runnable() {
@Override
public void run() {
setData();
}
});
}
}).start();
}
/**
* 設定資料
*/
private void setData() {
loadMoreListView.loadMoreFinish();
adapter.notifyDataSetChanged();
if (page == 3){
loadMoreListView.setHasMore(false);
}
page++;
}
/**
* 獲取資料
*/
public void getDatas() {
int i = 0;
if (page == 1){
i = page -1;
}else{
i = (page-1)*pagesize;
}
for (; i < (page*pagesize); i++) {
String str = "載入更多的tiem——"+i;
datas.add(str);
}
}
}
複製程式碼
使用很簡單,初始化view,然後設定回撥方法,在回撥方法中去獲取資料,同時呼叫loadMoreListView.isLoadingMore()方法,顯示載入的loading。
載入資料完成之後,需要呼叫loadMoreListView.loadMoreFinish(),這個方法隱藏掉loading同時設定mIsLoadingMore,如果沒有設定setHasMore(false),滑動到底部會觸發載入更多的回撥,繼續載入資料。
public class ListAdapter extends BaseAdapter {
private List<String> datas;
private Context mContext;
public ListAdapter(Context mContext,List<String> datas) {
this.datas = datas;
this.mContext = mContext;
}
@Override
public int getCount() {
return datas == null ? 0 : datas.size();
}
@Override
public Object getItem(int i) {
return datas == null ? null : datas.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
if (convertView == null && !(convertView instanceof ItemLayout)){
convertView = new ItemLayout(mContext);
}
((ItemLayout)convertView).setData(datas.get(position));
return convertView;
}
public static class ItemLayout extends LinearLayout{
public String tagStr;
private Button mButton;
public ItemLayout(Context context) {
super(context);
initView(context);
}
private void initView(Context context) {
int MP = LinearLayout.LayoutParams.MATCH_PARENT;
int WC = LinearLayout.LayoutParams.WRAP_CONTENT;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(MP, WC);
LinearLayout layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.list_item_layout,null);
addView(layout,params);
mButton = (Button)layout.findViewById(R.id.text);
}
public void setData(String str){
if (str == null || str == tagStr){
return;
}else{
tagStr = str;
mButton.setText(str);
}
}
}
}
複製程式碼
這是listview的adapter,主要顯示資料,比較簡單。
整個封裝和使用已經完成了,希望對大家有所幫助。