• 自定义ListView_下拉刷新上拉加载更多


    自定义ListView实现下拉刷新和上拉自动加载

    效果图:

    下拉效果:

    上拉效果:

    实现原理:通过ListView的addFooter与addHeader方法,将下拉布局与上拉布局添加到ListView中,再通过设置padding属性,隐藏头部和脚部

         监听onTouchEvent事件,根据手势滑动距离,动态更改下拉布局的padding,并动态更改头布局内控件效果

         监听onScrollStateChanged,动态显示隐藏脚布局

                  设置回调,提供下拉刷新与加载更多的方法

    Demo:https://files.cnblogs.com/files/liujingg/PullRefreshDemo.rar

    PullListView.java

    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.RotateAnimation;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ListView;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    /**
     * 自定义ListView,下拉刷新、上拉自动加载更多
     * @author liujing
     * @version 1.0
     */
    public class PullListView extends ListView implements OnScrollListener {
    
        private final int PULL_DOWN_REFRESH = 0;//下拉状态
        private final int RELEASE_REFRESH = 1;//松开状态
        private final int REFRESHING = 2;//刷新中状态
        private int currentState = PULL_DOWN_REFRESH;
        private int mListViewOnScreenY = -1;
        private int downY = -1;
        
        private boolean isLoadingMore = false;
        private boolean isEnabledPullDownRefresh = false;
        private boolean isEnabledLoadMore = false;
        private OnPullDownRefresh mOnPullDownRefresh;
        
        //头布局、脚布局及高度
        private View mFootView;
        private LinearLayout mHeaderView;
        private int mFooterViewHeight;
        private int mPullDownHeaderViewHeight;
        
        //mHeaderView中组件及动画
        private View mCustomHeaderView;//用户自定义头布局
        private View mPullDownHeader;//下拉刷新头布局
        private RotateAnimation upAnimation,downAnimation;
        private ImageView ivArrow;
        private ProgressBar mProgressBar;
        private TextView tv_statue,tv_time;
        
    
        public PullListView(Context context) {
            this(context, null);
        }
    
        public PullListView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public PullListView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            initPullDownHeaderView();
            initLoadMoreFooterView();
        }
        
        private void initLoadMoreFooterView() {
            //加载更多的布局文件
            mFootView = View.inflate(getContext(), R.layout.pull_listview_footer,
                    null);
            mFootView.measure(0, 0);//测量
            mFooterViewHeight = mFootView.getMeasuredHeight();
            //隐藏脚布局
            mFootView.setPadding(0,-mFooterViewHeight,0,0);
            addFooterView(mFootView);
            setOnScrollListener(this);
        }
    
        private void initPullDownHeaderView() {
            //下拉刷新的布局文件
            mHeaderView = (LinearLayout) View.inflate(getContext(),
                    R.layout.pull_listview_header, null);
            mPullDownHeader = mHeaderView
                    .findViewById(R.id.ll_refresh_pull_down_header);
            ivArrow = (ImageView) mHeaderView
                    .findViewById(R.id.iv_refresh_header_arrow);
            mProgressBar = (ProgressBar) mHeaderView
                    .findViewById(R.id.pb_refresh_header);
            tv_statue = (TextView) mHeaderView
                    .findViewById(R.id.tv_refresh_header_status);
            tv_time = (TextView) mHeaderView
                    .findViewById(R.id.tv_refresh_header_time);
            mPullDownHeader.measure(0, 0);//测量
            mPullDownHeaderViewHeight = mPullDownHeader.getMeasuredHeight();
            //隐藏头布局
            mPullDownHeader.setPadding(0, -mPullDownHeaderViewHeight, 0, 0);
            addHeaderView(mHeaderView);
            initAnimation();
        }
        
        /**
         * 添加额外的头布局,比如轮播图
         * @param v 自定义头布局
         */
        public void addListViewCustomHeaderView(View v) {
            mCustomHeaderView = v;
            mHeaderView.addView(mCustomHeaderView);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (downY == -1)
                    downY = (int) ev.getY();
                //是否启用下拉刷新
                if (!isEnabledPullDownRefresh)
                    break;
                if (currentState == REFRESHING)
                    break;
                //解决用户添加header与下拉刷新header的冲突
                if (mCustomHeaderView != null) {
                    int[] location = new int[2];
                    if (mListViewOnScreenY == -1) {
                        this.getLocationOnScreen(location);
                        mListViewOnScreenY = location[1];
                    }
                    mCustomHeaderView.getLocationOnScreen(location);
                    if (location[1] < mListViewOnScreenY) {
                        break;
                    }
                }
    
                int moveY = (int) ev.getY();
                int diffY = (moveY - downY)/2;
                if (diffY > 0 && getFirstVisiblePosition() == 0) {
                    int paddingTop = -mPullDownHeaderViewHeight + diffY;
                    if (paddingTop < 0 && currentState != PULL_DOWN_REFRESH) {
                        //当前没有完全显示且当前状态为松开刷新,进入下拉刷新
                        currentState = PULL_DOWN_REFRESH;
                        refreshPullDownState();
                    } else if (paddingTop > 0 && currentState != RELEASE_REFRESH) {
                        //当前完全显示且当前状态为下拉刷新,进入松开刷新
                        currentState = RELEASE_REFRESH;
                        refreshPullDownState();
                    }
                    mPullDownHeader.setPadding(0, paddingTop, 0, 0);
                    return true;
                }else if(diffY < 0 && getLastVisiblePosition() == getCount()-1){
                    //脚布局可向上滑动
                    mFootView.setPadding(0,0,0,0);
                }
                break;
            case MotionEvent.ACTION_UP:
                downY = -1;
                if (currentState == PULL_DOWN_REFRESH) {
                    //隐藏header
                    mPullDownHeader.setPadding(0, -mPullDownHeaderViewHeight, 0, 0);
                } else if (currentState == RELEASE_REFRESH) {
                    currentState = REFRESHING;
                    refreshPullDownState();
                    mPullDownHeader.setPadding(0, 0, 0, 0);
                    //回调刷新方法
                    if (mOnPullDownRefresh != null) {
                        mOnPullDownRefresh.onPullDownRefresh();
                    }
                }
                break;
            }
            return super.onTouchEvent(ev);
        }
        
        /**
         * 隐藏头布局或脚布局并重置控件
         */
        public void OnRefreshDataFinish() {
            if (isLoadingMore) {
                isLoadingMore = false;
                mFootView.setPadding(0,-mFooterViewHeight,0,0);
            } else {
                ivArrow.setVisibility(View.VISIBLE);
                mProgressBar.setVisibility(View.INVISIBLE);
                tv_statue.setText("下拉刷新");
                tv_time.setText("最后刷新时间:" + getCurrentTime());
                mPullDownHeader.setPadding(0, -mPullDownHeaderViewHeight, 0, 0);
                currentState = PULL_DOWN_REFRESH;
    
            }
        }
    
        private String getCurrentTime() {
            SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
            return format.format(new Date());
        }
    
        private void refreshPullDownState() {
            switch (currentState) {
            case PULL_DOWN_REFRESH:
                ivArrow.startAnimation(downAnimation);
                tv_statue.setText("下拉刷新");
                break;
            case RELEASE_REFRESH:
                ivArrow.startAnimation(upAnimation);
                tv_statue.setText("松开刷新");
                break;
            case REFRESHING:
                ivArrow.clearAnimation();
                ivArrow.setVisibility(View.INVISIBLE);
                mProgressBar.setVisibility(View.VISIBLE);
                tv_statue.setText("正在刷新");
                break;
            default:
                break;
            }
        }
        
        /**
         * 箭头旋转动画
         */
        private void initAnimation() {
            upAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF,
                    0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            upAnimation.setDuration(200);
            upAnimation.setFillAfter(true);
    
            downAnimation = new RotateAnimation(-180, -360,
                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                    0.5f);
            downAnimation.setDuration(200);
            downAnimation.setFillAfter(true);
        }
        
        /**
         * 回调方法,用于刷新数据及加载更多
         * @param listener
         */
        public void setOnPullDownRefresh(OnPullDownRefresh listener) {
            this.mOnPullDownRefresh = listener;
        }
    
        public interface OnPullDownRefresh {
            public void onPullDownRefresh();
            public void onLoadingMore();
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if (!isEnabledLoadMore) {
                return;
            }
            //listView停止状态或惯性滑动状态
            if (scrollState == SCROLL_STATE_IDLE
                    || scrollState == SCROLL_STATE_FLING) {
                //listView已到达最底部
                if ((getLastVisiblePosition() == getCount() - 1) && !isLoadingMore) {
                    isLoadingMore = true;
                    //展示脚布局
                    //mFootView.setPadding(0, 0, 0, 0);
                    setSelection(getCount());
                    if (mOnPullDownRefresh != null) {
                        mOnPullDownRefresh.onLoadingMore();
                    }
                }
            }
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            
        }
        
        /**
         * 是否启用下拉刷新
         * @param isEnable
         */
        public void setEnabledPullDownRefresh(boolean isEnable) {
            isEnabledPullDownRefresh = isEnable;
        }
        
        /**
         * 是否启用加载更多
         * @param isEnable
         */
        public void setEnabledLoadMore(boolean isEnable) {
            isEnabledLoadMore = isEnable;
        }
    }

     pull_listview_header.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
    
        <LinearLayout
            android:id="@+id/ll_refresh_pull_down_header"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >
    
            <FrameLayout
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_marginBottom="3dp"
                android:layout_marginLeft="28dp"
                android:layout_marginTop="8dp" >
    
                <ImageView
                    android:id="@+id/iv_refresh_header_arrow"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:src="@drawable/common_listview_headview_red_arrow" />
    
                <ProgressBar
                    android:id="@+id/pb_refresh_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:layout_weight="1"
                android:gravity="center_horizontal"
                android:orientation="vertical" >
    
                <TextView
                    android:id="@+id/tv_refresh_header_status"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="下拉刷新"
                    android:textColor="#ff0000"
                    android:textSize="16sp"
                    android:textStyle="bold" >
                </TextView>
    
                <TextView
                    android:id="@+id/tv_refresh_header_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="最后刷新时间:09:23:23"
                    android:textColor="@android:color/darker_gray"
                    android:textSize="12sp" >
                </TextView>
            </LinearLayout>
            <TextView 
                android:layout_width="40dp"
                android:layout_marginRight="28dp"
                android:layout_height="wrap_content"
                />
        </LinearLayout>
    
    </LinearLayout>

    pull_listview_footer.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="wrap_content"
        android:gravity="center"
        android:orientation="horizontal" >
    
        <ProgressBar
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_margin="2dp"
            android:indeterminateDrawable="@drawable/custom_progressbar" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="5dp"
            android:text="加载更多..."
            android:textColor="#ff0000"
            android:textSize="18sp" />
    
    </LinearLayout>

    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="4"
            android:shape="ring"
            android:thicknessRatio="10"
            android:useLevel="false" >
            <gradient
                android:centerColor="#ff6666"
                android:endColor="#ff0000"
                android:startColor="#ffffff"
                android:type="sweep" />
        </shape>
    
    </rotate>
  • 相关阅读:
    仿苹果菜单的效果
    不用系统自带的复选框,单选按钮,选择框的样式,该怎么做
    js面向对象(三)---组件开发
    JS面向对象(二)---继承
    js面向对象(一)---基本的概念、属性、方法
    移动端新建html页面
    《程序员思维修炼》读后摘录
    做一个简单的贪吃蛇游戏
    做一个简单的遮罩层
    在不同设备上控制元素
  • 原文地址:https://www.cnblogs.com/liujingg/p/4633861.html
Copyright © 2020-2023  润新知