ScrollView嵌套EditText不能滑动问题

ScrollView嵌套EditText不能滑动问题

Android小彩虹2021-07-15 0:45:2480A+A-

问题

在ScrollView中嵌套EditText是非常常见的,例如下面的页面:

投诉反馈具体内容这块,要求里面的EditText可以上下滑动,但是它嵌套在ScrollView里面,无法滑动。

原因

外层ScrollView将滑动事件消费了,导致滑动事件没有向下传递,EditText根本没有接收到该事件。

这里就要说一下事件分发机制了:

一般情况下事件分发会遵循activity / fragment-->ViewGroup-->View,其中涉及事件分发的核心方法如下:

  • dispatchTouchEvent()
  • onTouchEvent()
  • onInterceptTouchEvent()

但并非所有组件中都含有这三个方法,它们的存在情况如下:

组件 dispatchTouchEvent() onTouchEvent() onInterceptTouchEvent()
activity 存在 存在 不存在
ViewGroup 存在 存在 存在
View 存在 存在 不存在

它们的作用如下:

方法 作用 调用时刻
dispatchTouchEvent() 分发(传递)点击事件 当点击事件能够被传递给当前View时调用
onTouchEvent() 处理点击事件 在dispatchTouchEvent()内部调用
onInterceptTouchEvent() 判断是否拦截某个事件 在dispatchTouchEvent()内部调用

它们的返回结果如下:

看到这里,相信大家已经想到好几种解决方法了吧。下面给出我的解决方案:

解决

新建类SolveEditTextScrollClash 实现 View.OnTouchListener

重写onTouch()如下:

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        //触摸的是EditText而且当前EditText能够滚动则将事件交给EditText处理。否则将事件交由其父类处理
        if ((view.getId() == editText.getId() && canVerticalScroll(editText))) {
            view.getParent().requestDisallowInterceptTouchEvent(true);
            if (event.getAction() == MotionEvent.ACTION_UP) {
                view.getParent().requestDisallowInterceptTouchEvent(false);
            }
        }
        return false;
    }

其中canVerticalScroll()如下:

   /**
     * EditText竖直方向能否够滚动
     * @param editText  须要推断的EditText
     * @return  true:能够滚动   false:不能够滚动
     */
    private boolean canVerticalScroll(EditText editText) {
        //滚动的距离
        int scrollY = editText.getScrollY();
        //控件内容的总高度
        int scrollRange = editText.getLayout().getHeight();
        //控件实际显示的高度
        int scrollExtent = editText.getHeight() - editText.getCompoundPaddingTop() -editText.getCompoundPaddingBottom();
        //控件内容总高度与实际显示高度的差值
        int scrollDifference = scrollRange - scrollExtent;
        if(scrollDifference == 0) {
            return false;
        }
        return (scrollY > 0) || (scrollY < scrollDifference - 1);
    }

完整的类如下:

public class SolveEditTextScrollClash implements View.OnTouchListener {

    private EditText editText;

    public SolveEditTextScrollClash(EditText editText) {
        this.editText = editText;
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        //触摸的是EditText而且当前EditText能够滚动则将事件交给EditText处理。否则将事件交由其父类处理
        if ((view.getId() == editText.getId() && canVerticalScroll(editText))) {
            view.getParent().requestDisallowInterceptTouchEvent(true);
            if (event.getAction() == MotionEvent.ACTION_UP) {
                view.getParent().requestDisallowInterceptTouchEvent(false);
            }
        }
        return false;
    }

    /**
     * EditText竖直方向能否够滚动
     * @param editText  须要推断的EditText
     * @return  true:能够滚动   false:不能够滚动
     */
    private boolean canVerticalScroll(EditText editText) {
        //滚动的距离
        int scrollY = editText.getScrollY();
        //控件内容的总高度
        int scrollRange = editText.getLayout().getHeight();
        //控件实际显示的高度
        int scrollExtent = editText.getHeight() - editText.getCompoundPaddingTop() -editText.getCompoundPaddingBottom();
        //控件内容总高度与实际显示高度的差值
        int scrollDifference = scrollRange - scrollExtent;
        if(scrollDifference == 0) {
            return false;
        }
        return (scrollY > 0) || (scrollY < scrollDifference - 1);
    }
}

用法如下:

etContent.setOnTouchListener(new SolveEditTextScrollClash(etContent));

思考

ScrollView内嵌套其他能滑动的控件时都会遇到这样的问题,其解决方法都与上面类似,重写滑动冲突控件的onTouch()方法。

结语

能力有限,文章中可能有错误或者不严谨的地方,欢迎批评指正,不喜勿喷。

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1

联系我们