自定义ListView下拉刷新上拉加载

自定义ListView下拉刷新上拉加载

ONE Goal,ONE Passion!                  
                                              ---czfy

公司让分析项目,发现一个效果确实不错,分析了半天,用了一种感觉很low的方法实现了,感觉那个效果肯定是属性动画做出来,等明天开始学习怎样去写那个效果吧.属性动画确实不错,建议可以参考”宏洋”大神的博客吧,写的确实不错!好了,开始今天的正题.
—自定义ListView下拉刷新上拉加载

第一步:PullRefreshListView完整代码

public class PullRefreshListView extends ListView {


    Context context;
    private View refresh_header;  //刷新头
    private View refresh_footer;   //刷新脚布局
    private int refresh_headerMeasuredHeight;   //刷新头的高度
    private int refresh_footerMeasuredHeight;   // 刷新脚的高度
    private ImageView refresh_img;              //做动画的图
    private ProgressBar refresh_header_progressbar;


    private int currentState = 0;      //刷新头的当前状态

    private int DOWNPULL_REFRESH = 1;  //  下拉刷新
    private int RELEASE_REFRESH = 2;  //  释放刷新
    private int DOING_REFRESH = 3;  //    正在刷新

    private boolean isMoreLoding = true;  //    防止上拉时多次请求加载更多.只有当第一次加载完成后才能进行第二次加载


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

    public PullRefreshListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PullRefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        this.context = context;

        initView();

    }


    /**
     * 初始化 头布局,以及脚布局
     */
    private void initView() {
       //自己的刷新头布局
        refresh_header = View.inflate(context, R.layout.refresh_header, null);
        //自己想要的刷新脚布局
        refresh_footer = View.inflate(context, R.layout.refresh_footer, null);

    //添加头,脚布局
        addHeaderView(refresh_header);
        addFooterView(refresh_footer);


        refresh_img = (ImageView) refresh_header.findViewById(R.id.refresh_header_imageview);
        refresh_header_progressbar = (ProgressBar) findViewById(R.id.refresh_header_progressbar);

        //得到刷新头的高度
        refresh_header.measure(0, 0);
        refresh_headerMeasuredHeight = refresh_header.getMeasuredHeight();

        //得到刷新脚的高度
        refresh_footer.measure(0, 0);
        refresh_footerMeasuredHeight = refresh_footer.getMeasuredHeight();

        //隐藏刷新头,脚
        refresh_header.setPadding(0, -refresh_headerMeasuredHeight, 0, 0);
        refresh_footer.setPadding(0,-refresh_footerMeasuredHeight,0,0);

    //为listview设置滑动监听
        this.setOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (scrollState == OnScrollListener.SCROLL_STATE_IDLE && getLastVisiblePosition() == getCount() - 1) {


                    if (mOnRefreshListener != null && isMoreLoding) {
                        isMoreLoding = false;
                        //显示脚布局
                        refresh_footer.setPadding(0,0,0,0);
                        mOnRefreshListener.refreshFooter();
                    }


                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

            }
        });


    }


    private int downY;  //downY的位置
    private int moveY;  //moveY的位置
    private int disY;  //disY的大小
    private int moveTop;  //刷新头移动的后应该隐藏的高度


    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        int action = ev.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN:

                // getFirstVisiblePosition() 返回屏幕上显示第一条item的position
                if (getFirstVisiblePosition() == 0) {

                    currentState = DOWNPULL_REFRESH;
                    downY = (int) ev.getY();

                }

                break;
            case MotionEvent.ACTION_MOVE:

                if ((int) ev.getY() - downY > 300) {  // 如果滑动的距离大于300就不允许滑动了
                    return true;
                }


                //只有当第一个item显示的在屏幕上的时候才允许出现刷新头
                if (getFirstVisiblePosition() == 0) {

                    moveY = (int) ev.getY();

                    disY = moveY - downY;


                    if (disY > 0) {

                        moveTop = -refresh_headerMeasuredHeight + disY;
                        refresh_header.setPadding(0, moveTop, 0, 0);

                        /**
                         * 1,  如果是下拉刷新状态(下拉过程)且刷新头已经全部显示
                         */
                        if (currentState == DOWNPULL_REFRESH && moveTop > 0) {

                            currentState = RELEASE_REFRESH;

                            refreshState(currentState);

                        }


                        /**
                         *  2,如果是释放刷新状态,但是又不刷新,而是将刷新头送回
                         */
                        if (currentState == RELEASE_REFRESH && moveTop < 0) {

                            currentState = DOWNPULL_REFRESH;
                            refreshState(currentState);
                        }


                    }

                }


                break;
            case MotionEvent.ACTION_UP:


                if (currentState == DOWNPULL_REFRESH) {
                    //隐藏刷新头
                    refresh_header.setPadding(0, -refresh_headerMeasuredHeight, 0, 0);

                }

                if (currentState == RELEASE_REFRESH) {  //释放刷新

                    currentState = DOING_REFRESH;
                    refreshState(currentState);

                }


                break;
        }


        return super.onTouchEvent(ev);
    }

    /**
     * 刷新头布局的状态
     */
    private void refreshState(int state) {

        switch (state) {
            case 1:                //  下拉刷新状态.

                up2down();

                break;
            case 2:                 //释放刷新

                down2up();


                break;
            case 3:    // 正在刷新

                refresh_img.clearAnimation();  //把动画清空
                refresh_header_progressbar.setVisibility(View.VISIBLE);
                refresh_img.setVisibility(View.GONE);

                if (mOnRefreshListener != null) {
                    mOnRefreshListener.refreshHeader();
                }


                break;

        }


    }

    /**
     * 刷新完成
     *
     * @param flag 0:刷新完成调用时传递的参数
     *             1:加载完成时传达的参数
     */
    public void refreshComplete(int flag) {

        switch (flag) {
            case 0:       //  刷新完成
 // 数据刷新是直接对集合添加了,速度太快,可能看不到圆形进度条.正常开发是是可以看到的             refresh_header_progressbar.setVisibility(View.INVISIBLE);
                refresh_img.setVisibility(View.VISIBLE);
                refresh_header.setPadding(0, -refresh_headerMeasuredHeight, 0, 0);

                break;
            case 1:    //加载完成

                isMoreLoding = true;
             //   refresh_footer.setPadding(0,-refresh_footerMeasuredHeight,0,0);  把这句注释掉是因为数据加载是直接对集合添加了,速度太快,可能看不到脚布局.正在项目中使用时应该加上这句代码

                break;
        }


    }

    /**
     * 1,让刷新头的箭头至下向上旋转
     * 2,改变文字提示
     */
    public void down2up() {
        RotateAnimation down2up = new RotateAnimation(0, -180,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);
        down2up.setDuration(200);
        down2up.setFillAfter(true);

        refresh_img.startAnimation(down2up);

    }

    /**
     * 1,让刷新头至上向下旋转
     * 2,改变文字提示
     */
    public void up2down() {

        RotateAnimation up2down = new RotateAnimation(-180, 0,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);

        up2down.setDuration(200);
        up2down.setFillAfter(true);
        refresh_img.startAnimation(up2down);


    }


    /**
     * 暴露给外部使用的回调方法
     *
     * @param mOnRefreshListener
     */
    public void setOnRefreshListener(OnRefreshListener mOnRefreshListener) {
        this.mOnRefreshListener = mOnRefreshListener;
    }

    public OnRefreshListener mOnRefreshListener;

    public interface OnRefreshListener {

        // 刷新数据的回调
        void refreshHeader();

        //加载更多数据的回调
        void refreshFooter();

    }


}

第二步: 一些用到的布局

头布局文件 R.layout.refresh_header:

<?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">

    <LinearLayout
        android:id="@+id/refresh_header_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <FrameLayout
            android:layout_margin="5dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

<!--这里ProgressBar隐藏用的是invisible 因为这个属性值会将ProgressBar不显示,但是还是会占位置 -->
            <ProgressBar
                android:id="@+id/refresh_header_progressbar"
                android:visibility="invisible"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>


            <ImageView
                android:id="@+id/refresh_header_imageview"
                android:layout_gravity="center"
                android:src="@drawable/red_arrow"   //你自己的图片,就是一个箭头
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </FrameLayout>
        <LinearLayout
            android:layout_gravity="center"
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">
            <TextView
                android:layout_gravity="center"
                android:id="@+id/refresh_header_text"
                android:text="下拉刷新"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <TextView
                android:layout_gravity="center"
                android:id="@+id/refresh_header_time"
                android:text="1999-10-10"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </LinearLayout>
    </LinearLayout>





</LinearLayout>

脚布局文件 R.layout.refresh_footer:

<?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:id="@+id/refresh_footer_root"
    android:orientation="horizontal" 
    android:gravity="center">

    <ProgressBar 
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView 
        android:text="正在加载..."
        android:layout_margin="20dp"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>


</LinearLayout>

第三步:如何使用

像正常使用系统listview一样:

//设置监听
 lv.setOnRefreshListener(new PullRefreshListView.OnRefreshListener() {
            @Override
            public void refreshHeader() {

                mList.add(0,"刷新出来的数据");
                lv.refreshComplete(0);  adapter.notifyDataSetChanged();

            }

            @Override
            public void refreshFooter() {
                mList.add(mList.size(), "加载出来的数据");

                lv.refreshComplete(1);
                adapter.notifyDataSetChanged();
            }
        });

第四步:箭头图片资源

这里写图片描述

这里写图片描述 箭头图片

注意:刷新过程中,文字和时间这里我没有做处理,使用时处理一下就可以了.我们自定义的listview已经实现了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值