Android实现ListView的下拉刷新、上拉加载更多

Android实现ListView的下拉刷新、上拉加载更多

在Andoird编程中经常使用的控件包括ListView,就个人而言,我还是很喜欢ListView的,在使用ListView的过程中,必不可少的就是下拉刷新、上拉加载更多。下面是我自己写出一个小Demo便于大家理解。希望大家可以理解。共同进步!

自己bb那么多,希望大家见谅,我直接上图说话

这里写图片描述

第一步:先定义一个自定义控件SlipListView继承与ListView,在SlipListView中增加ListView的头布局与脚布局并实现其滑动监听的功能(代码虽然多,但是原理很简单,聪明的你们肯定可以看明白的。)

    public class SlipListView extends ListView implements OnScrollListener {

        private Context mContext;
        private int startY;
        private int moveY;
        private int mHeaderViewHeight;
        private View mHeaderview;

        /**
         * 下拉刷新
         */
        private static final int downRefresh = 0;

        /**
         * 正在刷新
         */
        private static final int refreshing = 1;

        /**
         * 释放刷新
         */
        private static final int upRefresh = 2;

        private int currentState = downRefresh;

        private RotateAnimation mUpAnimation;
        private RotateAnimation mDownAnimation;
        private TextView tvTiTile;
        private ProgressBar pbUp;
        private ImageView ivRefresh;
        private RefreshListener mListener;
        private View mFootView; // 脚布局
        private boolean isLoadingMore; // 是否正在加载更多
        private int mFootViewHeight;

        public SlipListView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init();
        }

        public SlipListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }

        public SlipListView(Context context) {
            super(context);
            init();
        }

        /**
         * 初始化界面,及动画
         */
        private void init() {
            mContext = getContext();

            setOnScrollListener(this);

            // 初始化头布局
            initHeaderView();
            // 初始化脚布局
            initFootView();
            initAnimation();
        }

        /**
         * 初始化脚布局
         */
        private void initFootView() {
            mFootView = View.inflate(mContext, R.layout.layout_foot, null);

            mFootView.measure(0, 0);
            mFootViewHeight = mFootView.getMeasuredHeight();

            addFooterView(mFootView);
        }

        /**
         * 初始化动画
         */
        private void initAnimation() {
            mUpAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF,
                    0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            mUpAnimation.setDuration(300);
            mUpAnimation.setFillAfter(true);

            mDownAnimation = new RotateAnimation(-180, -360,
                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                    0.5f);
            mDownAnimation.setDuration(300);
            mDownAnimation.setFillAfter(true);
        }

        /**
         * 初始化头布局
         */
        private void initHeaderView() {
            mHeaderview = View.inflate(mContext, R.layout.layout_header, null);
            ivRefresh = (ImageView) mHeaderview.findViewById(R.id.iv_refresh);
            pbUp = (ProgressBar) mHeaderview.findViewById(R.id.pb_up);
            tvTiTile = (TextView) mHeaderview.findViewById(R.id.tv_title);

            mHeaderview.measure(0, 0);
            mHeaderViewHeight = mHeaderview.getMeasuredHeight();
            // 隐藏头布局
            mHeaderview.setPadding(0, -mHeaderViewHeight, 0, 0);

            addHeaderView(mHeaderview);
        }

        // 监听listview的滑动事件
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN:
                startY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                moveY = (int) ev.getY();
                if (currentState == refreshing) {
                    return super.onTouchEvent(ev);
                }

                int valueY = moveY - startY;
                if (valueY > 0 && getFirstVisiblePosition() == 0) {
                    int result = -mHeaderViewHeight + valueY;
                    mHeaderview.setPadding(0, result, 0, 0);

                    // 判断状态
                    if (result < 0 && currentState != downRefresh) {
                        currentState = downRefresh;
                        updateHeader();
                    } else if (result >= 0 && currentState != upRefresh) {
                        currentState = upRefresh;
                        updateHeader();
                    }
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                // 松开
                if (currentState == downRefresh) {
                    mHeaderview.setPadding(0, -mHeaderViewHeight, 0, 0);
                } else if (currentState == upRefresh) {
                    mHeaderview.setPadding(0, 0, 0, 0);
                    currentState = refreshing;
                    updateHeader();
                }
                break;

            default:
                break;
            }

            return super.onTouchEvent(ev);
        }

        /**
         * 更改头布局的状态
         */
        private void updateHeader() {
            switch (currentState) {
            case downRefresh:
                ivRefresh.startAnimation(mDownAnimation);
                tvTiTile.setText("下拉刷新");
                break;
            case refreshing:
                // 正在刷新
                ivRefresh.clearAnimation();
                ivRefresh.setVisibility(View.INVISIBLE);
                pbUp.setVisibility(View.VISIBLE);
                tvTiTile.setText("正在刷新...");

                // 利用回调增加listview中的内容
                if (mListener != null) {
                    mListener.onRefresh();
                }
                break;
            case upRefresh:
                // 释放刷新
                ivRefresh.startAnimation(mUpAnimation);
                tvTiTile.setText("释放刷新");
                break;
            }
        }

        public interface RefreshListener {

            /**
             * 刷新数据
             */
            void onRefresh();

            /**
             * 加载更多
             */
            void onLoadMore();
        }

        /**
         * 刷新头布局的回调方法
         */
        public void setOnRefreshListener(RefreshListener mListener) {
            this.mListener = mListener;
        }

        /**
         * 刷新结束
         */
        public void setOnRefreshFinah() {
            if (isLoadingMore) {
                // 加载更多
                mFootView.setPadding(0, -mFootViewHeight, 0, 0);
                isLoadingMore = false;
            }

            currentState = downRefresh;
            mHeaderview.setPadding(0, -mHeaderViewHeight, 0, 0);
            ivRefresh.setVisibility(View.VISIBLE);
            pbUp.setVisibility(View.INVISIBLE);
            tvTiTile.setText("下拉刷新");
        }

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if (isLoadingMore) {
                return;
            }
            // 最新状态是空闲状态, 并且当前界面显示了所有数据的最后一条. 加载更多
            if (scrollState == SCROLL_STATE_IDLE
                    && getLastVisiblePosition() >= (getCount() - 1)) {
                isLoadingMore = true;
                mFootView.setPadding(0, 0, 0, 0);

                setSelection(getCount());

                if (mListener != null) {
                    mListener.onLoadMore();
                }
            }

        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            // 滑动过程中
        }
    }

第二步:在布局文件中使用此自定义控件(比较简单)

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

        <com.lx.pulllistview.ui.SlipListView
            android:id="@+id/slv_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </RelativeLayout>

第三步:定义ListView的Item的布局(里面我将ProgressBar自定义了一个style,你们可以使用默认的)

    <?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:orientation="horizontal" >

        <FrameLayout
            android:layout_width="60dp"
            android:layout_height="50dp"
            android:layout_marginBottom="5dp"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="5dp" >

            <ProgressBar
                android:id="@+id/pb_up"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:indeterminateDrawable="@drawable/progressbar_shape" />
        </FrameLayout>

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:gravity="center"
            android:text="加载更多..."
            android:textColor="#ff0000"
            android:textSize="16dp" />

    </LinearLayout>

第四步:在MainActivity中调用(不难喲,加油)

    public class MainActivity extends Activity {

        private static final int PULL_DOWN = 0;
        private static final int LOAD_MORE = 1;
        private SlipListView slView;
        private Context mContext;
        private List<String> mTestList;
        private MyAdapter mAdapter;

        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {

                switch (msg.what) {

                case PULL_DOWN:
                    mAdapter.notifyDataSetChanged();
                    slView.setOnRefreshFinah();
                    break;
                case LOAD_MORE:

                    break;
                }

                super.handleMessage(msg);
            }
        };

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

            mContext = this;
            // 初始化UI
            initUI();

            // 初始化数据
            initData();
            initEvent();
            // 初始化数据适配器
            initAdpater();
        }

        /**
         * 初始化事件
         */
        private void initEvent() {
            slView.setOnRefreshListener(new RefreshListener() {
                @Override
                public void onRefresh() {

                    new Thread(new Runnable() {

                        @Override
                        public void run() {
                            SystemClock.sleep(2000);
                            mTestList.add(0, "我是刷新出来的测试数据");

                            mHandler.sendEmptyMessage(PULL_DOWN);
                        }
                    }).start();

                }

                @Override
                public void onLoadMore() {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            SystemClock.sleep(2000);

                            mTestList.add("我是加载出来的测试数据1");
                            mTestList.add("我是加载出来的测试数据2");

                            mHandler.sendEmptyMessage(PULL_DOWN);

                        }
                    }).start();
                }
            });
        }

        /**
         * 初始化ListView的适配器
         */
        private void initAdpater() {
            mAdapter = new MyAdapter();
            slView.setAdapter(mAdapter);
        }

        /**
         * 初始化listview的测试数据
         */
        private void initData() {
            mTestList = new ArrayList<String>();
            for (int i = 0; i < 30; i++) {
                mTestList.add("我是ListView的测试数据");
            }
        }

        /**
         * 初始化UI
         */
        private void initUI() {
            slView = (SlipListView) findViewById(R.id.slv_view);
        }

        /**
         * 自定义适配器
         */
        class MyAdapter extends BaseAdapter {

            @Override
            public int getCount() {
                return mTestList.size();
            }

            @Override
            public String getItem(int position) {
                return mTestList.get(position);
            }

            @Override
            public long getItemId(int position) {
                return position;
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                // 由于item的布局就一个TextView并且数量较少,因此不使用优化了
                TextView textView = new TextView(mContext);
                textView.setText(mTestList.get(position));
                textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);

                return textView;
            }

        }
    }

你是不是想说终于结束了,嘿嘿!当你阅读到这里的时候,你的知识与忍耐力已经更上一层楼了。废话不多说了,如果您有疑问请咨询我,最后谢谢大家的观看,你们的支持是给我最大的努力!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值