Popup Menu in custom ListView
Asked Answered
C

8

12

What I want to achieve:

I have a custom ListView adapter. To each Listitem I want to add a popup menu, pretty similar to the ListView in the current Google Play application.

Screenshot of Google Play items

This is what I tried: Most of my code comes from this Android sample samples\android-19\ui\ActionBarCompat-ListPopupMenu

CustomFragmentPageAdapter.java:

// create new fragment
mCustomFragment = CustomFragment.newInstance(position);

CustomFragment.java

public class CustomFragment extends ListFragment implements View.OnClickListener{

...

@Override
public void onClick(final View v) {
    v.post(new Runnable() {
        @Override
        public void run() {
            showPopupMenu(v);
        }
    });
}

private void showPopupMenu(View view) {

    PopupMenu popup = new PopupMenu(getActivity(), view);

    popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu());

    popup.show();
}

CustomArrayAdapter:

public class CustomAdapter extends ArrayAdapter<WatchListPlayerItem> {
    ...    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final int pos = position;

        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        final View rowView = inflater.inflate(R.layout.watch_list_row, parent, false);

        View popupButton = rowView.findViewById(R.id.imgPopUp);

        popupButton.setTag(getItem(position));

        popupButton.setOnClickListener(mFragment);

        return rowView;
    }
}

popup_menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/install"
        android:title="Install" />
    <item
        android:id="@+id/addtowishlist"
        android:title="Add to wishlist" />
</menu>

Logcat output:

java.lang.RuntimeException: Failed to resolve attribute at index 6
            at android.content.res.TypedArray.getLayoutDimension(TypedArray.java:603)
            at android.view.ViewGroup$LayoutParams.setBaseAttributes(ViewGroup.java:6423)
            at android.view.ViewGroup$MarginLayoutParams.<init>(ViewGroup.java:6591)
            at android.widget.FrameLayout$LayoutParams.<init>(FrameLayout.java:735)
...

The error is thrown at popup.show() in my CustomFragment.

This error is clearly driving me crazy and ANY help to solve this issue is highly appreciated!

Cantabrigian answered 5/1, 2015 at 15:41 Comment(1)
#36713324Sweated
C
39

I finally found the solution to my problem, eventhough I have no explanation why this solution works.

With the following import I always had the error:

import android.support.v7.widget.PopupMenu;

It works fine with the following import:

import android.widget.PopupMenu;

I tested the code provided by Ric (Thanks for the great help!) and my own. Both are working now. Maybe someone has an explanation why the import matters in this case.

Cantabrigian answered 7/1, 2015 at 18:59 Comment(0)
U
6

First create a button in your custom-item-listview.xml and then add the code below:

Button:

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_text"
android:id="@+id/button1"
... />

class:

public class CustomAdapter extends ArrayAdapter<CustomItem> {

    private static Activity context = null;
    private final ArrayList<CustomItem> mItemsArrayList;
    private CustomFragment mFragment;


    public CustomAdapter(Activity context, ArrayList<CustomItem> itemsArrayList, CustomFragment fragment) {

        super(context, R.layout.watch_list_row, itemsArrayList);

        CustomAdapter.context = context;
        this.mItemsArrayList = itemsArrayList;
        this.mFragment = fragment;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final int pos = position;
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        final View rowView = inflater.inflate(R.layout.watch_list_row, parent, false);
    final Button popUp_btn = (Button)rowView.findViewById(R.id.button1);
    popUp_btn.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            final PopupMenu popup = new PopupMenu(context, popUp_btn);
            popup.getMenuInflater().inflate(R.menu.context_menu, popup.getMenu());
            popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                public boolean onMenuItemClick(MenuItem item) {
                    int i = item.getItemId();
                    if (i == R.id.item1) {
                        //do something
                        return true;
                    }
                    else if (i == R.id.item2){
                        //do something
                        return true;
                    }
                    else if (i == R.id.item3) {
                        //do something
                        return true;
                    }
                    else {
                        return onMenuItemClick(item);
                    }
                }
            });

            popup.show();

EDIT: This works well for me:

TAB1

public  class TAB1 extends Fragment {
View view;

public TAB1() {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.tab1, null);


            ListView list = (ListView) view.findViewById(android.R.id.list);
            CustomList adapter = new CustomList(getActivity());
            adapter.addAll();
            list.setAdapter(adapter);


    return view;
}

CustomList:

public class CustomList extends ArrayAdapter<YourArrayAdapter> {

private static Activity context = null;

public CustomList(Activity context) {
    super(context, R.layout.custom_listview, web);
    CustomList.context = context;
}
@Override
public View getView(final int position, View view, ViewGroup parent) {
    LayoutInflater inflater = context.getLayoutInflater();
    final View rowView = inflater.inflate(R.layout.custom_listview, null, true);

    //your stuff here

    final Button popUp_btn = (Button)rowView.findViewById(R.id.button1);
    popUp_btn.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            final PopupMenu popup = new PopupMenu(context, popUp_btn);
            popup.getMenuInflater().inflate(R.menu.context_menu, popup.getMenu());
            popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                public boolean onMenuItemClick(MenuItem item) {
                    int i = item.getItemId();
                    if (i == R.id.item1) {
                        //do something
                        return true;
                    }
                    else if (i == R.id.item2){
                        //do something
                        return true;
                    }
                    else if (i == R.id.item3) {
                        //do something
                        return true;
                    }
                    else {
                        return onMenuItemClick(item);
                    }
                }
            });

            popup.show();

        }
    });

    return rowView;

}
Uncircumcision answered 5/1, 2015 at 16:49 Comment(8)
Unfortunately this gives me the same error, again at popup.show();Cantabrigian
I have already tried with context instead of getActivity(). Is there any other major edit that I am not seeing?Cantabrigian
Can you post your entire CustomAdapter class?Uncircumcision
Tested it and got the same error again. Note that the Adapter is used within a Fragment, not an Activity. I know that I can get the Activity using getActivity() in the Fragment, but maybe this is the main issue?Cantabrigian
CustomFragment should extend Fragment in wich you create the CustomAdapterUncircumcision
Well it extends ListFragment, is there any significant difference?Cantabrigian
I extended to Fragment in which I created my custom ListView. Then I created the class for my listview and where I have the code above and everything works fineUncircumcision
Can you maybe post a full working example? I extended to Fragment now (instead of ListFragment) and I still get the same error.Cantabrigian
S
3

use this as(activity context)not application context or context

     PopupMenu popup = new PopupMenu(this, v);
Smiga answered 14/6, 2016 at 10:17 Comment(0)
P
2
    popup = (Button)findViewById(R.id.button);

    popup.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            PopupMenu popup = new PopupMenu(MainActivity.this,view);
            popup.getMenuInflater().inflate(R.menu.popup_menu,popup.getMenu());
            popup.show();
            popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    int id = item.getItemId();
                    if(id==R.id.install){
                        show_toast("Install Clicked");
                    }else{
                        show_toast("WishList Clicked");                            
                    }
                    return true;
                }
            });
        }
    });



    public void show_toast(String message){
        Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
    }

Note:
Don't forgot to import this....

import android.support.v7.widget.PopupMenu;
import android.view.MenuItem;
Par answered 29/9, 2016 at 10:1 Comment(0)
P
2

Rick's code of lines works perfect as long as you import the following:

import android.widget.PopupMenu;

Not the one below:

import android.support.v7.widget.PopupMenu;
Placeeda answered 9/3, 2017 at 15:22 Comment(0)
C
1

I've just had the same issue when I modified the theme parent style: from

<style name="MainAppTheme" parent="@style/Theme.AppCompat.Light">

to

<style name="MainAppTheme" parent="@style/Theme.Base.AppCompat.Light">

Maybe your app uses the Theme.Base style, which does not define the required 6th parameter used by PopupMenu. From SO question How to use ActionBarActivity with Theme.Material, Theme.AppCompat extends Theme.Base.AppCompat

Cornea answered 7/1, 2015 at 11:2 Comment(1)
I'm using Theme.Holo.Light.DarkActionBar, I don't think that this is the problem in my case. Also, I found another solution to my problem, please see the answer that I have posted.Cantabrigian
T
0

I fixed a similar error just by passing as parameter a static activity. For example:

static AppCompatActivity sActivity;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    sActivity = this;

yourLayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        PopupMenu popup = new PopupMenu(sActivity, v);
        MenuInflater inflater = popup.getMenuInflater();
        inflater.inflate(R.menu.my_popup_menu, popup.getMenu());
        popup.show();
        }
   });
}

Also, you problem might be this one: Issue 152141

Hopefully it will help you, respecting the android.support.v7.widget.PopupMenu import.

Regards.

Tbilisi answered 9/6, 2016 at 10:23 Comment(0)
A
0

Firstly required to import
import android.widget.PopupMenu;

And your it must be look like this

holder.dayDate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PopupMenu popupMenu = new PopupMenu(context, holder.dayDate);
                popupMenu.getMenu().add("Futa");
                popupMenu.getMenu().add("Acha");
                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem item) {
                        switch (item.getTitle().toString()) {
                            case "View" :
                                Toast.makeText(context, "Bidhaa imefutwa.", Toast.LENGTH_SHORT).show();
                                break;
                            case "Edit":
//                                popupMenu.dismiss();
                                break;
                        }
                        return false;
                    }
                });
                popupMenu.show();
            }
        });

    }
Alecalecia answered 18/1, 2022 at 8:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.