真正完美解决EditText嵌套ScrollView的滑动冲突

最近项目有需要 用到 edittext 嵌套在 srolllview的情况,由于edittext 如果多行的情况下,是可以上下滑动的,但是由于嵌套了scrollview,所以会产生滑动冲突,所以我随手网上一搜解决方案,不出所料,很多解决方案。

微笑
微笑
然后当我应用于项目中,实际测试了一下,发现并不完美。

网上的方案是,直接将滑动事件交由edittex处理,但是这种方案并不完美,因为只有滑动edittext区域外的地方才能滑动ScrollView,这样如果你的edittext的高度很大,甚至占满了一个屏幕,那么很抱歉,因为点不到edittext区域外的地方了,所以Scrollview就不能再滑动了,是不是很坑爹。


微笑
微笑

我们的需求是当edittext是多行需要上下滑动的时候,将滑动事件交给edittetx,并且 edittext滑动到底部或者顶部的时候,将事件还给 scrollview,
以此实现滑动联动。所以我简单的对网上的方案修改了一下,最终代码如下,大家可以直接拿去用,将自己项目种的edittext替换掉就行了,亲测有效。

**
 * Created by Sherlock on 2017/6/14.
 * 用于解决嵌套Scrollview的时候由于多行而产生的滑动冲突问题
 */
public class EditTextWithScrollView extends EditText {

    //滑动距离的最大边界
    private int mOffsetHeight;

    //是否到顶或者到底的标志
    private boolean mBottomFlag = false;
    private boolean mCanVerticalScroll;

    public EditTextWithScrollView(Context context) {
        super(context);
        init();
    }

    public EditTextWithScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public EditTextWithScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mCanVerticalScroll = canVerticalScroll();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN)
            //如果是新的按下事件,则对mBottomFlag重新初始化
            mBottomFlag = false;
        //如果已经不要这次事件,则传出取消的信号,这里的作用不大
        if (mBottomFlag)
            event.setAction(MotionEvent.ACTION_CANCEL);

        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean result = super.onTouchEvent(event);
        if (mCanVerticalScroll) {
            //如果是需要拦截,则再拦截,这个方法会在onScrollChanged方法之后再调用一次
            if (!mBottomFlag)
                getParent().requestDisallowInterceptTouchEvent(true);
        } else {
            getParent().requestDisallowInterceptTouchEvent(false);
        }
        return result;
    }

    @Override
    protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
        super.onScrollChanged(horiz, vert, oldHoriz, oldVert);
        if (vert == mOffsetHeight || vert == 0) {
            //这里触发父布局或祖父布局的滑动事件
            getParent().requestDisallowInterceptTouchEvent(false);
            mBottomFlag = true;
        }
    }

    /**
     * EditText竖直方向是否可以滚动
     *
     * @return true:可以滚动   false:不可以滚动
     */
    private boolean canVerticalScroll() {
        //滚动的距离
        int scrollY = getScrollY();
        //控件内容的总高度
        int scrollRange = getLayout().getHeight();
        //控件实际显示的高度
        int scrollExtent = getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();
        //控件内容总高度与实际显示高度的差值
        mOffsetHeight = scrollRange - scrollExtent;

        if (mOffsetHeight == 0) {

            return false;
        }

        return (scrollY > 0) || (scrollY < mOffsetHeight - 1);
    }
}

参考了以下两位作者的文章
http://blog.csdn.net/z191726501/article/details/50701165
http://blog.csdn.net/sahadev_/article/details/51207068

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,455评论 25 708
  • 在此特此声明:一下所有链接均来自互联网,在此记录下我的查阅学习历程,感谢各位原创作者的无私奉献 ! 技术一点一点积...
    远航的移动开发历程阅读 11,230评论 12 197
  • 我知道我特么为什么这么多年都放不下了,你在我本想要重新开始的时候,告诉我你已经有新的开始了,所以,我将永远恨你,带...
    寻觅我的萧言缄阅读 202评论 0 0
  • 我有一个好朋友,是个男生,跨国恋,他昨天发了一条状态:“我他妈就没有办法和你们形容,我有多恨别人为我牺牲这件事。”...
    浮生aureate阅读 643评论 0 2
  • 隔着时间我们拥抱,你以为我拥抱的是回忆,我以为你拥抱的是未来,他们看到的是我和你在拥抱。每座山升起的炊烟,都是因为...
    Dharma59阅读 601评论 0 0