1. 程式人生 > >繼承SwipeRefreshLayout實現上拉載入更多功能

繼承SwipeRefreshLayout實現上拉載入更多功能

Android 的SwipeRefreshLayout是一個比較好的下拉重新整理控制元件,現在已經有越來越多的企業開始使用這個控制元件了。但是遺憾的是這個控制元件並沒有上拉載入更多的功能,所以自己抽空,根據網上已有的例子,自己寫了一個。

首先必須要做的是建立一個類繼承SwipeRefreshLayout,這裡我把它命名為:XZHRefreshLayout

/**
 * TODO:Created by XuZhenhao on 2016/12/6.
 */

public class XZHRefreshLayout extends SwipeRefreshLayout {


    private boolean isLoading = false;

    private ListView mListView;

    private View mListFooter;

    private OnLoadListener mLoadListener;


    public XZHRefreshLayout(Context context) {
        this(context, null);
    }

    public XZHRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        //這裡初始化FooterView,並給裡面的一個菊花圖片新增一個動畫
        mListFooter = LayoutInflater.from(context).inflate(R.layout.list_footer, null, false);
        Animation anim = AnimationUtils.loadAnimation(context, R.anim.img_animation);
        LinearInterpolator lin = new LinearInterpolator();
        anim.setInterpolator(lin);
        mListFooter.findViewById(R.id.progress_iv).startAnimation(anim);
    }

    //這裡set回撥函式
    public void setOnLoadListener(OnLoadListener loadListener) {
        this.mLoadListener = loadListener;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //這裡判斷ViewGroup裡面是不是有個子View,並且第一個是不是ListView
        int childCount = getChildCount();
        if (childCount > 0) {
            View child = getChildAt(0);
            if (child instanceof ListView) {
                mListView = (ListView) child;

            }
        }

    }

    //用於新增和移除FooterView
    public void setLoad(boolean isLoad) {
        isLoading = isLoad;
        if (isLoad) {

            mListView.addFooterView(mListFooter);
        } else {

            mListView.removeFooterView(mListFooter);
        }
    }

    //記錄手指觸控式螢幕幕的上一個Y座標值
    private float lastY;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        float currentY = ev.getY();
        switch (action) {
            case MotionEvent.ACTION_DOWN:

                break;
            case MotionEvent.ACTION_MOVE:
                //如果當前的Y座標小於上一個Y座標的值說明是向上滑動,,並且子ListView不為null,並且沒有FooterView
                if (currentY < lastY && mListView != null && mListView.getFooterViewsCount() == 0) {
                    //如果當前listView的最後一個item的position等於可見範圍內最後一個item的position,
                    //並且螢幕中的item總數小於11,當前沒有載入FooterView
                    if (mListView.getAdapter().getCount() - 1 == mListView.getLastVisiblePosition() 
                        && mListView.getChildCount() >= 11 && !isLoading) {
                        setLoad(true);//新增FooterView
                        mLoadListener.onLoad();//執行回撥函式
                    }
                }
                break;
        }
        lastY = currentY;
        return super.onInterceptTouchEvent(ev);
    }
    
    //回撥
    public interface OnLoadListener {

        void onLoad();
    }
}

最核心的程式碼已經實現了,網上有很多Demo是在onScroll方法中實現的,但是我發現在滑動到底部時,onScroll方法一直在執行,那麼這樣的話會導致我們一直的執行回撥函式,因為這裡的回撥函式是用來載入資料的,從而會導致不停地獲取資料,不停的新增和移除FooterView,並且導致ListView的點選事件失效,所以我將其移到了onInterceptTouchEvent(MotionEvent ev)裡面去執行。



下面上Activity的程式碼:

public class MessageListActivity extends AppCompatActivity {


    private Toolbar SMSToolbar;
    private XZHRefreshLayout refreshLayout;
    private ListView lvSMSList;
    private MessageListAdapter adapter;
    private List smsList;
    private MRLTDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_message_list);

        initData();
        initView();
    }


    /**
     * TODO: 初始化控制元件
     */
    private void initView() {

        SMSToolbar = (Toolbar) findViewById(R.id.sms_list_toolbar);
        SMSToolbar.setTitle("簡訊列表");
        SMSToolbar.setNavigationIcon(ContextCompat.getDrawable(this, R.mipmap.btn_back));
        SMSToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onBackPressed();
            }
        });
        //實現我們自定義的下拉重新整理控制元件
        refreshLayout = (XZHRefreshLayout) findViewById(R.id.refresh_sms_ly);
        refreshLayout.setColorSchemeColors(ContextCompat.getColor(this, android.R.color.holo_blue_bright),
                ContextCompat.getColor(this, android.R.color.holo_green_light),
                ContextCompat.getColor(this, android.R.color.holo_orange_light),
                ContextCompat.getColor(this, android.R.color.holo_red_light));
        //監聽下拉重新整理事件
        refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        smsList.clear();
                        smsList.addAll(dao.querySMSALL(0));
                        adapter.notifyDataSetChanged();
                        refreshLayout.setRefreshing(false);
                    }
                }, 1500);
            }
        });
        //我們寫的回撥函式,在裡面做查詢資料的方法
        refreshLayout.setOnLoadListener(new XZHRefreshLayout.OnLoadListener() {
            @Override
            public void onLoad() {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //我這裡是用了一個Sqlite,大家可以根據自己的實際應用在這裡做資料的查詢,相信大家一般都不可能會有問題。
                        if (dao != null && smsList != null) {
                            List<SmsEntity> datas = dao.querySMSALL(smsList.size());
                            if (datas.size() > 0) {//如果查詢到有資料,就新增到資料來源裡面去。
                                smsList.addAll(datas);
                                adapter.notifyDataSetChanged();
                            }else{//如果沒有資料,就彈一個吐司
                                MyToast.show(MessageListActivity.this,"沒有更多資料!");
                            }
                        }
                        refreshLayout.setLoad(false);

                    }
                }, 1000);

            }
        });

        lvSMSList = (ListView) findViewById(R.id.sms_list_lv);
        adapter = new MessageListAdapter(this, smsList);
        lvSMSList.setAdapter(adapter);
        lvSMSList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                SmsEntity entity = (SmsEntity) adapter.getItem(position);
                showSMSDialog(entity);
            }
        });

    }

    /**
     * TODO: 初始化資料
     */
    private void initData() {
        if (smsList == null)
            smsList = new ArrayList<>();
        if (dao == null)
            dao = new MRLTDao(getApplicationContext());
        smsList = dao.querySMSALL(0);

    }


    @Override
    protected void onDestroy() {

        super.onDestroy();
    }
    //點選item彈一個Dialog,顯示當前Item的內容
    private void showSMSDialog(SmsEntity entity) {
        if (entity == null) {
            return;
        }
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(entity.getSendcode());
        builder.setMessage("接收時間:"+entity.getCreate_time()+"\n"+entity.getContent());
        builder.setPositiveButton("知道了", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });
        builder.create().show();

    }
}

總的來說Activity裡面完全沒有啥技術含量,只是有可能程式碼寫的其醜無比。

下面上XML:

1.Activity的XML檔案

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_message_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.yihuacomputer.sdmrlt.ui.MessageListActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/sms_list_toolbar"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/cpb_blue"
        app:titleTextColor="@color/cpb_white" />
<com.yihuacomputer.sdmrlt.ui.view.XZHRefreshLayout
    android:id="@+id/refresh_sms_ly"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/sms_list_toolbar">
    <ListView
        android:id="@+id/sms_list_lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="12dp"
        android:paddingRight="12dp"
        android:scrollbars="none">

    </ListView>
</com.yihuacomputer.sdmrlt.ui.view.XZHRefreshLayout>


</RelativeLayout>

2.ListView的Item的XML

<?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="match_parent"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:paddingBottom="4dp"
    android:paddingTop="4dp"
    android:weightSum="10">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:src="@mipmap/will" />

    <RelativeLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="9"
        android:layout_marginLeft="4dp">

        <TextView
            android:id="@+id/item_sms_rvd_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/colorPrimaryDark"
            android:maxLength="15"
            android:textSize="16sp" />
        <TextView
            android:id="@+id/item_sms_time_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/colorPrimaryDark"
            android:textSize="16sp"
            android:layout_alignParentTop="true"
            android:layout_alignParentEnd="true" />

        <TextView
            android:id="@+id/item_sms_content_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/item_sms_rvd_tv"
            android:maxLines="1"
            android:textColor="@color/menu_fragment_background"
            android:textSize="14sp" />
    </RelativeLayout>
</LinearLayout>

3.FooterView的XML檔案

<?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="45dp"
    android:gravity="center"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/progress_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/gpu" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="正在載入..."/>

</LinearLayout>

所有的XML檔案裡面就用到了兩個Image,大家隨便去找兩個就可以了,我是解壓了手機QQ的App後這裡面找的。

好了所有的東西基本已經實現,大家還可以在這個基礎上擴充套件一下,比如加一個動畫,讓FooterView被移除的時候好看一點,不要那麼突兀的就消失了,如果大家實現了,希望能留個言讓我學習學習!!!公司沒有錄屏工具,我就不上圖了。