zoukankan      html  css  js  c++  java
  • 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);

  • 相关阅读:
    轻轻松松教你写日志-超级简单
    JAVA实现KNN分类
    怎样给filter加入自己定义接口
    设计模式之Visitor模式(笔记)
    Leet Code OJ 237. Delete Node in a Linked List [Difficulty: Easy]
    在C#中怎样推断线程当前所处的状态
    leetCode 83.Remove Duplicates from Sorted List(删除排序链表的反复) 解题思路和方法
    谈谈源码管理那点事儿(一)——源码管理十诫(转)
    安装gi的时候回退root.sh的运行
    Android开发学习之路--异步消息Handler,Message,Looper和AsyncTask之初体验
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12360983.html
Copyright © 2011-2022 走看看