Search code examples
javaandroidpopupmenu

PopupMenu sometimes does not show on screen


I have a View which is contained in a Fragment. The View contains a number of "buttons" (Each "Button is an ImageView)(see screen 1) Screen 1

My objective is that when I click on one of these buttons a PopupMenu will appear (see screen 2) Screen 2

This is working well most of the time but on some "buttons", when the "button" is clicked, the PopupMenu does not usually show (although the toast message does appear indicating that the 'cick' has been registered).

The issue is apparent on the "button" in the top left corner and on buttons at the bottom of the fragment. Sometimes the menu appears (but usually after many 'clicks')

My working assumption is that, for some reason, the menu is not being displayed on the screen (I believe it is being displayed but is 'off screen'/not visible).

I have researched the issue but cannot find anyone with a similar issue.

I have tried different Gravity settings when creating the PopupMenu, but nothing made a difference.

The code I am using to create the PopupMenu appears to be classical.

Thanks in advance for any help you can offer me on this.

Extract from RemoteView.java

// Constructors
public RemoteView(Context context) {
    super(context);
    init(context);
}

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

public RemoteView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
}

private void init(Context context) {
    rootview = inflate(context, R.layout.remote, this);

}
public class IconViewOnTouchListener implements View.OnTouchListener {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (!edit) {
                        actionDOWN(v);
                    }
                    break;

                case MotionEvent.ACTION_UP:
                    KeyMap keyMap=(KeyMap) v.getTag();
                    if (edit) {
                        if (movingButton) {
                            toIndex=keyMap.AMKeyItem;
                            toKey=keyMap.keyIndex;
                            exchangeButtons();
                        } else {
                            //popup edit options
                            if (keyMap.AMKeyItem  >= 0) showPopup(v);
                        }
                    } else {
                       actionUP(v);
                        performClick();
                    }
                    break;
            }
            return true;
        }
    }

private void showPopup(final View view) {
        //Creating the instance of PopupMenu
        PopupMenu popup = new PopupMenu(context, view, Gravity.RIGHT, R.attr.actionOverflowMenuStyle, 0);
        //Inflating the Popup using xml file
        popup.getMenuInflater()
                .inflate(R.menu.edit_button_menu, popup.getMenu());
        Toast.makeText(context, "Popup Menu is visible",
                Toast.LENGTH_SHORT).show();
        popup.show(); //showing popup menu
    }

remote.xml

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent">
        <com.andy.andymote.CommunicatorView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/remote_communicator">
        </com.andy.andymote.CommunicatorView>

        <GridView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/buttons"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:numColumns="5"
            android:gravity="center"
            android:stretchMode="spacingWidthUniform"
            >
        </GridView>
    </RelativeLayout>
</merge>

frag_device.xml

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

    <com.andy.andymote.RemoteView
        android:layout_width="match_parent"
        android:layout_height="match_parent"

        android:id="@+id/remote">
    </com.andy.andymote.RemoteView>

</LinearLayout>

edit_button_menu.xml

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

    <item
        android:id="@+id/moveButton"
        android:title="Move"/>

    <item
        android:id="@+id/editButton"
        android:title="Edit"/>
    <item
        android:id="@+id/insertRow"
        android:title="Insert Row Above"/>

</menu>

Extract from DeviceACTIVITY.java

    private void loadFragment(){
        device = new DeviceFRAGMENT();
        device.setDevice(GLOBALS.deviceList.getDevice(deviceName));
        getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
                device).commit();
    }

Extract from DeviceFRAGMENT.java

    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

            view = inflater.inflate(R.layout.frag_device, container, false);
            //Declare Widgets
            remote = view.findViewById(R.id.remote);
            remote.setKeys(device.getRemote());

        return view;
    }

RemoteKeysAdapter.java

import static com.andy.andymote.GLOBALS.iconSize;

public class RemoteKeysAdapter extends BaseAdapter {

    private final Context mContext;
    private final List<RemoteButton> remoteButtons;
    private _resourceAccess resource;
    private RemoteView.IconViewOnTouchListener iconViewOnTouchListener;
    private Remote remote;

    // 1
    public RemoteKeysAdapter(Context context, Remote remote, List<RemoteButton> remoteButtons,
                             RemoteView.IconViewOnTouchListener iconViewOnTouchListener) {
        this.mContext = context;
        this.remote=remote;
        this.remoteButtons = remoteButtons;
        this.iconViewOnTouchListener=iconViewOnTouchListener;
        resource = new _resourceAccess(context);
    }

    // 2
    @Override
    public int getCount() {
        return remoteButtons.size();
    }

    // 3
    @Override
    public long getItemId(int position) {
        return 0;
    }

    // 4
    @Override
    public Object getItem(int position) {
        return null;
    }

    // 5
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Find the proper remoteButton for this cell by using the position index
        final RemoteButton remoteButton = remoteButtons.get(position);

        if (convertView == null) {
            final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
            convertView = layoutInflater.inflate(R.layout.remote_button, null);
        }

        // create reference for the image in the XML layout file.
        final AppCompatImageView imageView = convertView.findViewById(R.id.button);


        // Set the image
        int indexOfAndyMoteKeyItem=remoteButton.getFromToIndex();
        if (indexOfAndyMoteKeyItem == -1){
            imageView.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_nobutton));
        } else {
            AndyMoteKeyItem andyMoteKeyItem=remote.getRemoteLayout().get(indexOfAndyMoteKeyItem);
            if (andyMoteKeyItem.getLircKeyItem().getIcon().length() == 0) {
                displayText(imageView, andyMoteKeyItem.getLircKeyItem().getText());
            } else {
                displayIcon(imageView, andyMoteKeyItem.getLircKeyItem().getIcon());
            }
        }
        KeyMap keyMap=new KeyMap();
        keyMap.AMKeyItem=indexOfAndyMoteKeyItem;
        keyMap.keyIndex=position;

        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        params.gravity= Gravity.CENTER;
        params.width=iconSize;
        params.height=iconSize;
        convertView.setLayoutParams(params);
        convertView.setOnTouchListener(iconViewOnTouchListener);
        convertView.setPadding(16, 0, 0, 16);
        convertView.setVisibility(remoteButton.getVisibility());

        convertView.setTag(keyMap);
        return convertView;
    }
    private void displayIcon(AppCompatImageView imageView, String icon) {
        clIcon newIcon = factory.createIcon(icon);
        imageView.setImageDrawable(resource.getDrawableFromUri(newIcon.getURI(mContext)));
    }

    private void displayText(AppCompatImageView imageView, String text) {
        //https://github.com/amulyakhare/TextDrawable
        TextDrawable drawable = TextDrawable.builder().beginConfig()
                .textColor(Color.WHITE)
                .bold()
                .withBorder(4)
                .useFont(Typeface.DEFAULT)
                .fontSize(30) /* size in px */
                .endConfig()
                .buildRound(text, Color.DKGRAY);

        imageView.setImageDrawable(drawable);
    }
}

Solution

  • I fixed this by using Droppy instead of PopupMenu. No other magic was required

     private void showPopup(final View view) {
        DroppyMenuPopup.Builder popup = new DroppyMenuPopup.Builder(context, view);
        popup.addMenuItem(new DroppyMenuItem("Move").setId(R.id.moveButton));
        popup.addMenuItem(new DroppyMenuItem("Edit").setId(R.id.editButton));
        popup.addMenuItem(new DroppyMenuItem("Insert Row Above").setId(R.id.insertRow));
        // Set Callback handler
        popup.setOnClick(new DroppyClickCallbackInterface() {
            @Override
            public void call(View v, int id) {
                switch (id) {
                    case R.id.editButton:
                        //code for editButton
                        break;
                    case R.id.moveButton:
                        //code for moveButton
                        break;
                    case R.id.insertRow:
                        //code for insertRow
                        break;
                    default:
                }
            }
        });
    
        DroppyMenuPopup droppyMenu = popup.build();
        droppyMenu.show();
    }