Kalaivani R
Kalaivani R

Reputation: 357

How to pass a custom layout to a PopupMenu?

I want to customize the popupmenu in android, default popup menu gives more space ,so I'm trying to change the custom layout in popup menu but I cant figure out how.

enter image description here

Note: I want to do this small popup design so I go with default popup menu but i want to customize it.

findViewById(R.id.menuclick).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        PopupMenu popupMenu = new PopupMenu(Sample1.this, view);
        popupMenu.setOnMenuItemClickListener(Sample1.this);
        popupMenu.inflate(R.layout.menus_layout);
        popupMenu.show();
    }
});

Upvotes: 32

Views: 48717

Answers (3)

hcl2000
hcl2000

Reputation: 366

PopupMenu has the following constructor

public PopupMenu(@NonNull Context context, @NonNull View anchor, int gravity,
            @AttrRes int popupStyleAttr, @StyleRes int popupStyleRes)

Naturally, if you want to change the background, you need only define a style resource that sets that background, and then reference it on the fifth parameter. Setting zero on a parameter will use Android's defaults.

Example style:

<style name="popup_menu" parent="@android:style/Widget.PopupMenu">
   <item name="android:popupBackground">@drawable/bg_card</item>
</style>

Constructor invocation

PopupMenu popup
    = new PopupMenu(view.getContext(),
                    view,
                    Gravity.START,
                    0,
                    R.style.popup_menu);

Upvotes: 1

Liong
Liong

Reputation: 1584

My answer will be like an update for this answer (the first answer in this post) focusing at PopupWindow using Kotlin, also using View Binding

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    val bind = ViewBinding.inflate(inflater, container, false)

    val popupInflater =
        requireActivity().applicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflaterERVICE) as LayoutInflater
    val popupBind = YourPopupLayoutBinding.inflate(popupInflater)
    popupBind.icon1.setOnClickListener { // do your thing for 1st icon }
    popupBind.icon2.setOnClickListener { // do your thing for 2nd icon }

    val popupWindow = PopupWindow(
        popupBind.root, 126.fromDpToPx.toInt(),
        89.fromDpToPx.toInt(), true
    ).apply { contentView.setOnClickListener { dismiss() } }
    // make sure you use number than wrap_content or match_parent,
    // because for me it is not showing anything if I set it to wrap_content from ConstraintLayout.LayoutParams.

    bind.yourButton.setOnClickListener(popupWindow::showAsDropDown)

    return bind.root
}

This code is in Fragment class, that's why I call applicationContext using requireActivity()

Here is the code for layout,

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="126dp"
    android:layout_height="89dp"
    android:background="#FFFFFF">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/icon1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:drawablePadding="8dp"
        android:paddingHorizontal="10dp"
        android:paddingVertical="10dp"
        android:text="@string/tokopedia"
        android:textColor="@color/dark_grey"
        app:drawableStartCompat="@drawable/ic_icon1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/icon2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:drawablePadding="8dp"
        android:paddingHorizontal="10dp"
        android:paddingVertical="10dp"
        android:text="@string/shopee"
        android:textColor="@color/dark_grey"
        app:drawableStartCompat="@drawable/ic_icon2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/icon1" />
</androidx.constraintlayout.widget.ConstraintLayout>

Don't forget to add background color in custom layout, also you can styling freely in custom layout.

Hope this can help you all :)

Upvotes: 3

Abhi
Abhi

Reputation: 3511

To inflate popupMenu from a button onClick, use the following code.

btn = (Button) findViewById(R.id.btn);   
btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            PopupMenu popup = new PopupMenu(MainActivity.this, v);
            popup.getMenuInflater().inflate(R.menu.pop_up, popup.getMenu());

            popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                public boolean onMenuItemClick(MenuItem item) {
                    Toast.makeText(MainActivity.this, "Some Text" + item.getTitle(), Toast.LENGTH_SHORT).show();
                    return true;
                }
            });
            popup.show();//showing popup menu
        }
    });

EDIT

To style the popupMenu, add the following style.

<style name="PopupMenu" parent="@android:style/Widget.PopupMenu">
        <item name="android:popupBackground">#ffffff</item>
    </style>

I noticed you also want to add icons next to your text. It is possible to add icons in popupMenu. However it is a better approach to use popup Window instead. Here is a sample code:

PopupWindow mypopupWindow;
setPopUpWindow();  
     btn=(Button)findViewById(R.id.btn);  
     btn.setOnClickListener(new View.OnClickListener() {  
       @Override  
       public void onClick(View v) {              
           mypopupWindow.showAsDropDown(v,-153,0);  
           //showAsDropDown(below which view you want to show as dropdown,horizontal position, vertical position)  
         }  
       }  
     });  
   }  
   private void setPopUpWindow() {  
     LayoutInflater inflater = (LayoutInflater)  
         getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
     view = inflater.inflate(R.layout.popup, null);  

     Start=(RelativeLayout)view.findViewById(R.id.start_btn);  
     Pause=(RelativeLayout)view.findViewById(R.id.pause_btn);  
     Stop=(RelativeLayout)view.findViewById(R.id.stop_btn);

  mypopupWindow = new PopupWindow(view,300, RelativeLayout.LayoutParams.WRAP_CONTENT, true);

popup Layout

<?xml version="1.0" encoding="utf-8"?>  
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   android:orientation="vertical" android:layout_width="wrap_content"  
   android:background="@drawable/whitedrawable"  
   android:paddingRight="0dp"  
   android:layout_marginRight="0dp"  
   android:layout_height="wrap_content">  
   <RelativeLayout  
     android:id="@+id/btn1"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content">  
     <ImageView  
       android:layout_centerHorizontal="true"  
       android:layout_centerVertical="true"  
       android:layout_alignParentLeft="true"  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"  
       android:src="@drawable/startimg"  
       android:id="@+id/startimg"  
       android:paddingLeft="10dp"  
       android:paddingRight="10dp"  
       android:paddingTop="5dp"  
       android:paddingBottom="5dp"  
       />  
     <TextView  
       android:layout_centerHorizontal="true"  
       android:layout_centerVertical="true"  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"  
       android:paddingRight="0dp"  
       android:text="Start"  
       android:layout_toRightOf="@+id/startimg"  
       />  
 <!-- Continue for other items-->

The whitedrawable can be used to set a background of your choice. You can use 9patch to get the shadow and rounded corners for the background.

To dismiss the popupWindow, use the following code:

mypopupWindow.getContentView().setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mypopupWindow.dismiss();
    }
});

To dismiss using the back button, use:

@Override
public void onBackPressed() {
    if(mypopupWindow.isShowing()) {
        mypopupWindow.dismiss();
        return;
    }
    super.onBackPressed();
}

Upvotes: 47

Related Questions