自定义ListView,如何实现下拉刷新

自定义ListView下拉刷新的功能,给出一个不完整的东西,仅作思路和笔记:

代码参考了http://www.imooc.com/learn/135,一些地方做了自己的优化


public class DragList extends ListView implements OnScrollListener {

    // 下拉头的View和子View
    View header;
    TextView tip;
    TextView lastupdate_time;
    ImageView arrow;
    ProgressBar progress;

    // 下拉头高度
    int headerHeight;

    // 下拉刷新的回调
    PullRefreshListener onPullListener;

    // 下拉状态下的header的几个状态
    final int NORMAL = 0;
    final int PULL = 1;
    final int REFRESH = 2;
    final int REFRESHING = 3;

    // 用于控制onLayout只执行一次
    private boolean once = true;

    // listView第一个可见item的pos,用于指示listView,只有在这个值是0,
    //即目前header刚好隐藏在屏幕上方时才开始动态设置header的toppadding使之有隐藏显示的效果
    int firstVisibleItem;

    int yDown;
    int yMove;//move过程中y坐标
    boolean mark;// 如果是在顶端,才可以拉下去,否则不能拉至header(配合firstVisibleItem使用)
    int space;//一次的下拉距离
    int state = NORMAL;//初始状态

    // 没有使用自定义属性,系统调用两个参数的构造
    public DragList(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    // 使用系统的measure进行空间测量
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    // 隐藏header,方法是设置header的toppadding值为负的自身高度。
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (once) {
            headerHeight = header.getMeasuredHeight();
            topPadding(-headerHeight);
            once = false;
        }
    }

    // 简单的初始化和滚动监听
    private void initView(Context context) {
        LayoutInflater inflate = LayoutInflater.from(context);
        header = inflate.inflate(R.layout.header_layout, null);
        tip = (TextView) header.findViewById(R.id.tip);
        lastupdate_time = (TextView) header.findViewById(R.id.lastupdate_time);
        arrow = (ImageView) header.findViewById(R.id.arrow);
        progress = (ProgressBar) header.findViewById(R.id.progress);
        this.addHeaderView(header);
        this.setOnScrollListener(this);
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    //监听Scroll时间,设置当前ListView的第一个item,header是第0个,一般情况下,当ListView滑动到第1个item时,上边缘贴住父View的上边缘,这时ListView
    //的第一个item就是0,即可以理解为,item之间的devider属于上面的一个item,
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        this.firstVisibleItem = firstVisibleItem;
    }



    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            if (firstVisibleItem == 0) {
                mark = true;
                yDown = (int) ev.getY();
            }

            break;
        case MotionEvent.ACTION_MOVE:
            //这个方法主要任务是设置state的状态值,具体工作在Up中
            onMove(ev);
            break;
        case MotionEvent.ACTION_UP:
            if (state == REFRESH) {
                state = REFRESHING;
                updateHeader();
                // 做一些数据刷新的工作,这个由具体对象设置
                onPullListener.onPull();
            } else if (state == PULL) {
                state = NORMAL;
                mark = false;
                updateHeader();
            }
            break;
        }

        return super.onTouchEvent(ev);
    }

    private void onMove(MotionEvent ev) {
        if (!mark) {
            return;
        }

        yMove = (int) ev.getY();
        space = yMove - yDown;
        int topPadding = space - headerHeight;
        switch (state) {
        case NORMAL:
            //下拉情况
            if (space > 0) {
                state = PULL;
                updateHeader();
            }
            break;
        case PULL:
            //PULL状态表示还没达到一个阈值
            topPadding(topPadding);

            //距离大于这个值表示松开就刷新了
            if (space > headerHeight + 40) {
                state = REFRESH;
                updateHeader();
            }
            break;
        case REFRESH:
            // if (topPadding > 100)
            // return;
            topPadding(topPadding);

            //达到状态REFRESH但是又滑回去了,状态值重置
            if (space < headerHeight + 40) {
                state = PULL;
                updateHeader();
            } else if (space < 0) {
                state = NORMAL;
                updateHeader();
            }
            break;

        }

    }

    private void updateHeader() {
        switch (state) {
        case NORMAL:
            topPadding(-headerHeight);
            break;
        case PULL:
            arrow.setVisibility(View.VISIBLE);
            progress.setVisibility(View.GONE);
            tip.setText("下拉可以刷新!");
            break;
        case REFRESH:
            arrow.setVisibility(View.VISIBLE);
            progress.setVisibility(View.GONE);
            tip.setText("松开可以刷新!");
            break;
        case REFRESHING:
            //这个状态下由于没有方法将state设置回去,state一直保持REFRESHING,所以无法向下滑动动态设置header的toppadding
            //具体使用时需要完善
            arrow.setVisibility(View.GONE);
            progress.setVisibility(View.VISIBLE);
            tip.setText("正在刷新...");

            break;
        }
    }

    private void topPadding(int topPadding) {
        header.setPadding(header.getPaddingLeft(), topPadding,
                header.getPaddingRight(), header.getPaddingBottom());
        header.invalidate();
    }

    public interface PullRefreshListener {
        void onPull();
    }

    public void setOnPullListener(PullRefreshListener onPullListener) {
        this.onPullListener = onPullListener;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值