Open clhols opened 5 years ago
Would it be acceptable if BottomNavigationView had these two methods:
/**
* Suspend layout of the {@link Menu} before adding or updating items.
*/
public void suspendMenuUpdates() {
presenter.setUpdateSuspended(true);
}
/**
* Resume layout of the {@link Menu} after adding or updating items.
*/
public void resumeMenuUpdates() {
presenter.setUpdateSuspended(false);
presenter.updateMenuView(true);
}
You can call bottomNavigationView.menu.stopDispatchingItemsChanged() and bottomNavigationView.menu.startDispatchingItemsChanged() to achieve that.
@drchen The Menu interface doesn't have those functions. https://developer.android.com/reference/android/view/Menu
MenuBuilder has them, but like I wrote at the top, BottomNavigationMenu (which is a MenuBuilder) calls startDispatchingItemsChanged in its addInternal function and it triggers the relayout after each item is added.
Ah ok. The method it's a library only one.
We can add a public method to support that then. Reopen the issue.
In case anyone else needs this, our current hacky workaround is:
/**
* Adds items to [BottomNavigationView] without layout after each item.
* https://github.com/material-components/material-components-android/issues/563
*/
@SuppressLint("RestrictedApi")
fun BottomNavigationView.addItems(items: List<BottomNavigationItem>) {
val presenter = getPresenter()
presenter?.setUpdateSuspended(true)
items.forEachIndexed { index, item ->
menu.apply {
add(0, item.menuId, index, item.title).apply {
setIcon(item.icon)
}
}
}
presenter?.setUpdateSuspended(false)
presenter?.updateMenuView(true)
}
fun BottomNavigationView.getPresenter(): BottomNavigationPresenter? {
try {
val field = this.javaClass.getDeclaredField("presenter")
field.isAccessible = true
return field.get(this) as BottomNavigationPresenter
} catch (e: Exception) {
Timber.e(e, "Exception when getting presenter field from BottomNavigationView")
}
return null
}
I want to add menu items to BottomNavigationView in code as their configuration is retrieved from the backend. And that can be done like this:
But when you do that, MenuBuilder.addInternal calls onItemsChanged requesting a relayout after each item is added with is only needed after the last item has been added.
To handle this, MenuBuilder has stopDispatchingItemsChanged.
But BottomNavigationMenu.addInternal prevents this, as it calls startDispatchingItemsChanged internally.