วิธีสร้างเมนูบริบทสำหรับ RecyclerView


102

ฉันจะใช้เมนูบริบทสำหรับการRecyclerView?โทรแบบเห็นได้ชัดregisterForContextMenu(recyclerView)ไม่ได้อย่างไร ฉันเรียกมันจากเศษเสี้ยว มีใครประสบความสำเร็จบ้างในการนำสิ่งนี้ไปใช้


ฉันอยู่ในเรือลำเดียวกัน พยายามประเมิน ListView ต่างๆด้วย AdapterContextMenuInfo - แต่ไม่สามารถรับข้อมูลตำแหน่ง
RoundSparrow hilltx

ฉันคิดว่าวันของเมนูบริบทสิ้นสุดลงแล้ว
Binoy Babu

4
เฮ้ - ฉันใช้งานได้แล้ว;) การอ้างอิง: stackoverflow.com/questions/2321332/… - ViewHolder สำหรับฉันคือผู้ฟัง onClick - ฉันทำให้มันเป็น OnCreateContextMenuListener ด้วย กุญแจสำคัญของทั้งหมดนี้คือฉันรู้ว่าสามารถเปิดได้ครั้งละหนึ่งเมนูเท่านั้น - ดังนั้นอะแดปเตอร์จึงต้องการเพียง int เพื่อบอกว่ารายการใดเป็นรายการ RecyclerView สุดท้ายที่มีการคลิกเมนู ... จากนั้น Fragment / Activity สามารถ ถามอะแดปเตอร์เมื่อได้รับรายการเมนูจริงคลิก
RoundSparrow hilltx

คำตอบ:


94

คุณไม่สามารถใช้วิธีการเหล่านี้เช่นOnClickListener , OnContextMenuListenerฯลฯ เพราะRecycleViewขยายandroid.view.ViewGroup เราจึงใช้วิธีเหล่านี้โดยตรงไม่ได้ เราสามารถใช้วิธีการเหล่านี้ในคลาสอะแดปเตอร์ViewHolder เราสามารถใช้เมนูบริบทใน RecycleView ได้เช่นนี้:

public static class ViewHolder extends RecyclerView.ViewHolder implements OnCreateContextMenuListener {

    TextView tvTitle;
    ImageView ivImage;

    public ViewHolder(View v) {
        super(v);
        tvTitle =(TextView)v.findViewById(R.id.item_title);
        v.setOnCreateContextMenuListener(this);


    }

ตอนนี้เราทำตามขั้นตอนเดียวกันในขณะที่ใช้เมนูบริบท

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {

    menu.setHeaderTitle("Select The Action");    
    menu.add(0, v.getId(), 0, "Call");//groupId, itemId, order, title   
    menu.add(0, v.getId(), 0, "SMS"); 

}

หากคุณมีปัญหาใด ๆ ถามในความคิดเห็น


7
ตกลงจากนั้นเราใช้ระดับonContextItemSelectedกิจกรรม / ส่วนย่อย getTitleทำงานได้getItemIdผล แต่getMenuInfoให้ค่าว่าง ดังนั้นวิธีการรับของViewHolder?
Michael Schmidt

@MichaelSchmidt คุณสามารถแสดงรหัสของคุณที่คุณใช้ข้อมูลเมนูบริบทได้ไหม
Prabhakar

7
หลังจากทดลองบิตฉันไม่สามารถรับการทำงานอย่างใดอย่างหนึ่งผลตอบแทนที่เป็นโมฆะในgetMenuInfo() onContextItemSelected()บางทีคนที่ทำให้มันใช้งานได้อาจมีonCreateContextMenu()วิธีการในมุมมองที่ไกลขึ้นตามลำดับชั้น ( RecyclerViewหรือFragment) ซึ่งสามารถทำงานได้ แต่จะนำเราไปสู่คำตอบอื่น ๆ ของคำถามนี้
NeilS

3
Prabhakbar คุณไม่ได้พูดถึงวิธีรับรายการที่คลิกหรือมุมมอง?
Benjamin Stürmer

6
คุณสามารถใช้menu.add(this.getAdapterPosition(), v.getId(), 0, "Call");แล้วในการทดสอบวิธีการโทรกลับitem.getGroupId()เพื่อรับตำแหน่ง
JacobPariseau

103

ขอบคุณสำหรับข้อมูลและความคิดเห็น ฉันสามารถบรรลุContextMenuรายการในRecyclerview.

นี่คือสิ่งที่ฉันทำ

ในonViewCreatedวิธีการของ Fragment หรือonCreateวิธีการของกิจกรรม:

registerForContextMenu(mRecyclerView);

จากนั้นในอะแดปเตอร์เพิ่ม

private int position;

public int getPosition() {
    return position;
}

public void setPosition(int position) {
    this.position = position;
}

ทำให้ViewHolderคลาสใช้งานได้OnCreateContextMenuListener

public static class ViewHolder extends RecyclerView.ViewHolder 
        implements View.OnCreateContextMenuListener {

    public ImageView icon;

    public TextView fileName;
    public ImageButton menuButton;


    public ViewHolder(View v) {
        super(v);
        icon = (ImageView)v.findViewById(R.id.file_icon);
        fileName = (TextView)v.findViewById(R.id.file_name);
        menuButton = (ImageButton)v.findViewById(R.id.menu_button);
        v.setOnCreateContextMenuListener(this);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, 
        ContextMenu.ContextMenuInfo menuInfo) {
        //menuInfo is null
        menu.add(Menu.NONE, R.id.ctx_menu_remove_backup, 
            Menu.NONE, R.string.remove_backup);
        menu.add(Menu.NONE, R.id.ctx_menu_restore_backup,
            Menu.NONE, R.string.restore_backup);
    }
}

onBindViewHolderวิธีการเพิ่มOnLongClickListenerบน holder.itemView เพื่อจับตำแหน่งก่อนโหลดเมนูบริบท:

holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        setPosition(holder.getPosition());
        return false;
    }
});

จากนั้นให้onViewRecycledนำ Listener ออกเพื่อไม่ให้มีปัญหาในการอ้างอิง (อาจไม่จำเป็นต้องใช้)

@Override
public void onViewRecycled(ViewHolder holder) {
    holder.itemView.setOnLongClickListener(null);
    super.onViewRecycled(holder);
}

สุดท้ายใน Fragment / Activity จะแทนที่onContextItemSelectedดังต่อไปนี้:

@Override
public boolean onContextItemSelected(MenuItem item) {
    int position = -1;
    try {
        position = ((BackupRestoreListAdapter)getAdapter()).getPosition();
    } catch (Exception e) {
        Log.d(TAG, e.getLocalizedMessage(), e);
        return super.onContextItemSelected(item);
    }
    switch (item.getItemId()) {
        case R.id.ctx_menu_remove_backup:
            // do your stuff
            break;
        case R.id.ctx_menu_restore_backup:
            // do your stuff
            break;
    }
    return super.onContextItemSelected(item);
}

1
ตำแหน่ง = ((BackupRestoreListAdapter) getAdapter ()) getPosition (); -> รับข้อผิดพลาด: วิธี getAdapter () ไม่ได้กำหนดไว้สำหรับประเภท ... คุณสามารถแสดงเมธอด
getAdapter ได้หรือไม่

1
ข้อเสนอแนะที่ดีขอบคุณ ผู้เยาว์: viewHolder.getPosition () เลิกใช้งานแล้ว คำแนะนำสำหรับการปรับปรุงคืออะไร?
tm1701

10
ใช้ viewHolder.getAdapterPosition () แทน getPosition ()
Sagar Chavada

2
สำหรับผู้ที่ได้รับข้อผิดพลาด getAdapter () ฉันแก้ไขได้โดยบันทึกการอ้างอิงไปยัง RecyclerView ของฉันแล้วใช้มันเช่น: ((BackupRestoreListAdapter) รีไซเคิล
Kevin Amorim

2
แล้ว Rid.ctx_menu_remove_backup อยู่ที่ไหนกันแน่?
akubi

31

คำตอบปัจจุบันไม่ถูกต้อง นี่คือการใช้งานที่ใช้งานได้:

public class ContextMenuRecyclerView extends RecyclerView {

  private RecyclerViewContextMenuInfo mContextMenuInfo;

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

  @Override
  public boolean showContextMenuForChild(View originalView) {
    final int longPressPosition = getChildPosition(originalView);
    if (longPressPosition >= 0) {
        final long longPressId = getAdapter().getItemId(longPressPosition);
        mContextMenuInfo = new RecyclerViewContextMenuInfo(longPressPosition, longPressId);
        return super.showContextMenuForChild(originalView);
    }
    return false;
  }

  public static class RecyclerViewContextMenuInfo implements ContextMenu.ContextMenuInfo {

    public RecyclerViewContextMenuInfo(int position, long id) {
        this.position = position;
        this.id = id;
    }

    final public int position;
    final public long id;
  }
}

ในส่วนของคุณ (หรือกิจกรรม):

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mRecyclerView = view.findViewById(R.id.recyclerview);
    registerForContextMenu(mRecyclerView);
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    // inflate menu
    MenuInflater inflater = getActivity().getMenuInflater();
    inflater.inflate(R.menu.my_context_menu, menu);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    return super.onContextItemSelected(item);
    RecyclerViewContextMenuInfo info = (RecyclerViewContextMenuInfo) item.getMenuInfo();
    // handle menu item here
}

และสุดท้ายใน ViewHolder ของคุณ:

class MyViewHolder extends RecyclerView.View.ViewHolder {
    ...
    private void onLongClick() {
        itemView.showContextMenu();
    }
}

โปรดเพิ่มตัวสร้าง RecyclerView ที่คุณต้องใช้กับ ContextMenuRecyclerView ของคุณ และgetChildPosition()ตอนนี้เลิกใช้แล้ว ฉันใช้getChildAdapterPosition()แทน
Juan José Melero Gómez

1
หมายเหตุ:ขอโทษนะฉันลืมที่จะเพิ่ม: เลิกในgetChildPosition() com.android.support:recyclerview-v7:22.0.0
Juan José Melero Gómez

1
สิ่งนี้ไม่ทำงาน คุณไม่สามารถเข้าถึง getView () showContextMenu () จาก RecyclerView.View.ViewHolder
Mulgard

5
สิ่งนี้ใช้ได้กับฉัน แต่ไม่จำเป็นต้องมี onLongClick () ใน MyViewHolder ก็เพียงพอที่จะตั้งค่า itemView.setLongClickable (true) ในตัวสร้างเมนูบริบทจะปรากฏขึ้นเมื่อไม่ได้ลงทะเบียน OnLongClickListener
ศิษย์เก่า

2
สิ่งสำคัญ: ในขณะที่ขยาย RecyclerView ไปยัง ContextMenuRecyclerView อย่าลืมเพิ่ม CONSTRUCTORS ที่ IDE แนะนำ โดยเฉพาะอย่างยิ่งถ้าคุณไม่ใช้ตัวสร้างสองอาร์กิวเมนต์ที่ใช้ Context และ AttributeSet Android จะไม่สามารถขยาย XML เค้าโครงของคุณได้
Lidia Hocke

24

ลองทำViewรายการใน recycleView

.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            menu.add("delete").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {

                    //do what u want
                    return true;
                }
            });
        }
    });

คุณสามารถใช้กับการตั้งค่าข้อมูลเป็นViewHolderรายการ


สิ่งที่ฉันต้องการสำหรับเมนูบริบทในมุมมองภาพภายในมุมมองรีไซเคิล
Themos

2
สำหรับใครที่กำลังมองหาสิ่งนี้ตอนนี้ใช้ได้กับ API 23 ขึ้นไปเท่านั้น
SWoo

16

คำตอบของ Prabhakar ถูกต้อง แต่เขาไม่ได้อธิบายวิธีรับข้อมูลที่เกี่ยวข้องกับรายการที่กดเมื่อเลือกรายการเมนูบริบท เราสามารถใช้การonContextItemSelectedโทรกลับได้ แต่ContextMenuInfoไม่สามารถใช้งานได้ ( null) ในกรณีนี้ (หากgetContextMenuInfo()วิธีการไม่ถูกเขียนทับสำหรับมุมมองที่กด) ดังนั้นทางออกที่ง่ายที่สุดคือเพิ่มลงOnMenuItemClickListenerในไฟล์MenuItem.

private class ViewHolder extends RecyclerView.ViewHolder {
    private final TextView mTitleTextView;
    private MyItemData mData;

    public ViewHolder(View view) {
        super(view);

        mTitleTextView = (TextView)view.findViewById(R.id.title);

        view.setOnCreateContextMenuListener(mOnCreateContextMenuListener);
    }

    public void bind(@NonNull MyItemData data) {
         mData = data;

         String title = mData.getTitle();
         mTitleTextView.setText(title);
    }

    private final View.OnCreateContextMenuListener mOnCreateContextMenuListener = new View.OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            if (mData!= null) {
                MenuItem myActionItem = menu.add("My Context Action");
                myActionItem.setOnMenuItemClickListener(mOnMyActionClickListener);
            }
        }
    };

    private final MenuItem.OnMenuItemClickListener mOnMyActionClickListener = new MenuItem.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            //todo: process item click, mData is available here!!!
            return true;
        }
    };
}

1
อธิบายอย่างชัดเจนว่าข้อมูลโค้ดของคุณทำอะไรและทำอย่างไร เฉพาะรหัสที่คัดลอกมาวางไม่เพียงพอแม้ว่าจะมีมูลค่ามากก็ตาม
peterh - คืนสถานะ Monica

สิ่งนี้ดูเหมือนจะเป็นการประนีประนอมที่สมเหตุสมผลหากคุณไม่ต้องการสร้างคลาสย่อยที่กำหนดเองRecyclerViewเพียงเพื่อแทนที่getContextMenuInfoฯลฯ แม้ว่าจะไม่ค่อยมีประสิทธิภาพเท่ากับการปล่อยให้ส่วนย่อย / กิจกรรมจัดการกับการคลิกก็ตาม ผู้ฟังจะสามารถเข้าถึงข้อมูลในตัวยึดได้ดังนั้นคุณไม่ควรต้องการตำแหน่ง และในทางทฤษฎีคุณสามารถแคชตำแหน่งเมื่อมีการเชื่อมโยงในอะแดปเตอร์ของคุณได้และใช้การมอบหมายเพื่อเรียกออกจากผู้ถือของคุณหากคุณต้องการแม้ว่าการใช้Contextมุมมองจากมุมมองที่ถูกผูกไว้ในบางครั้งก็เพียงพอแล้ว
qix

10

คำตอบของ @ มองซิเออร์ได้ผลสำหรับฉัน แต่ต้องแก้ไขโค้ดหลายอย่างก่อน เหมือนกับว่าเขาโพสต์ตัวอย่างโค้ดจากการทำโค้ดซ้ำหลาย ๆ ครั้ง การเปลี่ยนแปลงที่ต้องทำ ได้แก่

  • RecyclerContextMenuInfoและRecyclerViewContextMenuInfoเป็นคลาสเดียวกัน เลือกชื่อและติดมัน
  • ViewHolderจะต้องดำเนินการView.OnLongClickListenerและอย่าลืมที่จะเรียกsetOnLongClickListener()ในรายการในตัวสร้าง
  • ในonLongClick()ผู้ฟังgetView().showContextMenu()ผิดอย่างสมบูรณ์ คุณต้องโทรshowContextMenuForChild()เข้าContextMenuRecyclerViewมิฉะนั้นContextMenuInfoคุณจะเข้ามาonCreateContextMenu()และonContextItemSelected()จะเป็นโมฆะ

รหัสที่แก้ไขของฉันด้านล่าง:

ContextMenuRecyclerView:

public class ContextMenuRecyclerView extends RecyclerView {

    private RecyclerViewContextMenuInfo mContextMenuInfo;

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

    @Override
    public boolean showContextMenuForChild(View originalView) {
        final int longPressPosition = getChildPosition(originalView);
        if (longPressPosition >= 0) {
            final long longPressId = getAdapter().getItemId(longPressPosition);
                mContextMenuInfo = new RecyclerViewContextMenuInfo(longPressPosition, longPressId);
            return super.showContextMenuForChild(originalView);
        }
        return false;
    }

    public static class RecyclerViewContextMenuInfo implements ContextMenu.ContextMenuInfo {

        public RecyclerViewContextMenuInfo(int position, long id) {
            this.position = position;
            this.id = id;
        }

        final public int position;
        final public long id;
    }
}

ในส่วนของคุณ:

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mRecyclerView = view.findViewById(R.id.recyclerview);
    registerForContextMenu(mRecyclerView);
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    // inflate menu here
    // If you want the position of the item for which we're creating the context menu (perhaps to add a header or something):
    int itemIndex = ((ContextMenuRecyclerView.RecyclerViewContextMenuInfo) menuInfo).position;
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    ContextMenuRecyclerView.RecyclerViewContextMenuInfo info = (ContextMenuRecyclerView.RecyclerViewContextMenuInfo) item.getMenuInfo();
    // handle menu here - get item index or ID from info
    return super.onContextItemSelected(item);
}

ใน ViewHolder ของคุณ:

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener {

    public MyViewHolder( View itemView ) {
        super( itemView );
        itemView.setOnLongClickListener( this );
    }

    @Override public boolean onLongClick() {
        recyclerView.showContextMenuForChild( v );
        return true;
    }
}

นอกจากนี้อย่าลืมแทนที่RecyclerViewด้วยContextMenuRecyclerViewในเลย์เอาต์ของคุณ!


1
ขอบคุณ @ josh2112 สำหรับการชี้ความผิดพลาดฉันออกฉันเพียงแค่การแก้ไขพวกเขา - แต่เกี่ยวกับจุดสุดท้ายของคุณคุณสามารถแทนที่โดยrecyclerView.showContextMenuForChild(itemView); itemView.showContextMenu()
Renaud Cerrato

1
สิ่งสำคัญ: ในขณะที่ขยาย RecyclerView ไปยัง ContextMenuRecyclerView อย่าลืมเพิ่ม CONSTRUCTORS ที่ IDE แนะนำ โดยเฉพาะอย่างยิ่งถ้าคุณไม่ใช้ตัวสร้างสองอาร์กิวเมนต์ที่ใช้ Context และ AttributeSet Android จะไม่สามารถขยาย XML เค้าโครงของคุณได้
Lidia Hocke

7

นี่คือวิธีที่สะอาดในการใช้บริบทเมนูบนรายการ RecyclerView

ขั้นแรกคุณต้องมีตำแหน่งรายการ

ในคลาสอะแดปเตอร์:

 /**
 * Custom on long click item listener.
 */
onLongItemClickListener mOnLongItemClickListener;

public void setOnLongItemClickListener(onLongItemClickListener onLongItemClickListener) {
    mOnLongItemClickListener = onLongItemClickListener;
}

public interface onLongItemClickListener {
    void ItemLongClicked(View v, int position);
}

ในการonBindViewHolderเชื่อมต่อตัวฟังที่กำหนดเอง:

        // Hook our custom on long click item listener to the item view.
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (mOnLongItemClickListener != null) {
                    mOnLongItemClickListener.ItemLongClicked(v, position);
                }

                return true;
            }
        });

ใน MainActivity (Activity / Fragment) ให้สร้างฟิลด์:

private int mCurrentItemPosition;

ในวัตถุอะแดปเตอร์ของคุณตั้งค่า Listener แบบกำหนดเอง:

    mAdapter.setOnLongItemClickListener(new FileAdapter.onLongItemClickListener() {
        @Override
        public void ItemLongClicked(View v, int position) {
            mCurrentItemPosition = position;
        }
    });

ตอนนี้คุณมีตำแหน่งที่อร่อยสำหรับรายการใด ๆ ที่คุณคลิกมานานแล้ว😋

อย่างที่สองสร้างเมนูของคุณ

ใน res -> เมนู สร้างไฟล์ต่อรายการเมนูของคุณcontext_menu_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/delete" android:title="Delete"/>
<item android:id="@+id/share" android:title="Share"/>
</menu>

ใน MainActivity: ใช้ทั้งสองอย่างonCreateContextMenuและonContextItemSelected:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.context_menu_main, menu);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    int id = item.getItemId();
    if (id == R.id.delete) {

    }

    if (id == R.id.share) {

    }

    return true;
}

ประการที่สามกลับไปที่วัตถุอะแดปเตอร์ของคุณ

  1. ลงทะเบียนเมนูบริบทของคุณ
  2. แสดงเมนูบริบท

    registerForContextMenu(mRecyclerView);
    mAdapter.setOnLongItemClickListener(new FileAdapter.onLongItemClickListener() {
        @Override
        public void ItemLongClicked(View v, int position) {
            mCurrentItemPosition = position;
            v.showContextMenu();
        }
    });
    

หวังว่าฉันจะไม่ลืมอะไร🤔

ข้อมูลเพิ่มเติมที่เอกสารเมนู


ขอบคุณ! จะส่งข้อมูลไปยังเมนูบริบทได้อย่างไร ตัวอย่างเช่นรหัสรายการข้อความรายการและอื่น ๆ
CoolMind

4

นี่เป็นวิธีที่ง่ายกว่าในการใช้ Kotlin ที่เหมาะกับฉัน ความท้าทายที่สำคัญคือการหาตำแหน่งของรายการที่กด ภายในอะแดปเตอร์ของคุณคุณสามารถวางข้อมูลโค้ดนี้และจะสามารถจับตำแหน่งของรายการที่แสดงเมนูบริบทได้ นั่นคือทั้งหมด

override fun onBindViewHolder(holder: YourViewHolder, position: Int) {

...     

    holder.view.setOnCreateContextMenuListener { contextMenu, _, _ -> 
            contextMenu.add("Add").setOnMenuItemClickListener {
                    longToast("I'm pressed for the item at position => $position")
                    true    
            }       
    }       

} 

2
นี่เป็นวิธีที่เป็นธรรมชาติและควบคุมได้มากที่สุด
nima

3

ฉันอาจจะไปงานปาร์ตี้สาย แต่ฉันมีวิธีแก้ปัญหาวิธีการทำงานฉันได้ทำส่วนสำคัญสำหรับมัน

เพิ่มเมนูบริบทใน RecyclerView

ActivityName.java

//Import Statements

public class ActivityName extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view_birthdays);


        //Recycle View
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        mLayoutManager = new LinearLayoutManager(getApplicationContext());
        mRecyclerView.setLayoutManager(mLayoutManager);
        mAdapter = new BirthdaysListAdapter(data, this);
        mRecyclerView.setAdapter(mAdapter);


    }

RecyclerAdapter.java

//Import Statements


public class BirthdaysListAdapter extends RecyclerView.Adapter<BirthdaysListAdapter.ViewHolder> {
    static Context ctx;

    private List<typeOfData> Data;


    public BirthdaysListAdapter(List<typeOfData> list, Context context) {
        Data = list;
        this.ctx = context;

    }

    BirthdaysListAdapter() {
    }

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {
        public TextView name;
        public TextView Birthday;
        public ImageView colorAlphabet;
        public TextView textInImg;


        public ViewHolder(View v) {
            super(v);
            name = (TextView) v.findViewById(R.id.name);
            Birthday = (TextView) v.findViewById(R.id.Birthday);
            colorAlphabet = (ImageView) v.findViewById(R.id.colorAlphabet);
            textInImg = (TextView) v.findViewById(R.id.textInImg);


            v.setOnCreateContextMenuListener(this); //REGISTER ONCREATE MENU LISTENER
        }

        @Override
        public void onCreateContextMenu(ContextMenu menu, View v                         //CREATE MENU BY THIS METHOD
                                        ContextMenu.ContextMenuInfo menuInfo) {
            new BirthdaysListAdapter().info = (AdapterView.AdapterContextMenuInfo) menuInfo;
            MenuItem Edit = menu.add(Menu.NONE, 1, 1, "Edit");
            MenuItem Delete = menu.add(Menu.NONE, 2, 2, "Delete");
            Edit.setOnMenuItemClickListener(onEditMenu);
            Delete.setOnMenuItemClickListener(onEditMenu);


        }
//ADD AN ONMENUITEM LISTENER TO EXECUTE COMMANDS ONCLICK OF CONTEXT MENU TASK
        private final MenuItem.OnMenuItemClickListener onEditMenu = new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {


                DBHandler dbHandler = new DBHandler(ctx);
                List<WishMen> data = dbHandler.getWishmen();

                switch (item.getItemId()) {
                    case 1:
                        //Do stuff
                        break;

                    case 2:
                       //Do stuff

                        break;
                }
                return true;
            }
        };


    }


    public List<ViewBirthdayModel> getData() {
        return Data;
    }


    @Override
    public long getItemId(int position) {

        return super.getItemId(position);
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_view_birthdays, parent, false);
        ViewHolder vh = new ViewHolder(view);
        return vh;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        holder.name.setText(Data.get(position).getMan().getName());
        holder.Birthday.setText(Data.get(position).getMan().getBday());
        holder.colorAlphabet.setBackgroundColor(Color.parseColor(Data.get(position).getColor()));
        holder.textInImg.setText(String.valueOf(Data.get(position).getMan().getName().toUpperCase().charAt(0)));
           }


    @Override
    public int getItemCount() {
        return Data.size();
    }

    private int position;

    public int getPosition() {

        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }

}

3

ฉันได้รวมโซลูชันของฉันเข้ากับโซลูชันจาก @Hardik Shah:

ในกิจกรรมฉันมี:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    if (v.getId() == R.id.rvQuests) {
        getMenuInflater().inflate(R.menu.list_menu, menu);
    }
}

ในอะแดปเตอร์ฉันมี:

private MainActivity context;
private int position;

public int getPosition() {
    return position;
}

public void setPosition(int position) {
    this.position = position;
}

public QuestsAdapter(MainActivity context, List<Quest> objects) {
    this.context = context;
    this.quests.addAll(objects);
}

public class QuestViewHolder extends RecyclerView.ViewHolder {
    private QuestItemBinding questItemBinding;

    public QuestViewHolder(View v) {
        super(v);
        questItemBinding = DataBindingUtil.bind(v);
        v.setOnCreateContextMenuListener(context);
    }
}

@Override
public void onBindViewHolder(final QuestViewHolder holder, int position) {
    Quest quest = quests.get(position);
    holder.questItemBinding.setQuest(quest);
    holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            setPosition(holder.getAdapterPosition());
            return false;
        }
    });
}

@Override
public void onViewRecycled(QuestViewHolder holder) {
    holder.itemView.setOnLongClickListener(null);
    super.onViewRecycled(holder);
}

ในส่วนฉันมี:

@Override
public boolean onContextItemSelected(MenuItem item) {
    int position = ((QuestsAdapter) questsList.getAdapter()).getPosition();
    switch (item.getItemId()) {
        case R.id.menu_delete:
            Quest quest = questsAdapter.getItem(position);
            App.getQuestManager().deleteQuest(quest);
            questsAdapter.remove(quest);
            checkEmptyList();
            return true;
        default:
            return super.onContextItemSelected(item);
    }
}

2

วิธีแก้ปัญหาสำหรับผู้ที่ต้องการรับ item idContextMenuเมื่อโทร

หากคุณมีRecyclerViewรายการที่มีลักษณะนี้ (มีรายการที่คลิกได้ImageView):

รายการ

จากนั้นคุณควรได้รับการติดต่อกลับจาก onClickListenerแล้วคุณควรจะได้รับการเรียกกลับจาก

อะแดปเตอร์

class YourAdapter(private val contextMenuCallback: ContextMenuCallback) :
    RecyclerView.Adapter<YourAdapter.ViewHolder>() {

    private var items: MutableList<Item> = mutableListOf()

    ...

    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        val item = items[position] as Item
        updateItem(viewHolder, item)

        setOnClickListener(viewHolder.itemView, items[position].id, items[position].title)
    }

    private fun setOnClickListener(view: View, id: Int, title: String) {
//        view.setOnClickListener { v ->  }
        // A click listener for ImageView `more`.
        view.more.setOnClickListener {
            // Here we pass item id, title, etc. to Fragment.
            contextMenuCallback.onContextMenuClick(view, id, title)
        }
    }


    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val titleTextView: TextView = itemView.title
    }

    class Item(
        val id: Int,
        val title: String
    )

    interface ContextMenuCallback {
        fun onContextMenuClick(view: View, id: Int, title: String)
    }
}

ส่วนย่อย

class YourFragment : Fragment(), YourAdapter.ContextMenuCallback {

    private var adapter: YourAdapter? = null
    private var linearLayoutManager: LinearLayoutManager? = null
    private var selectedItemId: Int = -1
    private lateinit var selectedItemTitle: String


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        adapter = YourAdapter(this)
        view.recycler_view.apply {
            layoutManager = linearLayoutManager
            adapter = this@YourFragment.adapter
            setHasFixedSize(true)
        }

        registerForContextMenu(view.recycler_view)
    }

    override fun onCreateContextMenu(menu: ContextMenu?, v: View?,
                                     menuInfo: ContextMenu.ContextMenuInfo?) {
        activity?.menuInflater?.inflate(R.menu.menu_yours, menu)
    }

    override fun onContextItemSelected(item: MenuItem?): Boolean {
        super.onContextItemSelected(item)
        when (item?.itemId) {
            R.id.action_your -> yourAction(selectedItemId, selectedItemTitle)
            ...
        }
        return true
    }

    override fun onContextMenuClick(view: View, id: Int, title: String) {
        // Here we accept item id, title from adapter and show context menu.
        selectedItemId = id
        selectedItemTitle = title
        view.showContextMenu()
    }
}

คำเตือน!

หากคุณใช้ส่วนที่ViewPagerอิงตามส่วนเดียว (ทุกหน้าเป็นรายการที่คล้ายกัน) คุณจะประสบปัญหา เมื่อคุณลบล้างonContextItemSelectedเพื่อทำความเข้าใจว่ารายการเมนูใดถูกเลือกคุณจะได้รับรหัสรายการจากหน้าแรก! ที่จะเอาชนะปัญหานี้ดูส่วนผิดใน ViewPager ได้รับโทรศัพท์


1

สวัสดีพวกผมมาพร้อมกับทางเลือกหนึ่งที่เหมาะกับฉัน ฉันเพิ่งลงทะเบียน itemView ของฉันด้วย registerContextMenu และ ViewHolder Constructor ยังตั้งค่า onLongClikcListener เป็น View เดียวกัน ในการใช้งาน onLongClick (View v) ฉันได้รับตำแหน่งที่คลิกด้วย getLayoutPosition () และบันทึกในตัวแปรอินสแตนซ์ (ฉันสร้างคลาสเพื่อแสดงข้อมูลนี้เช่นเดียวกับที่คาดว่า ContextMenuInfo จะทำงาน) แต่สิ่งที่สำคัญกว่าคือการทำให้ แน่ใจว่าคุณส่งคืนเท็จในวิธีนี้ สิ่งที่คุณต้องทำตอนนี้คือคุณใน onContextItemSelected (รายการ MenuItem) อ่านข้อมูลที่คุณเก็บไว้ในตัวแปรอินสแตนซ์ของคุณและหากถูกต้องคุณจะดำเนินการต่อ นี่คือตัวอย่างข้อมูล

  public MyViewHolder(View itemView){
super(itemView);
registerForContextMenu(itemView);
itemView.setOnLongClickListener(this);
}

ฉันทำให้ ViewHolder ใช้ OnLongClickListener แต่คุณสามารถทำได้ในแบบที่คุณต้องการ

@Override
public boolean onLongClick(View v){
    mCurrentLongItem = new ListItemInfo(v.getId(), getLayoutPosition());
    return false; // REMEMBER TO RETURN FALSE.
  }

คุณยังสามารถตั้งค่านี้ในอะแดปเตอร์หรือเป็นมุมมองอื่นที่คุณมีใน ViewHolder (เช่น TextView) สิ่งสำคัญคือการใช้งาน onLongClik ()

@Override
public boolean onContextItemSelected(MenuItem item) {
    switch (item.getItemId()){
        case R.id.client_edit_context_menu:
            if(mCurrentLongItem != null){
                 int position = mCurrentLongItem.position;
                //TAKE SOME ACTIONS.
                mCurrentLongItem = null;
            }
            return true;
    }
    return super.onContextItemSelected(item);
}

ส่วนที่ดีที่สุดคือคุณยังสามารถประมวลผลเหตุการณ์ LongClick ที่ส่งคืนจริงในกรณีที่คุณต้องการและ conextMenu จะไม่ปรากฏขึ้น

วิธีนี้ใช้ได้ผลเนื่องจาก registerForContextView ทำให้ View LongClickable และเมื่อถึงเวลาประมวลผล ContextMenu ระบบจะเรียกใช้ performLongClick ซึ่งเรียกการใช้งาน onLongClick เป็นครั้งแรกและหากส่งคืนเป็นเท็จระบบจะเรียกใช้ showContextMenu


1

ฉันใช้วิธีแก้ปัญหานี้มาระยะหนึ่งแล้วและได้ผลดีสำหรับฉัน

public class CUSTOMVIEWNAME extends RecyclerView { 

public CUSTOMVIEWNAME(Context context) {
    super(context);
}

public CUSTOMVIEWNAME (Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CUSTOMVIEWNAME (Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

private RecyclerContextMenuInfo mContextMenuInfo;

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

@Override
public boolean showContextMenuForChild(View originalView) {
    final int longPressPosition = getChildAdapterPosition(originalView);
    if (longPressPosition >= 0) {
        final long longPressId = getAdapter().getItemId(longPressPosition);
        mContextMenuInfo = new RecyclerContextMenuInfo(longPressPosition,    `           longPressId);
        return super.showContextMenuForChild(originalView);
    }
    return false;
}

public class RecyclerContextMenuInfo implements ContextMenu.ContextMenuInfo             {

    public RecyclerContextMenuInfo(int position, long id) {
        this.position = position;
        this.id = id;
    }

    final public int position;
    final public long id;
}
}

ตอนนี้ในส่วนหรือกิจกรรมของคุณใช้วิธีการต่อไปนี้

  @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);

    // Inflate Menu from xml resource
    MenuInflater menuInflater = getMenuInflater();
    menuInflater.inflate(R.menu.context_menu, menu);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    ContextMenuRecyclerView.RecyclerContextMenuInfo info = (ContextMenuRecyclerView.RecyclerContextMenuInfo) item.getMenuInfo();
    Toast.makeText(InstanceOfContext , " User selected  " + info.position, Toast.LENGTH_LONG).show();

    return false;
}

สุดท้ายลงทะเบียนสำหรับ contextMenu ในมุมมองรีไซเคิล

   //for showing a popup on LongClick of items in recycler.
    registerForContextMenu(recyclerView);

ที่น่าทำงาน!


1

นี่คือวิธีที่คุณสามารถใช้เมนูบริบทสำหรับ RecyclerView และรับตำแหน่งของรายการซึ่งรายการเมนูบริบทถูกเลือก:

public class YourAdapter extends RecyclerView.Adapter<YourAdapter.ViewHolder> {

... 

@Override
public void onBindViewHolder(@NonNull final ViewHolder viewHolder, int position) {

    ...

    viewHolder.itemView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            menu.add(0, R.id.mi_context_disable, 0, R.string.text_disable)
                    .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                        @Override
                        public boolean onMenuItemClick(MenuItem item) {
                            // can do something with item at position given below,
                            // viewHolder is final
                            viewHolder.getAdapterPosition();
                            return true;
                        }
                    });
            menu.add(0, R.id.mi_context_remove, 1, R.string.text_remove)
                    .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                        @Override
                        public boolean onMenuItemClick(MenuItem item) {                                
                            // can do something with item at position given below,
                            // viewHolder is final
                            viewHolder.getAdapterPosition();
                            return true;
                        }
                    });
        }
    });
}

static class ViewHolder extends RecyclerView.ViewHolder {
    private View itemView;

    private ViewHolder(@NonNull View itemView) {
        super(itemView);
        this.itemView = itemView;
    }
}

}


0

ฉันดิ้นรนกับเรื่องนี้เพราะ Android ไม่ได้จัดการสิ่งนี้ให้ฉันใน RecyclerView ซึ่งทำงานได้ดีมากสำหรับ ListView

ชิ้นส่วนที่ยากที่สุดคือชิ้นส่วน ContextMenuInfo ถูกฝังอยู่ใน View ซึ่งคุณไม่สามารถแนบได้อย่างง่ายดายนอกจากการแทนที่ View

ดังนั้นคุณจะต้องมีกระดาษห่อหุ้มที่ช่วยส่งข้อมูลตำแหน่งไปยังกิจกรรม

public class RecyclerContextMenuInfoWrapperView extends FrameLayout {
private RecyclerView.ViewHolder mHolder;
private final View mView;

public RecyclerContextMenuInfoWrapperView(View view) {
    super(view.getContext());
    setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    mView = view;
    addView(mView);
}

public void setHolder(RecyclerView.ViewHolder holder) {
    mHolder = holder;
}

@Override
protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
    return new RecyclerContextMenuInfo(mHolder.getPosition(), mHolder.getItemId());
}

public static class RecyclerContextMenuInfo implements ContextMenu.ContextMenuInfo {

    public RecyclerContextMenuInfo(int position, long id) {
        this.position = position;
        this.id = id;
    }

    final public int position;
    final public long id;
}

}

จากนั้นใน RecyclerAdapter ของคุณเมื่อคุณสร้าง ViewHolders คุณต้องตั้งค่า Wrapper เป็นมุมมองรูทและลงทะเบียน contextMenu ในแต่ละมุมมอง

public static class AdapterViewHolder extends RecyclerView.ViewHolder {
    public AdapterViewHolder(  View originalView) {
        super(new RecyclerContextMenuInfoWrapperView(originalView);
        ((RecyclerContextMenuInfoWrapperView)itemView).setHolder(this);
        yourActivity.registerForContextMenu(itemView);
        itemView.setOnCreateContextMenuListener(yourListener);
    }

}

และสุดท้ายในกิจกรรมของคุณคุณจะสามารถทำสิ่งที่คุณมักจะทำ:

@Override
public boolean onContextItemSelected(MenuItem item) {
    int position = ((RecyclerContextMenuInfoWrapperView.RecyclerContextMenuInfo)item.getMenuInfo()).position;
    // do whatever you need as now you have access to position and id and everything

0

วิธีที่ดีที่สุดคือการใช้เมนูบริบทที่มีมุมมองผู้รีไซเคิลคือถ้าคุณสร้างมุมมองผู้รีไซเคิลแบบกำหนดเองและแทนที่getContextMenuInfo()วิธีการและส่งคืนอินสแตนซ์ของวัตถุข้อมูลเมนูบริบทของคุณเองเพื่อให้คุณสามารถดึงตำแหน่งเมื่อสร้างขึ้นและเมื่อคลิกเมนู:

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

ดูส่วนสำคัญที่ฉันสร้างขึ้นนี้:

https://gist.github.com/resengupta/2b2e26c949b28f8973e5


0

ขยายคำตอบด้านบนเล็กน้อยหากคุณต้องการหลีกเลี่ยงการกำหนดเมนูด้วยตนเองในโค้ดของคุณใน Adapter / ViewHolder คุณสามารถใช้ PopupMenu และขยายตัวเลือกเมนูจากไฟล์ทรัพยากร menu.xml มาตรฐาน

ตัวอย่างด้านล่างแสดงสิ่งนี้รวมถึงความสามารถในการส่งผ่าน Listener ที่คุณสามารถนำไปใช้ใน Fragment / Activity เพื่อตอบสนองต่อการคลิกเมนูบริบท

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {

private List<CustomObject> objects;
private OnItemSelectedListener listener;
private final boolean withContextMenu;

class ViewHolder extends RecyclerView.ViewHolder
        implements View.OnClickListener, View.OnCreateContextMenuListener, PopupMenu.OnMenuItemClickListener {

    @BindView(R.id.custom_name)
    TextView name;

    @BindView(R.id.custom_value)
    TextView value;

    ViewHolder(View view) {
        super(view);
        ButterKnife.bind(this, view);
        view.setOnClickListener(this);
        if (withContextMenu) {
            view.setOnCreateContextMenuListener(this);
        }
    }

    @Override
    public void onClick(View v) {
        int position = getAdapterPosition();
        if (listener != null) {
            listener.onCustomerSelected(objects.get(position));
        }
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        PopupMenu popup = new PopupMenu(v.getContext(), v);
        popup.getMenuInflater().inflate(R.menu.custom_menu, popup.getMenu());
        popup.setOnMenuItemClickListener(this);
        popup.show();
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        if (listener != null) {
            CustomObject object = objects.get(getAdapterPosition());
            listener.onCustomerMenuAction(object, item);
        }
        return false;
    }
}

public CustomerAdapter(List<CustomObject> objects, OnItemSelectedListener listener, boolean withContextMenu) {
    this.listener = listener;
    this.objects = objects;
    this.withContextMenu = withContextMenu;
}

public interface OnItemSelectedListener {

    void onSelected(CustomObject object);

    void onMenuAction(CustomObject object, MenuItem item);
}

@Override
public CustomerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.snippet_custom_object_line, parent, false);
    return new ViewHolder(v);
}

@Override
public void onBindViewHolder(CustomAdapter.ViewHolder holder, int position) {
    CustomObject object = objects.get(position);
    holder.name.setText(object.getName());
    holder.value.setText(object.getValue());
}

@Override
public int getItemCount() {
    return objects.size();
}
}

ข้อมูลสำคัญทั้งหมดที่นี่ https://gist.github.com/brettwold/45039b7f02ce752ae0d32522a8e2ad9c


0

คุณสามารถส่ง OnCreateContextMenuListener ไปยัง ViewHolder เมื่อผูก Listener นี้สามารถสร้างเมนูแบบกำหนดเองสำหรับข้อมูลแต่ละรายการ เพียงเพิ่ม setOnCreateContextMenuListener ใน ViewHolder ของคุณและเรียกใช้ในระหว่างการผูก

     public static class ItemViewHolder extends RecyclerView.ViewHolder
     {


        public ItemViewHolder(View itemView) {
            super(itemView);


        }
        void setOnCreateContextMenuListener(View.OnCreateContextMenuListener listener) {
            itemView.setOnCreateContextMenuListener(listener);
        }

}

ในอะแดปเตอร์:

      @Override
     public void onBindViewHolder(ItemViewHolder viewHolder,
                    int position) {
         final MyObject myObject = mData.get(position);
         viewHolder.setOnCreateContextMenuListener(new OnCreateContextMenuListener(){

                    @Override
                    public void onCreateContextMenu(ContextMenu menu,
                            View v, ContextMenuInfo menuInfo) {
                        switch (myObject.getMenuVariant() {
                            case MNU_VARIANT_1:
                                menu.add(Menu.NONE, CTX_MNU_1, 
                                        Menu.NONE,R.string.ctx_menu_item_1);    
                                menu.add(Menu.NONE, CTX_MNU_2,Menu.NONE, R.string.ctx_menu_item_2); 
                            break;
                            case MNU_VARIANT_2:
                                menu.add(Menu.NONE, CTX_MNU_3,Menu.NONE, R.string.ctx_menu_item_3); 
                            break;
                            default:
                                menu.add(Menu.NONE, CTX_MNU_4, 
                                        Menu.NONE, R.string.ctx_menu_item_4);   

                        }
                    }

                });
     }

0

ในกรณีของฉันฉันต้องใช้ข้อมูลจากส่วนของฉันในonContextItemSelected()วิธีการ วิธีแก้ปัญหาที่ฉันลงเอยด้วยการส่งอินสแตนซ์ของชิ้นส่วนไปยังอะแดปเตอร์ของฉันและลงทะเบียนรายการมุมมองในที่ยึดมุมมอง:

@Override
public void onBindViewHolder(final MyListAdapter.ViewHolder viewHolder, int position) {
    final Object rowObject = myListItems.get(position);

    // Do your data binding here

    viewHolder.itemView.setTag(position);
    fragment.registerForContextMenu(viewHolder.itemView);
}

จากนั้นonCreateContextMenu()คุณสามารถบันทึกดัชนีเป็นตัวแปรท้องถิ่น:

selectedViewIndex = (int)v.getTag();

และดึงข้อมูลเข้ามา onContextItemSelected()


0

ครั้งแรกที่ฉันพบปัญหานี้กับอะแดปเตอร์ปกติฉันลงเอยด้วยการสร้างคลาสย่อย View ที่กำหนดเองของฉันเองและจัดเก็บสิ่งที่ฉันต้องการ ฉันไม่ชอบวิธีแก้ปัญหานั้นจริงๆและใช้เวลาส่วนใหญ่ในการดูความคิดที่ยอดเยี่ยมที่ผู้คนเสนอมาและตัดสินใจว่าฉันไม่ชอบพวกเขาไปมากกว่านี้แล้ว ฉันก็เลยรวบรวมทุกอย่างเข้าด้วยกันเขย่ามันสักพักแล้วก็ออกมาพร้อมกับสิ่งใหม่ที่ฉันชอบ

เราเริ่มต้นด้วยคลาสยูทิลิตี้สองสามคลาส ContextMenuHandler เป็นอินเทอร์เฟซสำหรับวัตถุใด ๆ ที่จะจัดการกับเมนูบริบท ในทางปฏิบัตินี่จะเป็นคลาสย่อยของ ViewHolder แต่ในทางทฤษฎีมันอาจเป็นอะไรก็ได้

/**
 * Interface for objects that wish to create and handle selections from a context
 * menu associated with a view
 */
public interface ContextMenuHandler extends View.OnCreateContextMenuListener {

  boolean onContextItemSelected(MenuItem item);
}

ถัดไปคืออินเทอร์เฟซที่จะต้องใช้งานโดย View ใด ๆ ที่จะถูกใช้เป็นส่วนย่อยของ RecyclerView ในทันที

public interface ViewWithContextMenu {
  public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler);

  public ContextMenuHandler getContextMenuHandler();
}

ถัดไปมุมมองใด ๆ ที่จะสร้างเมนูบริบทในฐานะลูกของ RecylcerView จะต้องใช้ ViewWIthContextMenu ในกรณีของฉันฉันต้องการคลาสย่อยของ LinearLayout เท่านั้น

public class LinearLayoutWithContextMenu extends LinearLayout implements ViewWithContextMenu {

  public LinearLayoutWithContextMenu(Context context) {
    super(context);
   }

  public LinearLayoutWithContextMenu(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  private ContextMenuHandler handler;

  @Override
  public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler) {
    this.handler = handler;
    setOnCreateContextMenuListener(fragment);
  }

  @Override
  public ContextMenuHandler getContextMenuHandler() {
    return handler;
  }
}

และสุดท้ายเราจำเป็นต้องมีคลาส Fragment ที่ถูกปรับปรุงเพื่อสกัดกั้นการเรียกเมนูบริบทและเปลี่ยนเส้นทางไปยังตัวจัดการที่เหมาะสม

public class FragmentWithContextMenu extends Fragment {

  ContextMenuHandler handler = null;

  @Override
  public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, view, menuInfo);
    handler = null;
    if (view instanceof ViewWithContextMenu) {
      handler = ((ViewWithContextMenu)view).getContextMenuHandler();
      if (handler != null) handler.onCreateContextMenu(menu, view, menuInfo);
    }
  }

  @Override
  public boolean onContextItemSelected(MenuItem item) {
    if (handler != null) {
      if (handler.onContextItemSelected(item)) return true;
    }
    return super.onContextItemSelected(item);
  }
}

ด้วยเหตุนี้การใช้งานขั้นสุดท้ายจึงค่อนข้างง่าย แฟรกเมนต์หลักต้องมีคลาสย่อย FragmentWithContextMenu ตั้งค่า RecylerWindow หลักตามปกติและส่งผ่านตัวเองไปยังคลาสย่อยของ Adapter คลาสย่อยของ Adapter มีลักษณะดังนี้

public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {

  private final FragmentWithContextMenu fragment;

  Adapter(FragmentWithContextMenu fragment) {
    this.fragment = fragment;
  }

  @Override
  public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(context)
        .inflate(R.layout.child_view, parent, false);
    return new ViewHolder(view);
  }

  @Override
  public void onBindViewHolder(final Adapter.ViewHolder holder, int position) {
    // Logic needed to bind holder to specific position
    // ......
  }

  @Override
  public int getItemCount() {
    // Logic to return current item count
    // ....
  }

  public class ViewHolder extends RecyclerView.ViewHolder implements ContextMenuHandler {

    ViewHolder(View view) {
      super(view);
      ((ViewWithContextMenu)view).setContextMenuHandler(fragment, this);

      view.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {

          // Do stuff to handle simple clicks on child views
          // .......
        }
      });
    }

   @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {

      // Logic to set up context menu goes here
      // .... 
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {

      // Logic to handle context menu item selections goes here
      // ....

      return true;
    }
  }
}

เกี่ยวกับมัน. ดูเหมือนจะใช้งานได้ทั้งหมด มันใส่คลาสยูทิลิตี้ทั้งหมดไว้ในแพ็คเกจเมนูบริบทแยกต่างหากดังนั้นฉันสามารถตั้งชื่อคลาสที่ตรงกับคลาสที่มีคลาสย่อยได้ แต่ฉันคิดว่าน่าจะสับสนมากกว่านี้


-1

ตกลงจากคำตอบของ @ Flexo ฉันจะใส่ mPosition เพื่อสั่ง ...

protected class ExampleViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {

    int mPosition;

    public KWViewHolder(View itemView) {
        super(itemView);
        itemView.setOnCreateContextMenuListener(this);
    }

    public void setPosition(int position) {
        mPosition = position;
    }

    @Override
    public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
        contextMenu.setHeaderTitle(R.string.menu_title_context);
        contextMenu.add(0, R.id.menu_delete, mPosition, R.string.delete);
    }
}

จากนั้นในonContextItemSelectedฉันใช้

item.getOrder() 

และทำงานได้ดีฉันได้ตำแหน่งอาร์เรย์อย่างง่ายดาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.