• ConxtMenu高级用法


    ##背景
    我们经常在列表的页面中,点击列表中的行,一般进入详情页面,长按列表中一行,会弹出一个菜单,包含了对某一行的操作(编辑、删除等等),也知道通常的用法:

    • 0x01. 在Activity中注册需要上下文菜单的View:
      registerForContextMenu(mListView);
    • 0x02. 然后在Activity中继承onCreateContextMenu方法,添加菜单项:

      1
      2
      3
      4
      5
      6
      7
      8
      @Override
      public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
      Log.d(LOG_TAG, "onCreateContextMenu");
      super.onCreateContextMenu(menu, v, menuInfo);
      menu.setHeaderTitle(R.string.prompt);
      menu.add(Menu.NONE, R.id.context_menu_item_delete_record, Menu.NONE, R.string.delete_record);//groupId, itemId, order, title
      menu.add(Menu.NONE, R.id.context_menu_item_delete_record_with_file, Menu.NONE, R.string.delete_record_with_file);
      }

      PS:每次长按出现上下文菜单都会调用这个方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      /** * Called when a context menu for the {@code view} is about to
      be shown. * Unlike {@link #onCreateOptionsMenu(Menu)}, this will
      be called every * time the context menu is about to be shown and
      should be populated for * the view (or item inside the view for {@link
      AdapterView} subclasses, * this can be found in the {@code
      menuInfo})). * <p> * Use {@link #onContextItemSelected(android.view.MenuItem)} to know when an
      * item has been selected. * <p> * It is not safe to hold onto the
      context menu after this method returns. * */
      public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
      }
    • 0x03. 接下来长按列表中一行的时候,会弹出上下文菜单:
      device-2015-11-04-141103.png

    • 0x04. 点击菜单后,在Activity中继承onContextItemSelected方法进行处理:

      1
      2
      3
      4
      5
      @Override
      public boolean onContextItemSelected(MenuItem item) {
      switch (item.getItemId()){
      }
      }
    • 0x05. 获取Item标识(id)
      我们删除数据库或者一行记录的时候,要知道主键(一般是id)才能进行操作,很多人就想办法,有的是把ListView的每个ItemView添加一个LongClickListener,然后长按的时候记录下Position,然后在进行相应处理。

      其实有更优雅的做法,onContextItemSelected(MenuItem item)回调的参数item可以获取item.getMenuInfo(),在ListView和Adapter的模式中,可以强制转换成AdapterContextMenuInfo,拿到targetView(即所长按行的ItemVew,如果我们需要什么参数,直接放到View.setTag中去即可):

      1
      2
      3
      AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
      int index = info.position;
      View view = info.targetView;

    至此,常见的用法就完了,那么遇到其他自定义View呢?

    • 0x06. 自定义View的ContextMenu实现
      下面以用到的RecycleView为例,没有了ListView及其Adapter的封装,我们需要自己处理ContextMenu。
      最重要的是继承View的两个方法:
      1.上下文菜单Item的附加信息(上面item.getMenuInfo());
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      /** * Views should implement this if they have extra information to
      associate * with the context menu. The return result is supplied as a
      parameter to * the {@link
      OnCreateContextMenuListener#onCreateContextMenu(ContextMenu,
      View, ContextMenuInfo)} * callback. * * @return Extra information
      about the item for which the context menu * should be shown.
      This information will vary across different * subclasses of View. */
      protected ContextMenuInfo getContextMenuInfo() {
      return null;
      }

    2.ViewGroup的showContextMenuForChild,每次弹出上下文菜单都会调用此方法,需要在这里更新ContextMenuInfo;

    1
    2
    3
    4
    /** * {@inheritDoc} */
    public boolean showContextMenuForChild(View originalView) {
    return mParent != null && mParent.showContextMenuForChild(originalView);
    }

    • 0x07. 自定义RecycleView的ContextMenu全部代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    大专栏  ConxtMenu高级用法v class="line">163
    164
    165
    166
    167
    168
    169
    package com.lbrant.phone.view;
    import android.content.Context;
    import android.support.v7.widget.RecyclerView;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.ContextMenu;
    import android.view.View;
    /**
    * 作者:dell
    * 时间:2015/11/3 18:34
    * 文件:PhoneRecorder
    * 描述:
    */
    public class ContextMenuRecyclerView extends RecyclerView {
    private static final String LOG_TAG = "ContextMenuRecyclerView";
    private RecyclerContextMenuInfo mContextMenuInfo = new RecyclerContextMenuInfo();
    public ContextMenuRecyclerView(Context context) {
    super(context);
    }
    public ContextMenuRecyclerView(Context context, AttributeSet attrs) {
    super(context, attrs);
    }
    public ContextMenuRecyclerView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    }
    @Override
    protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
    return mContextMenuInfo;
    }
    @Override
    public boolean showContextMenuForChild(View originalView) {
    Log.d(LOG_TAG, "showContextMenuForChild");
    Object tag = originalView.getTag();
    if (tag instanceof RecyclerItemMarker) {
    mContextMenuInfo.mRecycleItemMarker = (RecyclerItemMarker) tag;
    }
    return super.showContextMenuForChild(originalView);
    }
    public static class RecyclerItemMarker {
    public final int position;
    public final Object obj;
    public RecyclerItemMarker(int position, Object obj) {
    this.position = position;
    this.obj = obj;
    }
    }
    public static class RecyclerContextMenuInfo implements ContextMenu.ContextMenuInfo {
    public RecyclerItemMarker mRecycleItemMarker;
    }
    }
    private class RecordRecycleViewAdapter extends RecyclerView.Adapter<RecordRecycleViewAdapter.RecordViewHolder> {
    private Cursor mCallRecordCursor;
    private int mIdIndex;
    private int mPhoneNumberIndex;
    private int mCallTimeIndex;
    private int mDurationIndex;
    private int mPathIndex;
    public RecordRecycleViewAdapter(Cursor cursor) {
    mCallRecordCursor = cursor;
    updateCursorColumnIndex();
    }
    private void updateCursorColumnIndex() {
    if (mCallRecordCursor != null) {
    mIdIndex = mCallRecordCursor.getColumnIndex(BaseDatabaseHelper.RECORDS_COLUMNS._ID);
    mPhoneNumberIndex = mCallRecordCursor.getColumnIndex(BaseDatabaseHelper.RECORDS_COLUMNS.NUMBER);
    mCallTimeIndex = mCallRecordCursor.getColumnIndex(BaseDatabaseHelper.RECORDS_COLUMNS.CALL_TIME);
    mDurationIndex = mCallRecordCursor.getColumnIndex(BaseDatabaseHelper.RECORDS_COLUMNS.DURATION);
    mPathIndex = mCallRecordCursor.getColumnIndex(BaseDatabaseHelper.RECORDS_COLUMNS.PATH);
    }
    }
    @Override
    public RecordRecycleViewAdapter.RecordViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View contentView = LayoutInflater.from(parent.getContext()).inflate(R.layout.record_list_item, parent, false);
    RecordViewHolder viewHolder = new RecordViewHolder(contentView);
    return viewHolder;
    }
    @Override
    public void onBindViewHolder(RecordRecycleViewAdapter.RecordViewHolder holder, final int position) {
    holder.itemView.setLongClickable(true);
    if (mCallRecordCursor != null && mCallRecordCursor.moveToPosition(position)) {
    long id = mCallRecordCursor.getLong(mIdIndex);
    String phoneNumber = mCallRecordCursor.getString(mPhoneNumberIndex);
    long seconds = mCallRecordCursor.getLong(mDurationIndex);
    String callTime = mCallRecordCursor.getString(mCallTimeIndex);
    String path = mCallRecordCursor.getString(mPathIndex);
    String duration = String.format("%1$02d:%2$02d:%3$02d", seconds / 3600, seconds % 3600 / 60, seconds % 60);
    RecordInfo info = new RecordInfo();
    info.setId(id);
    info.setPhoneNumber(phoneNumber);
    info.setSecondsDuration(seconds);
    info.setCallTime(callTime);
    info.setPath(path);
    holder.itemView.setTag(new ContextMenuRecyclerView.RecyclerItemMarker(position, info));
    holder.mTextViewPhoneNumber.setText(phoneNumber);
    holder.mTextViewDuration.setText(duration);
    holder.mTextviewCallTime.setText(callTime);
    Cursor cursor = queryContactByPhoneNumber(ContactsContract.CommonDataKinds.Phone.NUMBER + " = '" + phoneNumber + "'");
    if (cursor != null) {
    if (cursor.moveToNext()) {
    long contactId = cursor.getInt(0);
    Cursor contactCursor = queryContact(ContactsContract.Contacts._ID + "=" + contactId);
    if (contactCursor != null) {
    holder.mTextViewName.setText(contactCursor.getString(1));
    contactCursor.close();
    }
    }
    cursor.close();
    }
    }
    }
    @Override
    public void onViewRecycled(RecordViewHolder holder) {
    super.onViewRecycled(holder);
    holder.itemView.setOnCreateContextMenuListener(null);
    }
    @Override
    public int getItemCount() {
    return mCallRecordCursor == null ? 0 : mCallRecordCursor.getCount();
    }
    public void changeCursor(Cursor cursor) {
    if (cursor != mCallRecordCursor) {
    if (mCallRecordCursor != null) {
    mCallRecordCursor.close();
    }
    mCallRecordCursor = cursor;
    updateCursorColumnIndex();
    notifyDataSetChanged();
    }
    }
    public class RecordViewHolder extends RecyclerView.ViewHolder {
    private ImageView mImageViewAvatar;
    private TextView mTextViewPhoneNumber;
    private TextView mTextViewName;
    private TextView mTextviewCallTime;
    private TextView mTextViewDuration;
    public RecordViewHolder(View itemView) {
    super(itemView);
    mImageViewAvatar = (ImageView) itemView.findViewById(R.id.imageViewAvatar);
    mTextViewName = (TextView) itemView.findViewById(R.id.textViewName);
    mTextViewPhoneNumber = (TextView) itemView.findViewById(R.id.textViewPhoneNumber);
    mTextviewCallTime = (TextView) itemView.findViewById(R.id.textViewCallTime);
    mTextViewDuration = (TextView) itemView.findViewById(R.id.textViewDuration);
    }
    }
    }

    有两个地方需要注意:
    1.onBindViewHolder中给ItemView添加Tag;
    2.设置ItemView的LongClickable为true,不然不会出现上下文菜单(具体原因见ContextMenu原理分析);
    holder.itemView.setLongClickable(true);

  • 相关阅读:
    mybatis的注意事项一
    java代码操作word模板生成PDF文件
    使用mybatis框架实现带条件查询多条件(传入实体类)
    MyBatis框架ResultMap节点
    优化mybatis框架中的查询用户记录数的案例
    Mybatis框架联表查询显示问题解决
    使用mybatis框架实现带条件查询单条件
    [DB] 如何彻底卸载删除MySQL 【MYSQL】
    [DB] MySQL窗口输入密码后消失问题 【MYSQL】
    [acm] 曾经 刷题记录 [只有正确的坚持才是胜利]
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12360983.html
Copyright © 2020-2023  润新知