ScrollView嵌套EditText联带滑动的解决办法

简介: 本篇文章的相关内容需结合上文:从ScrollView嵌套EditText的滑动事件冲突分析触摸事件的分发机制以及TextView的简要实现和冲突的解决办法 在说完了如何解决ScrollView嵌套EditText的滑动事件冲突之后,我们接下来说一下如何实现它们两者之间的联带滑动。

本篇文章的相关内容需结合上文:从ScrollView嵌套EditText的滑动事件冲突分析触摸事件的分发机制以及TextView的简要实现和冲突的解决办法


在说完了如何解决ScrollView嵌套EditText的滑动事件冲突之后,我们接下来说一下如何实现它们两者之间的联带滑动。什么是联带滑动呢,就是当EditText滑动到底部的时候,这时就应该让外部的ScrollView跟着滑动,好让它们之间完成连贯的滑动事件,就是我们这篇文章的目的。具体效果就像下面这样:


上图是一个GIF图片,所以有些卡顿的效果,实际上效果是非常流畅的。那么实现这种效果该怎么做呢?


我们知道,子View可以根据requestDisallowInterceptTouchEvent方法来请求是否允许其祖父布局拦截本次的触摸事件,那么,我们就有了初步的解决办法,就是,在需要的时候,不要让祖父布局拦截事件,在不需要的时候,让它们拦截,这时,事件就会被交给祖父布局来处理,并会让ScrollView滑动起来。


上篇文章,我们已经对这一步做了基本的处理,如果你已经按照上文实现了的话,发现并没有按照想象中的那样实现本效果。那么是哪里出现了问题,是哪里还有问题吗?


细心的同学可以发现,我们在onScrollChanged方法中对到达顶部和底部时做了处理,允许祖父布局对事件进行拦截。但是,如果做了调试的话,onScrollChanged方法调用之后onTouchEvent方法也调用了一次requestDisallowInterceptTouchEvent,并设置的参数还是true,也就是说,刚才在onScrollChanged方法中做的处理被取消了。所以,这时我们需要加个标志,用于帮助onTouchEvent方法中的requestDisallowInterceptTouchEvent方法进行合理的调用。


So,我们的问题就解决了。


不过还需要一些后续工作,就是在dispatchTouchEvent判断时候有新一轮的事件被传递过来,这时,我们还需要将这个标志重新初始化一下。


全部的实现代码如下:

<span style="font-family:'Microsoft YaHei';font-size:14px;">package com.example.sahadev.gridlayout;

import android.content.Context;
import android.text.Layout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.EditText;

/**
 * Created by Sahadev on 2016/4/20.
 */
public class MyEditText extends EditText {

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

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

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

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

    public MyEditText(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);

        int paddingTop;
        int paddingBottom;
        int mHeight;
        int mLayoutHeight;

        //获得内容面板
        Layout mLayout = getLayout();
        //获得内容面板的高度
        mLayoutHeight = mLayout.getHeight();
        //获取上内边距
        paddingTop = getTotalPaddingTop();
        //获取下内边距
        paddingBottom = getTotalPaddingBottom();

        //获得控件的实际高度
        mHeight = getHeight();

        //计算滑动距离的边界
        mOffsetHeight = mLayoutHeight + paddingTop + paddingBottom - mHeight;
    }

    @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);
        //如果是需要拦截,则再拦截,这个方法会在onScrollChanged方法之后再调用一次
        if (!mBottomFlag)
            getParent().requestDisallowInterceptTouchEvent(true);
        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;
        }
    }


}
</span>

代码,相比上篇文章进行了稍微的改良。看起来更加明确。


所以,上面就是我们常常看到的对不同View之间进行连贯性滑动的解决办法。



PS:对于这种事件类的调试,如果身边没有源码可以调试的话,那么打印日志是一个好的解决办法。


经过这两篇文章,相信你一定会触摸事件之间的关系有了更进一步的了解。

目录
相关文章
|
存储 缓存 前端开发
关于Android SurfaceView截屏总结
关于Android SurfaceView截屏总结
2092 0
|
存储 缓存 图形学
ABC动画插件Alembic从浅入深(Unity3D)
今天分享一下Alembic插件的使用教程,这个插件的主要作用就是将.abc文件导入到Unity,然后进行播放。 .abc文件主要是影像业界使用的数据格式,用于存储巨大的顶点缓存数据。 Alembic插件就是转化这些影像资料和动力学等的模拟结果转换为顶点缓数 据为Unity可以使用的文件
|
Java API 开发工具
一个专为Android平台设计的高度可定制的日历库
Calendar库是Android开发的工具,支持RecyclerView和Compose,提供高度定制的日历组件。功能包括:单选/多选/范围日期选择、周/月模式、禁用特定日期、设置边界、自定义视图、每周起始日、滚动方式、热力图、标题和脚注、滑动导航及兼容低版本API。示例应用和源码可在GitHub找到,通过Gradle集成,有详细文档指导。
355 16
|
编解码 Android开发
Android 解决TextView多行滑动与NestedScrollView嵌套滑动冲突的问题
Android 解决TextView多行滑动与NestedScrollView嵌套滑动冲突的问题
415 0
|
Java 关系型数据库 微服务
Seata常见问题之项目一直启动不成功如何解决
Seata 是一个开源的分布式事务解决方案,旨在提供高效且简单的事务协调机制,以解决微服务架构下跨服务调用(分布式场景)的一致性问题。以下是Seata常见问题的一个合集
1200 0
|
jenkins 持续交付
【Jenkins】使用brew安装jenkins并配置局域网IP访问
解决Jenkins≈只能用localhost\127.0.0.1访问,但无法通过IP地址访问的问题
9105 0
|
Android开发
Android RecyclerView实现吸顶动态效果,详细分析
Android RecyclerView实现吸顶动态效果,详细分析
|
Android开发
关于安卓使用glide加载得出drawable,bitmap
关于安卓使用glide加载得出drawable,bitmap
697 0
|
开发者 异构计算
RecyclerView滑动时卡顿怎么办?
RecyclerView滑动时卡顿怎么办?
726 0
RecyclerView滑动时卡顿怎么办?
|
Web App开发 JSON 前端开发
2022年谷歌Chrome等浏览器在线打开编辑保存微软Office/金山WPS的Word、Excel和PPT方案大全
长久以来,在IE、Chrome 45及Firefox 53以下版本的浏览器网页中,可直接或间接调用微软免费开源的ActiveX控件DsoFramer或参考DsoFramer实现的一些收费NPAPI办公插件即可嵌入本地安装的Office桌面软件实现在线编辑或审阅Office文档。随着Windows系统及Office软件的不断升级,DsoFramer的稳定性和兼容性问题越来越多,
714 0
2022年谷歌Chrome等浏览器在线打开编辑保存微软Office/金山WPS的Word、Excel和PPT方案大全