View focusableInTouchMode=true导致第一次点击不响应

具体情况是这样的: 有一个ViewGroup A, 包含一个View B, 然后 A, B的focusableInTouchMode都是true, 第一次点击B, onClickListener不会触发, 而后续点击都可以.

查看源代码后发现这是因为 View 在 onTouchEvent() 中的 MotionEvent.ACTION_UP 中对focus做了处理: 如果View focusableInTouchMode 是true, 并且当前没有获得焦点, 那么会尝试获取焦点, 并且不会调用 performClick().

相关代码如下:

public boolean onTouchEvent(MotionEvent event) {

	...
	
	if (((viewFlags & CLICKABLE) == CLICKABLE ||
	        (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
	        (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
	    switch (action) {
	        case MotionEvent.ACTION_UP:
	            boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
	            if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
	                boolean focusTaken = false;
	                if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
	                    focusTaken = requestFocus();
	                }
	
	                if (prepressed) {
	                    setPressed(true, x, y);
	               }
	
	                if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
	                    removeLongPressCallback();
	
	                    if (!focusTaken) {
	                        if (mPerformClick == null) {
	                            mPerformClick = new PerformClick();
	                        }
	                        if (!post(mPerformClick)) {
	                            performClick();
	                        }
	                    }
	                }
	
	...
}

因此上面的现象可以如下解释:

  1. 第一次点击时, A 获得焦点, 而 B 没有焦点, 因此第一次点击之后, B 获取了焦点, 但没有调用 performClick().
  2. 后续点击时, B 已经拥有了焦点, 调用了 performClick(), 所以 OnClickListener能够被触发.

这个问题有下面几种解决方法:

  1. 将 B 的 focusableInTouchMode 设置为 false
  2. 在点击 B 之前, 让其获得焦点
    • 手动调用它的 requestFocus() 方法
    • 让 B 成为视图层级中第一个focusable的View (例如将 A 的focusable设置为false)

转载于:https://my.oschina.net/fengheju/blog/693119

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值