下拉刷新和上拉加载的ListView-MutilListView

public class LoadListView extends ListView implements OnScrollListener {
    private int firstItem;// 当前可以见第一个Item的位置
    private int lastItem;// 当前可以见最后一个Item的位置
    private int totalItemCount;// list总数量

    private OnLoadListener mListener;// 回调接口
    private boolean isLoading = false;;// 是否正在加载

    private View footer;// 底布局文件
    private View head;// 头布局文件
    private int headHeigth;// 布局高度

    // 下拉刷新相关
    private boolean isRemark;// 是否在第一个Item按下
    private int startY;// 滑动开始前的Y值
    private int state;// 当前状态
    private final int NONE = 0;// 正常状态
    private final int PULL = 1;// 提示下拉状态
    private final int RELESE = 2;// 提示释放状态
    private final int REFLASHING = 3;// 刷新状态状态
    private int scrollState;// 当前listview的状态

    public LoadListView(Context context) {
        super(context);
        initView(context);
    }

    public LoadListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public LoadListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    private void initView(Context context) {
        LayoutInflater mInflater = LayoutInflater.from(context);
        // 底布局操作相关
        footer = mInflater.inflate(R.layout.listiview_footer, null);
        footer.findViewById(R.id.footer_ll_layout).setVisibility(View.GONE);
        this.addFooterView(footer);

        head = mInflater.inflate(R.layout.listview_head, null);
        // 通知父布局Head占用的大小
        measureHead(head);
        // 获取高度
        headHeigth = head.getMeasuredHeight();
        // 设置头布局为高度的负值而隐藏
        setHeaderPaddingTop(-headHeigth);
        this.addHeaderView(head);
        this.setOnScrollListener(this);
    }

    /**
     * 通知父布局Head占用的大小 (此处本人也未彻底搞懂)
     * 
     * @param view
     */
    private void measureHead(View view) {
        ViewGroup.LayoutParams p = view.getLayoutParams();
        if (p == null) {
            p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
        int height;
        int tempHeight = p.height;
        if (tempHeight > 0) {
            height = MeasureSpec.makeMeasureSpec(tempHeight,
                    MeasureSpec.EXACTLY);
        } else {
            height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        view.measure(width, height);
    }

    /**
     * 设置Head布局的上边距,以达到隐藏头布局的目的
     * 
     * @param paddingTop
     */
    private void setHeaderPaddingTop(int paddingTop) {
        head.setPadding(head.getPaddingLeft(), paddingTop,
                head.getPaddingRight(), head.getPaddingBottom());
        // 刷新View的方法
        head.invalidate();
    }

    /**
     * 下拉刷新 监听手指的滑动状态
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // 如果实在顶部开始滑动 则记录当前y的位置,后面用来计算滑动的距离
            if (firstItem == 0) {
                startY = (int) ev.getY();
                isRemark = true;
            }
            break;
        case MotionEvent.ACTION_MOVE:
            onMove(ev);// 判断手指滑动过程中的动作
            break;
        case MotionEvent.ACTION_UP:
            // 手指抬起后用来判断是否到达刷新数据要求的目的
            if (state == RELESE) {
                state = REFLASHING;
                // 加载最新数据
                reflushData();
            } else if (state == PULL || state == NONE) {
                state = NONE;
                isRemark = false;
                reflushViewByState();
            }
            break;
        }
        return super.onTouchEvent(ev);
    }

    private void onMove(MotionEvent ev) {
        if (!isRemark) {
            return;
        }
        int tempY = (int) ev.getY();
        Log.v("y", tempY + "");
        // 滑动的距离
        int distance = tempY - startY;
        // 头布局慢慢显示出来的宽度
        int topPadding = distance - headHeigth;
        switch (state) {
        case NONE:
            if (distance > 0) {
                state = PULL;
                reflushViewByState();
            } else {
            }
            break;
        case PULL:
            // 绘制当前 拉动过程的头布局
            setHeaderPaddingTop(topPadding);
            // 如果距离大于头布局+100 dp且ListView在滑动过程中
            if (distance > headHeigth + 100
                    && scrollState == SCROLL_STATE_TOUCH_SCROLL) {
                state = RELESE;
                reflushViewByState();
            }
            break;
        case RELESE:
            // 绘制当前 拉动过程的头布局
            setHeaderPaddingTop(topPadding);
            if (distance < headHeigth + 100) {
                state = PULL;
                reflushViewByState();
            } else if (distance <= 0) {
                state = NONE;
                isRemark = false;
                reflushViewByState();
            } else if (distance > 500) {
            }
            break;
        }
    }

    /**
     * 刷新数据的执行方法
     */
    private void reflushData() {
        state = REFLASHING;
        isRemark = false;
        reflushViewByState();
        mListener.onRefresh();
    }

    /**
     * 根据当前状态改变界面显示
     * 
     * @param state
     */
    private void reflushViewByState() {
        TextView tip = (TextView) head.findViewById(R.id.head_tv_tips);
        ImageView pic = (ImageView) head.findViewById(R.id.head_iv_pic);
        ProgressBar pb = (ProgressBar) head.findViewById(R.id.head_pb_progress);

        RotateAnimation anim = new RotateAnimation(0, 180,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        anim.setDuration(500);
        anim.setFillAfter(true);
        RotateAnimation anim1 = new RotateAnimation(180, 0,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        anim1.setDuration(500);
        anim1.setFillAfter(true);
        switch (state) {
        case NONE:
            setHeaderPaddingTop(-headHeigth);
            break;
        case PULL:
            tip.setText("下拉可以刷新!");
            pic.setVisibility(View.VISIBLE);
            pb.setVisibility(View.GONE);
            // 设置相关动画
            pic.clearAnimation();
            pic.setAnimation(anim);
            break;
        case RELESE:
            tip.setText("松开可以刷新!");
            pic.setVisibility(View.VISIBLE);
            pb.setVisibility(View.GONE);
            // 设置相关动画
            pic.setAnimation(anim1);
            break;
        case REFLASHING:
            setHeaderPaddingTop(0);
            tip.setText("正在刷新!");
            pic.clearAnimation();// 这里一定要执行清楚动画,不然图片无法隐藏
            pic.setVisibility(View.GONE);
            pb.setVisibility(View.VISIBLE);
            break;
        }
    }

    // 下拉刷新完成回调
    public void reflushCompleted() {
        state = NONE;
        isRemark = false;
        reflushViewByState();
    }

    // 分页加载完成回调
    public void flushCompleted() {
        isLoading = false;
        footer.findViewById(R.id.footer_ll_layout).setVisibility(View.GONE);
    }

    public void setOnLoadListener(OnLoadListener listener) {
        this.mListener = listener;
    }

    public interface OnLoadListener {
        // 分页加载
        void onLoadMore();

        // 下拉刷新
        void onRefresh();
    }


    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (lastItem == totalItemCount && SCROLL_STATE_IDLE == scrollState) {
            if (!isLoading) {
                footer.findViewById(R.id.footer_ll_layout).setVisibility(
                        View.VISIBLE);
                mListener.onLoadMore();
                isLoading = true;
            }
        }
        this.scrollState = scrollState;
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        this.lastItem = firstVisibleItem + visibleItemCount;
        this.totalItemCount = totalItemCount;
        this.firstItem = firstVisibleItem;
    }
}

以上是实现了了下拉刷新和上拉加载第二页的ListView代码。
欢迎各位指出错误,大家多多指教。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值