摘要
- 关于Android子view超出父view点击事件失效问题
- 例如button超出父布局之外的点击事件无效
首先看一下结构图
我根布局用的LinearLayout;
然后嵌套了一个一定高度的LinearLayout;为上图顶部宽度撑满父元素的矩形框;称之为“线布2”;
线布2 里又水平布局了两个线性布局;
左边的线性布局不管; 右边的线性布局里嵌套了4个button按钮;
现在的问题是:
- 超出 线布2 的3个button按钮无法显示;
- 超出 线布2 的3个button按钮无法响应点击事件;
对于问题一:
我们想要显示溢出的3个button按钮,在 线布2 里的右布局中;
所以我们让这个右布局能溢出显示就好了;
相关代码
android:clipChildren="false"
android:clipToPadding="false"
官方对于第一行的解释:
Defines whether a child is limited to draw inside of its bounds or not.
翻译:定义一个子视图是否局限于它的范围内。
所以我们设置为false,让子视图不局限与自己;官方对于第二行的解释:
Defines whether the ViewGroup will clip its drawing surface so as to exclude the padding area.
翻译:定义ViewGroup是否将剪辑其绘图表面以排除填充区域。
由于笔者是Android新手,对此表示不太理解,也没有去研究它
(刚入手Android开发一周,只为做一个作品参加学校比赛,不过这作品也是我用心良苦的设计,欢迎大家点击下方链接体验^ _ ^);
- 对此我们解决了第一个问题,不过笔者实验了一番,发现把上述两行代码加在 线布2 的xml里,并没有显示 线布2 里溢出的右布局,也就是说那几个button按钮还是看不见;
- 我搜索问题时,说是上述两行代码是作用于 孙子视图 与 儿子视图;在此不解释孙子与儿子视图;
- 而我的 线布2 的父布局正是根布局,也就是说我需要在根布局中使用这两个参数,才可以使 线布2 里的右布局溢出于 线布2 显示;
实验成功;
笔者项目中,该问题用了一下午才解决,其实主要是首次开发,布局文件过于混乱,所以致使上述参数不生效,(但是我在所有布局标签加上也不生效,这点很纳闷)无奈之下,我把主要的布局文件分离开来,再使用include引入;
模块化确实方便,嘻嘻;
对于问题二:
- 让溢出的button按钮可点击
- 这个问题花费了我半天时间,一直搜找解决方案,遗憾的是,相关问题少,解决方案无用;
- 所以我尝试自己解决此问题,可谓是另辟蹊跷;
先介绍我搜索的解决方案,在此归纳成两条:
1. 使用android:focusable="true"参数
android:focusable="true"
其解释为:是否可聚焦,也是是否可点击
——
我把此参数在所有控件及布局中放了个遍,也无法触发溢出的按钮
——
我也搜找到相关的参数,同样无法点击。
——
我以为是下边的布局覆盖掉了溢出的按钮
——
然后我使用相对布局作为根布局,让有button的布局最后绘制,但结果是lose
——
我摸了摸秃头,发现事态不对劲,遂重建test布局,测试了一番;
——
发现没有其他布局的时候,也点击不了;
——
事情发展到这一步,我想我已经看破红尘…哦不是看破Layout了、手动滑稽
——
杰伦–结论:
所有溢出父布局的控件,无法响应事件,但通过参数可以显示;
其实这个结论是我自己臆想的,但是我实在是找不到方法;
- 这个世界的真理和公理,都是观物者们眼中的事物;//突然哲学
2. 拒绝使用布局进行嵌套
- 这个方案就是取消 线布2 布局,这样就没有布局去限制 线布2 中的button了;
- 但是,热爱模块化的我怎么会让button组脱离组织呢;(其实我差点就屈服于这个方案了)
这种方案就不做详细解释;让我们直接进入下一环:另辟蹊跷
另辟蹊跷:
- 我想着如果能在整个Activity窗口捕捉点击事件,就好办了;
public boolean onTouchEvent(MotionEvent event);
果然,程序员的直觉
——
只需要在Activity代码区重写此方法就好了;
不过他只返回布尔值,其值含义为是否触摸了屏幕;
聪明的我怎能让他只干这件事;
遂:
@Override
public boolean onTouchEvent(MotionEvent event) {
//首先定义一个数组用来接收按钮的坐标xy值
int[] xy = new int[2];
//获取按钮的top/left xy值
//button变量我在onCreat()函数中已经获取了控件,具体按实际情况写
button.getLocationOnScreen(xy);
//再定义一个数组用来计算控件的bottom/right xy值
int[] xy_end = new int[2];
xy_end[0] = buttom.getWidth() + xy[0];
xy_end[1] = buttom.getHeight() + xy[1];
//现在我们已经得到了按钮的左上坐标和右下坐标
//两个点可以确定一个矩形嘛
//event里包含了点击的信息;
//我们判断点击的坐标是否在按钮坐标内,实际就是判断点击的xy值是否在上述矩形中;
if (event.getX() >= xy[0] && event.getX() <= xy_end[0]
&& event.getY() >= xy[1] && event.getY() <= xy_end[1]) {
//如果是,那么就执行里边的代码,在这里我们可以callOnClick()按钮
//这里的代码说明
//实际体验了一番,发现轻点一下和长按均可以激活按钮;
//但是,我的按钮拥有animate()事件,所以连续点击会在动画未完成时再次点击按钮,
//所以我做了个判断,让动画未完成时不再执行点击,机制如我
//实际中,读者完全不用这两行代码
//让我看看有哪些读者看都不看直接复制代码--手动滑稽
//虽说站在巨人肩膀上,但是也要搞懂其原理才不会摔下来。
if (isMoreShow == false && xy[0] >= button.getHeight())
return false;
//我们callOnClick了按钮,也就是模拟点击了按钮;
button.callOnClick();
return false;
}
return super.onTouchEvent(event);
}
- 就这短短几行代码,搞了我半天的心态,严格说还有一个晚上;
不足:
- 不足之处还是有的
- 如果按钮过多,就需要写入更多的判断,这非常的不优雅;可是总比无法点击要好;
- 如果按钮有自定义点击背景(按下背景),将不显示,身为强迫症的我怎么能忍;