完美解决!隐藏listview的headerView,实现动态下拉,(仿ios)

这两天在做项目的 时候遇到了这个问题,发现网上也有人提出了这个问题,但是根本没有人去解决,可能是问题太简单了。我在这里贴上我的代码,以往对大家有帮助。

首先,实现的效果,希望是这样的。




网上也给出了一些解决方案,但是根本没有实现动态的下拉呀。(下面贴出网上解决方案的截图)



接下来再来描述一下问题。我要实现的是listview的headerview 一开始是隐藏的。我把它拉下来,它就可见了,(自己写的。由于是公司的代码,不能贴出完整项目,还是希望对大家有帮助)

/**
 * 下拉出现顶部HeaderView
 *
 */
public class PullShowHeaderListView extends ListView {

    private View mHeaderView;
    private int startY = -1;// 滑动起点的y坐标
    private int mHeaderViewHeight;//headerview 的高
    private static final int STATE_PULLING_DOWN = 0;//下拉状态
    private static final int STATE_PULLING_UP = 1;//上拉状态
    private int pulling_state = -1;

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

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

    public PullShowHeaderListView(Context context) {
        this(context, null, 0);
    }


    /**
     * 初始化头布局
     * init headerView in your code, init header Id first
     */
    public void initHeaderView(Context context, int layoutId) {
        mHeaderView = View.inflate(context, layoutId, null);
        this.addHeaderView(mHeaderView, null, false);        //这样可以让HeaderView不可点击
        mHeaderView.measure(0, 0);
        mHeaderViewHeight = mHeaderView.getMeasuredHeight();//我这里得到的结果是152
        mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏头布局1
        mHeaderView.setVisibility(View.GONE);// 隐藏头布局2
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
//                startY = -1;// 重置
                startY = (int) ev.getRawY();
                Log.i("---->PullShowHeaderListView", "startY " + startY);
                Log.i("---->PullShowHeaderListView", "getFirstVisiblePosition " + getFirstVisiblePosition());
                if (getFirstVisiblePosition() == 0 && mHeaderView.getPaddingTop() != 0) {//在第一个条目可见的情况下,将headerview置为visible,但是隐藏起来
                    mHeaderView.setVisibility(View.VISIBLE);//mHeaderView.getPaddingTop() 如果等于0表示headerView完全可见(也就是我们已经把它拉下来了,此时不需要进行操作)
                    mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
                    Log.i("---->PullShowHeaderListView", " visible,but hide");
                } else if (getFirstVisiblePosition() != 0) {
                    mHeaderView.setVisibility(View.GONE);
                    mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
                    Log.i("---->PullShowHeaderListView", "not visible,and hide");
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (mHeaderView.getVisibility() != View.VISIBLE) { //保证下面代码是在,headerview置为visible的情况下才进行操作,
                    break;
                } else {
                    int endY = (int) ev.getRawY();//得到滑动中的距离
                    int dy = endY - startY;// 移动偏移量
                    Log.i("---->PullShowHeaderListView", "endY -startY" + dy);
                    int padding = 0;
                    if (dy > 10 && mHeaderView.getPaddingTop() != 0 && pulling_state != STATE_PULLING_UP) {  // 当手指向下滑动了一定的距离(并且此时的headerView并不是完全可见的)
                        pulling_state = STATE_PULLING_DOWN;
                        padding = getPadding(dy);//控制padding大小在0到-mHeaderViewHeight之间
                        mHeaderView.setPadding(0, padding, 0, 0);
                        Log.i("---->PullShowHeaderListView", "down padding of the headerView" + padding);
                    }
                    if (dy < -10 && mHeaderView.getPaddingTop() != -mHeaderViewHeight && pulling_state != STATE_PULLING_DOWN) {//当手指向上滑动了一定的距离(并且此时的headerView并不是完全隐藏的)
                        pulling_state = STATE_PULLING_UP;
                        padding = getPadding(dy);//控制padding大小在0到-mHeaderViewHeight之间
                        mHeaderView.setPadding(0, padding, 0, 0);
                        Log.i("---->PullShowHeaderListView", "up padding of the headerView" + padding);
                    }

                }

                break;
            case MotionEvent.ACTION_UP:
                if (mHeaderView.getPaddingTop() <= -mHeaderViewHeight / 2) {
                    mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
                    mHeaderView.setVisibility(View.GONE);
                    Log.i("---->PullShowHeaderListView", "more than 1/2,hiding");
                } else if (mHeaderView.getPaddingTop() > -mHeaderViewHeight / 2) {
                    mHeaderView.setPadding(0, 0, 0, 0);// 显示
                    mHeaderView.setVisibility(View.VISIBLE);
                    Log.i("---->PullShowHeaderListView", "less than 1/2,show");
                }
                startY = -1;// 重置
                pulling_state = -1;
                break;
            default:
                break;
        }
        return super.onTouchEvent(ev);
//        return false;
    }

    private int getPadding(int dy) {
        int padding = 0;
        if (pulling_state == STATE_PULLING_DOWN) {//dy为正数,此时必须限定padding范围为-150~0
            padding = dy - mHeaderViewHeight;
            if (padding > 0) {
                padding = 0;
            }
        } else if (pulling_state == STATE_PULLING_UP) {//dy为负数,此时必须限定padding范围为0~-150
            padding = dy;
            if (padding < -mHeaderViewHeight) {
                padding = -mHeaderViewHeight;
            }
        }
        return padding;
    }


    public View getHeaderView() {
        return mHeaderView;
    }

    /**
     * 拦截事件。确保在item上面的click不消耗事件,从而在上面可以下拉
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return true;
    }
}

好了,接下来,就是在布局文件中引用这个自定义的view。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.view.PullShowHeaderListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:listSelector="@drawable/list_item_selector"
        android:drawSelectorOnTop="true" />

</FrameLayout>

在自己的activity里面可以引用了:

 <pre name="code" class="java">        list_view = (PullShowHeaderListView) view.findViewById(R.id.list_view);//添加了隐藏HeaderView的ListView
        list_view.initHeaderView(mContext, R.layout.header_view);
        list_view.setOnItemClickListener(new MyOnItemClickListener());
        list_view.setOnItemLongClickListener(new MyOnItemLongClickLister());

 好了,里面的headerview是我自定义的一个布局。你可以自定义一个自己的布局。 

整个自定义view主要实现的就是下拉和上拉以及隐藏和显示headerview的情况。

讲讲我自己遇到的问题。需要注意的情况:

由于自定义了OnTouchEvent,大家可以看看事件分发的一些问题。你会发现在空白区域是可以把listview下拉的,但是在我们的listview的item上面,就无法下拉。这是因为我们的item的click消耗了事件的传递。我也就在OnInterceTouchEvent中返回true,代表不让我们的item得到事件。所以实现了item上面也可以下拉。

这是后就注意了,item就不可以自定义click事件,但是我们可以定义ListView的ItemClickLIstener和ItemLongClickListener呀。

最后贴两个讲解非常棒的事件分发机制的大神帖:

http://blog.csdn.net/guolin_blog/article/details/9097463/

http://blog.csdn.net/xiaanming/article/details/21696315

希望对大家有帮助


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值