当我们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
所以如果返回了true,所以你的item中的view有一个为focusable那么setOnItemClickListener就不会生效if (child.hasFocusable()) { return true; }