• Android-自定义ListView下拉刷新与上拉加载


    效果图:

    第一步:编写需要在ListView中增加头加载的布局文件,与底部加载的布局文件:

    头布局文件:

    <?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="wrap_content"
        android:orientation="horizontal" >
    
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dip" >
    
            <ImageView
                android:id="@+id/iv_listview_header_arrow"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:src="@mipmap/common_listview_headview_red_arrow" />
    
            <ProgressBar
                android:id="@+id/pb_listview_header"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:indeterminateDrawable="@drawable/custom_progressbar"
                android:visibility="invisible" />
        </FrameLayout>
    
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:gravity="center_horizontal"
            android:orientation="vertical" >
    
            <TextView
                android:id="@+id/tv_listview_header_state"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下拉刷新"
                android:textColor="#FF0000"
                android:textSize="18sp" />
    
            <TextView
                android:id="@+id/tv_listview_header_last_update_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dip"
                android:text="最后刷新时间: 1990-09-09 09:09:09"
                android:textColor="@android:color/darker_gray"
                android:textSize="14sp" />
        </LinearLayout>
    
    </LinearLayout>

    底部布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_centerInParent="true"
            android:gravity="center_vertical">
    
            <ProgressBar
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:indeterminateDrawable="@drawable/custom_progressbar"
                />
    
            <TextView
                android:id="@+id/tv_bottom_state"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="加载更多"
                android:layout_marginLeft="10dp"/>
    
        </LinearLayout>
    
    </RelativeLayout>

    自定义ListView需要的接口回调给UI,告诉UI ListView执行了下拉加载/上拉加载动作 

    public interface ICustomUpdateListViewBack {
    
        public void downUpdateListData();
    
        public void upUpdateListData();
    
    }

    自定义ListView:

    public class CustomUpdateListView extends ListView implements AbsListView.OnScrollListener{
    
        private static final String TAG = CustomUpdateListView.class.getSimpleName();
    
        /**
         * 下拉刷新
         */
        private static final int DOWN_UPDATE = 111;
    
        /**
         * 准备刷新
         */
        private static final int PLAN_UPDATE = 112;
    
        /**
         * 正在刷新
         */
        private static final int PROCESS_UPDATE = 113;
    
        private int thisUpdateStatusValue = DOWN_UPDATE; // 默认一直是下拉刷新
    
        public CustomUpdateListView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            setOnScrollListener(this);
    
            initHeader();
            initBottom();
        }
    
        /**
         * 定义头部相关
         */
        private View headerView;
        private int headerViewHeight;
    
        private ImageView ivHeaderArrow;
        private ProgressBar pbHeader;
        private TextView tvHeaderState;
        private TextView tvHeaderLastUpdateTime;
    
        /**
         * 定义底部相关
         */
        private View bottomView;
        private int bottomViewHeight;
        private TextView tvBottomState;
        /**
         * 初始化头部 布局View相关
         */
        private void initHeader() {
            // 从布局中拿到一个View
            headerView = View.inflate(getContext(), R.layout.listview_header, null);
    
            // 获取头部各个控件的值
            ivHeaderArrow = headerView.findViewById(R.id.iv_listview_header_arrow);
            pbHeader = headerView.findViewById(R.id.pb_listview_header);
            tvHeaderState = headerView.findViewById(R.id.tv_listview_header_state);
            tvHeaderLastUpdateTime = headerView.findViewById(R.id.tv_listview_header_last_update_time);
    
            tvHeaderLastUpdateTime.setText(getThisTiem());
    
            // getHieight(); 方法只能获取到控件显示后的高度
            // int headerViewHeight = headerView.getHeight();
            // 结果 headerViewHeight: 0
    
            // View的绘制流程:测量 onLayout onDraw
    
            // 所以先测量后,就能得到测量后的高度了
            headerView.measure(0, 0); // 注意:传0系统会自动去测量View高度
    
            // 得到测量后的高度
            headerViewHeight = headerView.getMeasuredHeight();
            Log.i(TAG, "headerViewHeight:" + headerViewHeight);
    
            headerView.setPadding(0, -headerViewHeight, 0 ,0);
    
            addHeaderView(headerView);
    
            initHeaderAnimation();
        }
    
        private void initBottom() {
            bottomView = View.inflate(getContext(), R.layout.listview_bottom, null);
    
            tvBottomState = bottomView.findViewById(R.id.tv_bottom_state);
    
            // 先测量
            bottomView.measure(0, 0);
    
            // 获取高度
            bottomViewHeight = bottomView.getMeasuredHeight();
    
            bottomView.setPadding(0, -bottomViewHeight, 0, 0);
    
            addFooterView(bottomView);
    
        }
    
        private RotateAnimation upRotateAnimation;
        private RotateAnimation downRotateAnimation;
    
        private void initHeaderAnimation() {
            upRotateAnimation = new RotateAnimation(
                    0, 180,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f);
            upRotateAnimation.setDuration(500);
            upRotateAnimation.setFillAfter(true);
    
            downRotateAnimation = new RotateAnimation(
                    180, 360,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f);
            downRotateAnimation.setDuration(500);
            downRotateAnimation.setFillAfter(true);
        }
    
        /**
         * 滑动的状态改变
         * @param view
         * @param scrollState 有三种状态
         *                    SCROLL_STATE_IDLE 代表 滑动停止状态类似于手指松开UP
         *                    SCROLL_STATE_TOUCH_SCROLL 代表滑动触摸状态
         *                    SCROLL_STATE_FLING 快速滑动 猛的一滑
         */
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            // 如果是猛地滑动 或者 手指松开UP 才显示底部布局View
            if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) {
                // 判断必须是底部的Item的时候
                if (getLastVisiblePosition() == (getCount() -1)) {
                    bottomView.setPadding(0, 0, 0, 0);
    
                    // 回调接口方法
                    if (null != customUpdateListViewBack) {
                        customUpdateListViewBack.upUpdateListData();
                    }
                }
            }
        }
    
        private int firstVisibleItem;
    
        /**
         * ListView滑动的监听方法
         * @param view 当前ListView
         * @param firstVisibleItem 当前屏幕的第一个显示的Item
         * @param visibleItemCount 当前屏幕显示的Item数量
         * @param totalItemCount 总共Item数量
         */
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            this.firstVisibleItem = firstVisibleItem;
        }
    
        private int downY;
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downY = (int) ev.getY();
                    break;
                case MotionEvent.ACTION_UP:
                    if (thisUpdateStatusValue == DOWN_UPDATE) {
                        headerView.setPadding(0, -headerViewHeight ,0 ,0);
                    } else {
                        headerView.setPadding(0, 0, 0, 0);
                        thisUpdateStatusValue = PROCESS_UPDATE;
                        updateHeaderState();
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    int cha = (int) ev.getY() - downY;
                    if (this.firstVisibleItem == 0 && cha > 0) {
                        int paddingTop = -headerViewHeight + cha;
                        // Log.i(TAG, "paddingTop:" + paddingTop);
    
                        if (thisUpdateStatusValue == PROCESS_UPDATE) {
                            break;
                        }
    
                        if (paddingTop > 0 && thisUpdateStatusValue == DOWN_UPDATE) {
                            // 准备刷新
                            Log.i(TAG, "paddingTop:" + paddingTop + ">>>准备刷新");
                            thisUpdateStatusValue = PLAN_UPDATE;
    
                            updateHeaderState();
    
                        } else if (paddingTop < 0 && thisUpdateStatusValue == PLAN_UPDATE) {
                            // 正在刷新
                            Log.i(TAG, "paddingTop:" + paddingTop + ">>>正在刷新");
                            thisUpdateStatusValue = DOWN_UPDATE;
    
                            updateHeaderState();
                        }
    
                        headerView.setPadding(0, paddingTop, 0, 0);
                    }
                    break;
                default:
                    break;
            }
            return super.onTouchEvent(ev); // 不返回ture 而是去调用父类的方法,是保证ListView自身的滑动功能正常
        }
    
        private void updateHeaderState() {
    
            switch (thisUpdateStatusValue) {
                case DOWN_UPDATE:
                    ivHeaderArrow.startAnimation(downRotateAnimation);
                    tvHeaderState.setText("下拉刷新");
                    break;
                case PLAN_UPDATE:
                    ivHeaderArrow.startAnimation(upRotateAnimation);
                    tvHeaderState.setText("准备刷新");
                    break;
                case PROCESS_UPDATE:
                    ivHeaderArrow.setVisibility(INVISIBLE);
                    ivHeaderArrow.clearAnimation();
                    pbHeader.setVisibility(VISIBLE);
                    tvHeaderState.setText("正在刷新中...");
    
                    if (null != customUpdateListViewBack) {
                        customUpdateListViewBack.downUpdateListData();
                    }
                    break;
                default:
                    break;
            }
        }
    
        private ICustomUpdateListViewBack customUpdateListViewBack;
    
        public void setCallback(ICustomUpdateListViewBack back) {
            this.customUpdateListViewBack = back;
        }
    
        public void updateHeaderResult() {
            headerView.setPadding(0, -headerViewHeight, 0, 0);
    
            // 状态还原
            ivHeaderArrow.clearAnimation();
            tvHeaderState.setText("下拉刷新");
    
            ivHeaderArrow.setVisibility(VISIBLE);
            pbHeader.setVisibility(INVISIBLE);
    
            tvHeaderLastUpdateTime.setText(getThisTiem());
    
            thisUpdateStatusValue = DOWN_UPDATE;
        }
    
        private String getThisTiem() {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");// HH:mm:ss
            // 获取当前时间
            Date date = new Date(System.currentTimeMillis());
            return simpleDateFormat.format(date);
        }
    
        public void updateBottomResult() {
            /*tvBottomState.setText("加载成功");
            tvBottomState.setTextColor(Color.GREEN);*/
    
            new android.os.Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    bottomView.setPadding(0, -bottomViewHeight, 0, 0);
                }
            }, 2000);
        }
    }

    把ProgressBar的风格修改,从白色演变成红色的形式

    custom_progressbar.xml 文件:

    <?xml version="1.0" encoding="utf-8"?>
    <rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" >
    
        <shape
            android:innerRadiusRatio="3"
            android:shape="ring"
            android:thicknessRatio="10"
            android:useLevel="false" >
            <gradient
                android:centerColor="#FF6A6A"
                android:endColor="#FF0000"
                android:startColor="#FFFFFF"
                android:type="sweep" />
        </shape>
    
    </rotate>

    如何使用自定义的ListView:

        <heima.custom.CustomUpdateListView
            android:id="@+id/custom_listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/ll">
        </heima.custom.CustomUpdateListView>

    当把数据查询出来后,执行:

    listView.updateHeaderResult(); // 更新头部布局复原
    listView.updateBottomResult(); // 更新底部布局复原

    listView.setCallback(new ICustomUpdateListViewBack() {
                @Override
                public void downUpdateListData() {
                    new AsyncTask<Void, Void, Void>() {
    
                        @Override
                        protected Void doInBackground(Void... voids) {
                            SystemClock.sleep(3000);
                            mData.add(0, "1最新加载出来的数据");
                            mData.add(1, "2最新加载出来的数据");
                            mData.add(2, "3最新加载出来的数据");
                            mData.add(3, "4最新加载出来的数据");
                            mData.add(4, "5最新加载出来的数据");
                            mData.add(5, "6最新加载出来的数据");
                            return null;
                        }
    
                        @Override
                        protected void onPostExecute(Void aVoid) {
                            // super.onPostExecute(aVoid);
                            adapter.notifyDataSetChanged();
                            listView.updateHeaderResult();
                        }
                    }.execute(new Void[]{});
                }
    
                @Override
                public void upUpdateListData() {
                    new AsyncTask<Void, Void, Void>() {
    
                        @Override
                        protected Void doInBackground(Void... voids) {
                            SystemClock.sleep(6000);
                            mData.add("1commonlibrary");
                            mData.add("2commonlibrary");
                            mData.add("3commonlibrary");
                            mData.add("4commonlibrary");
                            mData.add("5commonlibrary");
                            mData.add("6commonlibrary");
                            return null;
                        }
    
                        @Override
                        protected void onPostExecute(Void aVoid) {
                            // super.onPostExecute(aVoid);
                            adapter.notifyDataSetChanged();
                            listView.updateBottomResult();
                        }
                    }.execute(new Void[]{});
                }
            });


  • 相关阅读:
    54.施工方案第二季(最小生成树)
    53.FIB词链
    52.1076 排序
    最短路径:我的理解--SPFA算法
    POJ2187Beauty Contest
    CodeForces 279B Books
    SDUT 2527 斗地主
    HDU1020 Encoding
    POJ 2635 The Embarrassed Cryptographer
    POJ 1942 Paths on a Grid(组合数)
  • 原文地址:https://www.cnblogs.com/android-deli/p/9647315.html
Copyright © 2020-2023  润新知