为什么ListView条目中有Button时setOnItemClickListener不生效

     当我们setOnItemClickListener时

     实际上调用的是AdapterView中

/**
 * Register a callback to be invoked when an item in this AdapterView has
 * been clicked.
 *
 * @param listener The callback that will be invoked.
 */
public void setOnItemClickListener(@Nullable OnItemClickListener listener) {
    mOnItemClickListener = listener;
}
那什么时候会回调这个onItemClick方法呢

我们会发现只有一处在调用这个回调

public boolean performItemClick(View view, int position, long id) {
    final boolean result;
    if (mOnItemClickListener != null) {
        playSoundEffect(SoundEffectConstants.CLICK);
        mOnItemClickListener.onItemClick(this, view, position, id);
        result = true;
    } else {
        result = false;
    }

    if (view != null) {
        view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    }
    return result;
}
那又是谁在执行
performItemClick
我们发现有三处调用了performItemClick

除去

ListItemAccessibilityDelegate(这是安卓辅助功能那一块的东西,我们平时并没有用到)
内部类中的调用 我们还剩两处

分别是1 

private class PerformClick extends WindowRunnnable implements Runnable {
    int mClickMotionPosition;

    @Override
    public void run() {
        // The data has changed since we posted this action in the event queue,
        // bail out before bad things happen
        if (mDataChanged) return;

        final ListAdapter adapter = mAdapter;
        final int motionPosition = mClickMotionPosition;
        if (adapter != null && mItemCount > 0 &&
                motionPosition != INVALID_POSITION &&
                motionPosition < adapter.getCount() && sameWindow()) {
            final View view = getChildAt(motionPosition - mFirstPosition);
            // If there is no view, something bad happened (the view scrolled off the
            // screen, etc.) and we should cancel the click
            if (view != null) {
                performItemClick(view, motionPosition, adapter.getItemId(motionPosition));
            }
        }
    }
}

2

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (KeyEvent.isConfirmKey(keyCode)) {
        if (!isEnabled()) {
            return true;
        }
        if (isClickable() && isPressed() &&
                mSelectedPosition >= 0 && mAdapter != null &&
                mSelectedPosition < mAdapter.getCount()) {

            final View view = getChildAt(mSelectedPosition - mFirstPosition);
            if (view != null) {
                performItemClick(view, mSelectedPosition, mSelectedRowId);
                view.setPressed(false);
            }
            setPressed(false);
            return true;
        }
    }
    return super.onKeyUp(keyCode, event);
}
而第二处是涉及到一些按键事件(并不是触摸事件)的调用,与我们平时使用没有关系,因为我们分析第一处调用

我们发现在

private void onTouchUp(MotionEvent ev) {。。。。}中用到了第一处
代码摘取如下
final int motionPosition = mMotionPosition;
final View child = getChildAt(motionPosition - mFirstPosition);
if (child != null) {
    if (mTouchMode != TOUCH_MODE_DOWN) {
        child.setPressed(false);
    }

    final float x = ev.getX();
    final boolean inList = x > mListPadding.left && x < getWidth() - mListPadding.right;

if (inList && !child.hasFocusable()) {
    if (mPerformClick == null) {
        mPerformClick = new PerformClick();
    }

    final AbsListView.PerformClick performClick = mPerformClick;
    performClick.mClickMotionPosition = motionPosition;
    performClick.rememberWindowAttachCount();

    mResurrectToPosition = motionPosition;。。。。
请注意前面的判断条件
!child.hasFocusable()也就是child没有焦点时才会走到里面
而这个child就是我们的一个item,我们一般使用ViewGroup(LinearLayout,ReltiveLayout都是他的子类)
那也就是说ViewGroup.hasFocusable()返回false我们的setOnitemClickListener才会生效
@Override
public boolean hasFocusable() {
    if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
        return false;
    }

    if (isFocusable()) {
        return true;
    }

    final int descendantFocusability = getDescendantFocusability();
    if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
        final int count = mChildrenCount;
        final View[] children = mChildren;

        for (int i = 0; i < count; i++) {
            final View child = children[i];
            if (child.hasFocusable()) {
                return true;
            }
        }
    }

    return false;
}
原谅我hasFocusable()这个判断是用log打印出来发现为true。。。而isFocusable()打印出来为false
所以如果
 if (child.hasFocusable()) {
                return true;
            }
返回了true,所以你的item中的view有一个为focusable那么setOnItemClickListener就不会生效



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值