zawadz88/MaterialPopupMenu

Multilevel menu

d3bt3ch opened this issue · 14 comments

Does the library supports multilevel menu ?

Hi @debjitk,
The library dies not support this currently. It would be a very nice feature though!

We really need this

Hi @jrcacd, could you describe your use case, please? How should it look like, what devices are you targeting etc.?
I've just had a look at the latest Material Design guidelines (https://material.io/design/components/menus.html#dropdown-menu) and cascading menus are actually marked as Desktop only.
Personally, I'm not sure if there's simply enough space to put it on phones (maybe just on tablets).

Hi @zawadz88,

Multilevel menu doesn't mean a Cascading menu.
It means the same behavior of standard contextmenu: menu items with a submenu have an arrow. Clicking on the item itself shows the submenu and hides the main menu.
Main menu and submenu are not visible at the same time.

Regards

Hi @marbat87,
I don't see it in the spec so I'm not sure how this should behave (animations, anchors, etc.).
However, what you're describing should be possible by e.g. using a custom item in the top level menu so that it has the arrow at the end. When this item gets clicked you could simply open a new menu.

Wouldn't that do the trick?

@zawadz88 Yes it should work. I just thought is was easy to implement as standard contextmenu manages it yet.

Thanks

Ah, right. I understand now what you had in mind. I'll try to have a look - shouldn't be too hard.
I thought the issue was about something else from start...
Thanks for clarification

You don't need a custom item actually.
I've modified one of the samples to achieve this:
multi-level

Code:

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (item.itemId == R.id.overflow) {
            val anchor = checkNotNull<View>(findViewById(R.id.overflow))
            val popupMenu = popupMenu {
                style = R.style.Widget_MPM_Menu //optional, light is the default
                dropdownGravity = Gravity.END
                section {
                    title = "Editing"
                    item {
                        label = "Copy"
                        icon = R.drawable.abc_ic_menu_copy_mtrl_am_alpha
                        callback = {
                            Toast.makeText(this@LightActivity, "Copied!", Toast.LENGTH_SHORT).show()
                        }
                    }
                    item {
                        label = "Paste"
                        iconDrawable = ContextCompat.getDrawable(this@LightActivity, R.drawable.abc_ic_menu_paste_mtrl_am_alpha)
                    }
                }
                section {
                    item {
                        label = "Share me please"
                        callback = {
                            shareUrl()
                        }
                    }
                    item {
                        label = "Multi-level"
                        callback = {
                            val nestedPopupMenu = popupMenu {
                                style = R.style.Widget_MPM_Menu //optional, light is the default
                                dropdownGravity = Gravity.END
                                section {
                                    title = "Second level"
                                    item {
                                        label = "Copy"
                                    }
                                    item {
                                        label = "Paste"
                                    }
                                }
                            }

                            nestedPopupMenu.show(this@LightActivity, anchor)
                        }
                    }
                }
            }

            popupMenu.show(this@LightActivity, anchor)
            return true
        }
        return false
    }

@debjitk @jrcacd @marbat87 Is that what you guys had in mind?

That's the wanted behavior, but actually items with a submenu show like the image below in the standard contextmenu (screenshot taken from Android 8.1).
We can achieve that only with a custom object in MaterialPopupMenu.

image

Hi @marbat87 ,
Could you post the code you used for creating this with a standard context menu?
Anyway, I'll try provide an example of how to do that in the sample app.

Regarding ContextMenus, this can look like this:
context menu
which can be achieve by adding in Activity:

    override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
        super.onCreateContextMenu(menu, v, menuInfo)
        menu.setHeaderTitle("Context Menu")
        menu.add(0, v.id, 0, "Upload")
        menu.add(0, v.id, 0, "Search")
        menu.add(0, v.id, 0, "Share")
        menu.add(0, v.id, 0, "Bookmark")
        val subMenu = menu.addSubMenu("Submenu")
        subMenu.setHeaderTitle("title")
        subMenu.add(0, v.id, 0, "Nested1")
        subMenu.add(0, v.id, 0, "Nested2")
        subMenu.add(0, v.id, 0, "Nested3")
    }

and somewhere in onCreate:

registerForContextMenu(clickedView)

Released in 3.4.0

Can we create like this?

popupMenu {
            section {
                title = R.string...
                item {
                    label = R.string...
                    icon = R.drawable...
                    iconColor = ...
                    callback = { }
                }

                item {
                    label = R.string...
                    icon = R.drawable...
                    iconColor = ...
                    callback = { )
                    }
                }
            }


            
            submenu {   //<---------------------------
                title = R.string...
                item {
                    label = R.string...
                    icon = R.drawable...
                    iconColor = ...
                    callback = { }
                }

                item {
                    label = R.string...
                    icon = R.drawable...
                    iconColor = ...
                    callback = { }
                }
            }

           section {
                title = R.string...
                item {
                    label = R.string...
                    icon = R.drawable...
                    iconColor = ...
                    callback = { }
                }

                item {
                    label = R.string...
                    icon = R.drawable...
                    iconColor = ...
                    callback = { )
                    }
                }
            }

}

Hi @jrcacd,
Not in 3.4.0. There's an example in the sample app of how to do this in a different way.
Regarding the DSL proposition - I'm not sure if putting submenu on the same level as section is a good idea. It should probably be under section or item.
There's also one more issue I see with having submenus supported this way. popupMenu returns a menu object on which we call show with Context and an anchor View. We can also use it to dismiss that menu. The submenu is actually a different menu so I'm not sure how to tackle this.

I'm open to suggestions and PRs regarding this. However, since basic submenu support is already added in 3.4.0 I'd suggest moving any DSL enhancements to a separate issue.