android scrollview listview的嵌套问题

本文探讨了在Android开发中遇到ScrollView与ListView嵌套的问题,建议将元素放入ListView的headview以避免嵌套。若必须嵌套,可以设置ListView高度为0,然后在ScrollView渲染后调整其高度。同时,需要修改ScrollView的触屏事件处理。参考代码可从GitHub项目获取。
摘要由CSDN通过智能技术生成

     android scrollview和listview的嵌套问题

在实际的项目中,我们可能会碰到scrollview嵌套listview的情况,最好的解决方法是如果能把这个元素放到listview的headview是最好的。如果必须得嵌套在scrollview中,我们应该怎么做呢?

       1、首先,在xml中将listview的高度设置为0;

       2、在scrollview渲染之后,设置listview的高度为scrollview的高度,这样会形成一个吸顶效果;

      

ViewTreeObserver viewTreeObserver = mScrollView.getViewTreeObserver();
        if (viewTreeObserver.isAlive()) {
            viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    mScrollView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    int viewHeight = mScrollView.getHeight();
                    mListView.getLayoutParams().height = viewHeight;
                }
            });
        }

      3、需要调整scrollview的触屏事件处理模块,dispatchTouchEvent(MotionEvent ev),具体的参考下面的demo代码;

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mImitateTouch = false;
                mIsBeingDragged = false;
                mLastMotionY = (int) ev.getY();
                mOriInterupt = mInterupt;
                final float offsetX = getScrollX() - mListView.getLeft();
                final float offsetY = getScrollY() - mListView.getTop();

                // 表示scrollview仍有部分可见,同时点击事件是在嵌套的view中(如listview、viewpager),模拟一个点击事件
                if ((int)(offsetX+ev.getX()) >= 0 && (int)(offsetY+ev.getY()) >= 0 && canScrollDown(1)) {
                    imitateTouchEvent(ev, mListView);
                    mImitateTouch = true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                final int y = (int) ev.getY();
                int deltaY = mLastMotionY - y;
                boolean isSrollDown;
                if (deltaY > 0) {
                    isSrollDown = true;
                } else {
                    isSrollDown = false;
                }

                if (!mIsBeingDragged) {
                    if (Math.abs(deltaY) > mTouchSlop) {
                        mIsBeingDragged = true;
                        deltaY = deltaY > 0 ? deltaY-mTouchSlop : deltaY+mTouchSlop;
                    } else {
                        break;
                    }
                }

                // 如果有模拟事件,因为有move事件,需要发送一个cancel事件给嵌套的view(这里是listview,viewpager情况会更加复杂一些)
                if (mImitateTouch) {
                    imitateTouchEvent(MotionEvent.ACTION_CANCEL, ev.getX(), ev.getY(), mListView);
                    mImitateTouch = false;
                }

                if (!isSrollDown) {
                    // 从上向下滑动,同时listview不能继续滑动
                    if (!canScrollList(-1, mListView)) {
                        mInterupt = true;
                        // 从listview滑向scrollview,由于scrollview没有获取事件响应,需要手动控制
                        if (!mOriInterupt) {
                            mDisable = true;
                            scrollBy(0, deltaY);
                        } else {
                            mDisable = false;
                        }
                    } else {
                        mDisable = true;
                        if (mImitateClicked) {
                            imitateTouchEvent(ev, mListView);
                        }
                    }
                } else {
                    // 从下向上滑动,同时scrollview不能继续滑动
                    if (!canScrollDown(1)) {
                        // 通过scrollview滑动到listview,由于嵌套的listview没有获取事件响应,需要为listview模拟一个down事件
                        if (mOriInterupt && mInterupt) {
                            imitateTouchEvent(MotionEvent.ACTION_DOWN, ev.getX(), ev.getY(), mListView);
                            mImitateClicked = true;
                        }
                        // 继续为listview模拟后续的move事件
                        if (mOriInterupt) {
                            imitateTouchEvent(ev, mListView);
                        }
                        mInterupt = false;
                        mDisable = true;
                    } else {
                        mInterupt = true;
                        // 嵌套的view获取了事件响应,需要为外层的scrollview手动触发滑动
                        if (canScrollDown(-1) && !mOriInterupt) {
                            mDisable = true;
                            scrollBy(0, deltaY);
                        } else  {
                            mDisable = false;
                        }
                    }
                }
                mLastMotionY = y;
                break;
            case MotionEvent.ACTION_UP:
                mOriInterupt = mInterupt;
                if (mImitateTouch || mImitateClicked) {
                    imitateTouchEvent(ev, mListView);
                    mImitateTouch = mImitateClicked = false;
                }
                break;

        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mInterupt;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (mDisable) {
            return true;
        } else {
            return super.onTouchEvent(ev);
        }
    }


代码示例:https://github.com/xsbupt/nestscrollview


后续会继续更新scrollview嵌套webview,viewpager等的嵌套问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值