封裝ListView,實現自動載入更多

鋸齒流沙發表於2018-01-08

如今網上關於封裝ListView,實現載入更多和下拉重新整理的文章已經鋪天蓋地的了,基本都是通過addHeaderView()和addFooterView(),設定下拉頭和上拉底部,然後通過OnScrollListener監聽器的onScroll方法中判斷是否滑動到底部。

判斷滑動到底部還是頭部:

 if (firstVisibleItem == 0) {
            Log.i("ListView", "滾動到頂部");
        } else if ((firstVisibleItem + visibleItemCount) == totalItemCount) {
            Log.i("ListView", "滾動到底部");
 }
複製程式碼

理論都是萬變不離其宗。

S70815-203921.jpg
S70815-203926.jpg

這是我封裝之後得到的效果圖。

以下是封裝控制元件的實現。

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,主要顯示資料,比較簡單。

整個封裝和使用已經完成了,希望對大家有所幫助。

相關文章