11

I have a RecyclerView, when RecyclerView item clicked, want to open a popup window which contains another RecyclerView. It is almost done, but in popup window, cardviews don't appear. I can't figure out why, can any one help?

1- My Main RecyclerView Adapter

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>    {

private ArrayList<Mission> mDataset;
private Context mContext;

// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<Mission> myDataset, Context context) {
    mDataset = myDataset;
    this.mContext = context;
}

// Create new views (invoked by the layout manager)
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // create a new view
    View v = LayoutInflater.from(mContext)
            .inflate(R.layout.mission_card_item, parent, false);
    // set the view's size, margins, paddings and layout parameters
    MyViewHolder vh = new MyViewHolder(v);
    return vh;
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    holder.mTextView.setText(mDataset.get(position).getName());
    holder.mPuanView.setText(mDataset.get(position).getPoint());
    holder.mRankView.setText(mDataset.get(position).getRank());

    holder.btnAdd.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(mContext,"Buton Clicked", Toast.LENGTH_SHORT).show();
        }
    });
}

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

    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public  class MyViewHolder extends RecyclerView.ViewHolder {

        public CardView mCardView;
        public TextView mTextView;
        public TextView mPuanView;
        public TextView mRankView;
        public Button btnAdd;

        public MyViewHolder(final View itemView) {
            super(itemView);

            mCardView = (CardView) itemView.findViewById(R.id.card_view);
            mTextView = (TextView) itemView.findViewById(R.id.tv_text);
            mRankView = (TextView) itemView.findViewById(R.id.tv_rank);
            mPuanView = (TextView) itemView.findViewById(R.id.tv_puan);

            btnAdd = (Button) itemView.findViewById(R.id.button_add);


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

                    showPopup();

                    Toast.makeText(itemView.getContext(),"Element " + getAdapterPosition() + " clicked", Toast.LENGTH_SHORT).show();
                    Log.d("hello", "Element " + getAdapterPosition() + " clicked.");
                }
            });
        }
    }

 public void showPopup(){
        final View popupView = LayoutInflater.from(mContext).inflate(R.layout.recycler_popup_window, null);
        final PopupWindow popupWindow = new PopupWindow(popupView, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);

Button btn = (Button) popupView.findViewById(R.id.button);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popupWindow.dismiss();
            }
        });

        RecyclerView recyclerView = (RecyclerView) popupView.findViewById(R.id.rv_recycler_view);
        ArrayList<String> data = new ArrayList<>();
        data.add("my data");
        data.add("my test data");
        PopupRecyclerViewAdapter adapter = new PopupRecyclerViewAdapter(mContext,data);
        recyclerView.setAdapter(adapter);

        popupWindow.showAtLocation(popupView,Gravity.CENTER, 0, 0);

    }

}

2- My second RecyclerView adapter, its for popup window

public class PopupRecyclerViewAdapter extends RecyclerView.Adapter<PopupRecyclerViewAdapter.MyViewHolder>{

    private Context mContext;
    private ArrayList<String> data;

    public PopupRecyclerViewAdapter(Context mContext, ArrayList<String> data) {
        this.mContext = mContext;
        this.data = data;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(mContext).inflate(R.layout.recycler_popup_card_item, parent,false);
        MyViewHolder vh = new MyViewHolder(v);
        return vh;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.mTextView.setText(data.get(position));
    }

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


    //View Holder
    public class MyViewHolder extends RecyclerView.ViewHolder {

        public TextView mTextView;

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

            mTextView = (TextView) itemView.findViewById(R.id.tv_text2);
        }
    }
}

3- Layout for Recycler popup window

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content" android:layout_height="wrap_content">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_recycler_view2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/button"
        android:background="#ff4545">
    </android.support.v7.widget.RecyclerView>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Close"
        android:id="@+id/button"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

4- CardView Layout for popup RecyclerView

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_margin="10dp"
        android:layout_height="wrap_content"
        card_view:cardCornerRadius="4dp"
        card_view:elevation="14dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:gravity="center">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="175dp"
            android:id="@+id/imageView2"
            android:src="@mipmap/testimage"
            android:layout_marginBottom="10dp"
            android:scaleType="centerCrop"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/tv_text2"
            android:text="Blah blah blah..."
            android:gravity="center"
            android:layout_marginBottom="10dp"/>

        </LinearLayout>


    </android.support.v7.widget.CardView>

</RelativeLayout>
kgandroid
  • 5,507
  • 5
  • 39
  • 69
ysfcyln
  • 2,857
  • 6
  • 34
  • 61
  • put a toast in showpopup to check that it is get calling or not – kgandroid Sep 14 '16 at 14:06
  • I checked with toast also I set red background color for check in Recycler popup window, popup shows up but cardviews which should be there, not appear – ysfcyln Sep 14 '16 at 14:16
  • Code seems ok...print the data.size()....and also check the logcat – kgandroid Sep 14 '16 at 14:20
  • I put a log and checked data.size(), its okey too, still cant understand why cardviews dont appear – ysfcyln Sep 15 '16 at 07:46
  • now print data.get(position) and check it is giving correct value or not.... – kgandroid Sep 15 '16 at 10:40
  • I put 3 three log, first two are in showPopup() function, Log.d("test", "data0" + data.get(0) + "tested" ) and Log.d("test", "data1" + data.get(1) + "tested" ) and the last log is in onBindViewHolder method in second RecyclerView adapter Log.d("test3", "ViewHolderData test" + data.get(position) + "tested" ) but test3 log did not appear, so I think maybe the problem is in second adapter class. Views can not bind properly – ysfcyln Sep 15 '16 at 21:48
  • I think you should implement the itemclick on the related activity/fragment and show the pop up over there.Showing pop up in the adapter is causing the problem – kgandroid Sep 16 '16 at 06:31
  • I called popup in fragment but still same problem – ysfcyln Sep 16 '16 at 09:16
  • ok then post your logcat when the popup is called – kgandroid Sep 16 '16 at 09:46
  • 09-16 12:53:24.561 29715-29715/com.example.demoapp E/RecyclerView: No layout manager attached; skipping layout [ 09-16 12:49:24.561 29715:29738 E/ ] [android_ws] Format: 5, Width: 1002, Height: 1845 [ 09-16 12:49:24.571 29715:29738 E/ ] [android_ws] Format: 5, Width: 378, Height: 132 – ysfcyln Sep 16 '16 at 09:55
  • 1
    Add the below lines in your recyclerview popup RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); recyler_view.setLayoutManager(mLayoutManager); – kgandroid Sep 16 '16 at 10:01
  • Wow, finally it works, can you post it as an answer so I can approve it – ysfcyln Sep 16 '16 at 10:51
  • Finally.............................. – kgandroid Sep 16 '16 at 10:51

2 Answers2

6

Add the below lines in your recyclerview popup:

RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); 
recyler_view.setLayoutManager(mLayoutManager); 
kgandroid
  • 5,507
  • 5
  • 39
  • 69
  • could you please see this question of mine? https://stackoverflow.com/questions/74036836/how-to-display-recyclerview-data-inside-a-popupwindow – Kumza Ion Oct 12 '22 at 07:07
0

You may, like me, find this becomes rather a lot of boilerplate code just for a simple Popup Window with a list of clickable items, and so I made a custom Drop Down class which is easily reusable. You just need the PopupWindow custom class, and the RecyclerView adapter, as well as an item data class (in Kotlin), and this is then easily reusable.

The DropDown class:

  class DropDown(context: Context, items: List<DropDownItem>, val listener: DropDownClickListener) : PopupWindow(context) {

  private val binding = DropdownLayoutBinding.inflate(LayoutInflater.from(context))

  init {
    contentView = binding.root
    setBackgroundDrawable(null)
    elevation = 8f
    isOutsideTouchable = true
    isFocusable = true
    binding.recyclerView.adapter = DropDownItemAdapter(items) { item -> onItemClicked(item) }
    setOnDismissListener { listener.onMenuDismissed() }
  }

  private fun onItemClicked(item: DropDownItem) {
    listener.onMenuItemClicked(item)
    dismiss()
  }

  fun show(anchor: View) {
    showAsDropDown(anchor, 0, 20)
  }

  interface DropDownClickListener {

    fun onMenuItemClicked(item: DropDownItem)

    fun onMenuDismissed()

  }

}

data class DropDownItem(
    val text: String,
    val icon: Int
)

With accompanying layout code:

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background="@drawable/rounded_corners"
  android:id="@+id/recycler_view"
  xmlns:tools="http://schemas.android.com/tools"
  tools:listitem="@layout/item_drop_down"
  app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintTop_toTopOf="parent" />

Explanation: This reusable new DropDown class uses ViewBinding of a simple layout that is simply a RecyclerView (with whatever Item layout you want, again mine is a reusable one called item_drop_down, a TextView with a Drawable.)

The constructor just needs three things, the context, the list of drop down items (I made a DropDownItem data class, which for simplicity I put in the same file), and then the listener - an interface also defined in this class).

In the init for this class, we set the content view, setBackgroundDrawable to null to get rid of an ugly border, give it some elevation, then make it dismissable by touching outside or pressing the back button. We then set the recyclerview adapter here from the list of items in the constructor. Finally, we set the on dismiss listener and defer to our interface.

Now the adapter code:

class DropDownItemAdapter(val items: List<DropDownItem>, val clickListener: (DropDownItem) -> Unit) : RecyclerView.Adapter<DropDownItemAdapter.ViewHolder>() {

  override fun getItemCount() = items.size

  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    return ViewHolder(ItemDropDownBinding.inflate(LayoutInflater.from(parent.context), parent, false))
  }

  override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.bind(items[position])
  }

  inner class ViewHolder(val binding: ItemDropDownBinding) : RecyclerView.ViewHolder(binding.root) {

    fun bind(item: DropDownItem) {
      binding.textView.text = item.text
      binding.textView.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(binding.root.context, item.icon), null, null, null)
      itemView.setOnClickListener { clickListener(item) }
    }

  }

}

This is just a straight forward RecyclerView adapter, and rather than another interface, the only thing this needs to notify is when an item is clicked, so simply accept a function parameter in the constructor for handling the clicks.

Altogether, it looks like this in the calling code:

DropDown(view.context, dropDownMenu, this).show(view)

Where dropDownMenu is a list of DropDownItem.

You can then handle the interface functions as desired:

    override fun onMenuItemClicked(item: DropDownItem) {
          when (item.text) {
            "Delete" -> // respond as desired
            "Edit" -> // simply inspect the text, or alter your DropDownItem to have an ID
          }
    }
    
   override fun onMenuDismissed() {
          // it may be useful to know when the popup is dismissed
          // in my case, I select the item which has been long pressed, and want to know when to un-select it
    }

With a nice rounded corners background on my DropDown layout, and being able to know when popup showing and when dismissed to highlight my chosen item, I get this nice effect:

Drop down popup window example

Vin Norman
  • 2,749
  • 1
  • 22
  • 33