OnCreateContextMenuListener,MultiChoiceModeListener和OnLongClickListener的优先级

来源:互联网 发布:中世纪2优化9 圣殿骑士 编辑:程序博客网 时间:2024/06/05 04:39

查看短信源码的时候,对于以下代码,发现一个问题:

listView.setOnCreateContextMenuListener(mConvListOnCreateContextMenuListener);        listView.setOnKeyListener(mThreadListKeyListener);        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);        listView.setMultiChoiceModeListener(new ModeCallback()); private class ModeCallback implements ListView.MultiChoiceModeListener {        private View mMultiSelectActionBarView;        private TextView mSelectedConvCount;        private HashSet<Long> mSelectedThreadIds;        @Override        public boolean onCreateActionMode(ActionMode mode, Menu menu) {             }        @Override        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {        }        @Override        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {        }        @Override        public void onDestroyActionMode(ActionMode mode) {        }        @Override        public void onItemCheckedStateChanged(ActionMode mode,                int position, long id, boolean checked) {                }    }    private final OnCreateContextMenuListener mConvListOnCreateContextMenuListener =        new OnCreateContextMenuListener() {        @Override        public void onCreateContextMenu(ContextMenu menu, View v,                ContextMenuInfo menuInfo) {                  }    };    @Override    public boolean onContextItemSelected(MenuItem item) {    }

OnCreateContextMenuListener,MultiChoiceModeListener和OnLongClickListener(这里没有出现)都是长按view然后回调,那么有什么区别呢?查看源码(View.java
):

public boolean performLongClick() {        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);        boolean handled = false;        ListenerInfo li = mListenerInfo;        if (li != null && li.mOnLongClickListener != null) {            handled = li.mOnLongClickListener.onLongClick(View.this);        }        if (!handled) {            handled = showContextMenu();        }        if (handled) {            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);        }        return handled;    }

可以发现,对于普通的View,优先响应OnLongClickListener,如果没有处理然后才是交给ContextMenuListener处理。而MultiChoiceModeListener是
AbsListView定义的,所以可以从AbsListView中寻找答案。

“`
public void setMultiChoiceModeListener(MultiChoiceModeListener listener) {
if (mMultiChoiceModeCallback == null) {
mMultiChoiceModeCallback = new MultiChoiceModeWrapper();
}
mMultiChoiceModeCallback.setWrapped(listener);
}

boolean performLongPress(final View child,        final int longPressPosition, final long longPressId) {    // CHOICE_MODE_MULTIPLE_MODAL takes over long press.    if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {        if (mChoiceActionMode == null &&                (mChoiceActionMode = startActionMode(mMultiChoiceModeCallback)) != null) {            setItemChecked(longPressPosition, true);            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);        }        return true;    }    boolean handled = false;    if (mOnItemLongClickListener != null) {        handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child,                longPressPosition, longPressId);    }    if (!handled) {        mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);        handled = super.showContextMenuForChild(AbsListView.this);    }    if (handled) {        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);    }    return handled;}@Overridepublic boolean showContextMenuForChild(View originalView) {    final int longPressPosition = getPositionForView(originalView);    if (longPressPosition >= 0) {    // 注意!见后文        final long longPressId = mAdapter.getItemId(longPressPosition);        boolean handled = false;        if (mOnItemLongClickListener != null) {            handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, originalView,                    longPressPosition, longPressId);        }        if (!handled) {            mContextMenuInfo = createContextMenuInfo(                    getChildAt(longPressPosition - mFirstPosition),                    longPressPosition, longPressId);            handled = super.showContextMenuForChild(originalView);        }        return handled;    }    return false;}
AbsListView重写了onTouchEvent。可以发现,处理长按事件的优先级为:MultiChoiceModeCallback > ItemLongClickListener > ContextMenuListener注意,如果ListView的Adapter是CursorAdapter的话,那么上面showContextMenuForChild调用了adapter的getItemId,这样cursor已经移动了!!
public long getItemId(int position) {    if (mDataValid && mCursor != null) {        if (mCursor.moveToPosition(position)) {            return mCursor.getLong(mRowIDColumn);        } else {            return 0;        }    } else {        return 0;    }}
##关于ContextMenu大意是AdapterVIew在onContextItemSelected中可以确定是AdapterView调出的ContextMenu,因为

@Override
public boolean onContextItemSelected(MenuItem item) {

AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();  long id = menuInfo.id;//这个id是showContextMenuForChild中item的id


}

AdapterView.java包含:

@Override
protected ContextMenuInfo getContextMenuInfo() {
return mContextMenuInfo;
}

而普通的view没有,所以需要自定view(以ImageView为例子)

public class ImageViewWithContextMenuInfo extends ImageView {
public ImageViewWithContextMenuInfo(Context context) {
super(context);
}

@Override  protected ContextMenuInfo getContextMenuInfo() {      return new ImageViewContextMenuInfo(this);  }  public ImageViewWithContextMenuInfo(Context context, AttributeSet attrs, int defStyle) {      super(context, attrs, defStyle);  }  public ImageViewWithContextMenuInfo(Context context, AttributeSet attrs) {      super(context, attrs);  }  public static class ImageViewContextMenuInfo implements ContextMenu.ContextMenuInfo {      public ImageViewContextMenuInfo(View targetView) {          this.targetView = (ImageView) targetView;      }      public ImageView targetView;  }  

}

用法:

public boolean onContextItemSelected(MenuItem item) {
ImageViewWithContextMenuInfo.ImageViewContextMenuInfo menuInfo = (ImageViewWithContextMenuInfo.ImageViewContextMenuInfo) item.getMenuInfo();
ImageViewWithContextMenuInfo img = (ImageViewWithContextMenuInfo) menuInfo.targetView;
“`

来源:
http://ogrelab.ikratko.com/identifying-the-view-selected-in-a-contextmenu-in-oncontextitemselected-method/

0 0
原创粉丝点击