在 Android BottomNavigationView 中设置所选项目
Set selected item in Android BottomNavigationView
我正在使用支持库中的新 android.support.design.widget.BottomNavigationView
。
如何从代码中设置当前选择?我意识到,旋转屏幕后,选择变回了第一项。当然,如果有人能告诉我,如何在 onPause
函数中 "save" BottomNavigationView
的当前状态以及如何在 onResume
中恢复它,当然也会有所帮助。
谢谢!
这可能会在未来的更新中添加。但与此同时,您可以使用反射来完成此操作。
创建一个从 BottomNavigationView 扩展的自定义视图并访问它的一些字段。
public class SelectableBottomNavigationView extends BottomNavigationView {
public SelectableBottomNavigationView(Context context) {
super(context);
}
public SelectableBottomNavigationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SelectableBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setSelected(int index) {
try {
Field f = BottomNavigationView.class.getDeclaredField("mMenuView");
f.setAccessible(true);
BottomNavigationMenuView menuView = (BottomNavigationMenuView) f.get(this);
try {
Method method = menuView.getClass().getDeclaredMethod("activateNewButton", Integer.TYPE);
method.setAccessible(true);
method.invoke(menuView, index);
} catch (SecurityException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
然后在您的 xml 布局文件中使用它。
<com.your.app.SelectableBottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemBackground="@color/primary"
app:itemIconTint="@drawable/nav_item_color_state"
app:itemTextColor="@drawable/nav_item_color_state"
app:menu="@menu/bottom_navigation_menu"/>
我不想修改你的代码。
如果是这样,我建议你试试BottomNavigationViewEx。
你只需要替换调用方法setCurrentItem(index);
和getCurrentItem()
。
反射不是个好主意。
前往此 gist。有一个方法执行选择但也调用回调:
@CallSuper
public void setSelectedItem(int position) {
if (position >= getMenu().size() || position < 0) return;
View menuItemView = getMenuItemView(position);
if (menuItemView == null) return;
MenuItemImpl itemData = ((MenuView.ItemView) menuItemView).getItemData();
itemData.setChecked(true);
boolean previousHapticFeedbackEnabled = menuItemView.isHapticFeedbackEnabled();
menuItemView.setSoundEffectsEnabled(false);
menuItemView.setHapticFeedbackEnabled(false); //avoid hearing click sounds, disable haptic and restore settings later of that view
menuItemView.performClick();
menuItemView.setHapticFeedbackEnabled(previousHapticFeedbackEnabled);
menuItemView.setSoundEffectsEnabled(true);
mLastSelection = position;
}
只是添加了另一种方式来以编程方式执行选择 - 这可能是最初的意图,也可能是后来添加的。
Menu bottomNavigationMenu = myBottomNavigationMenu.getMenu();
bottomNavigationMenu.performIdentifierAction(selected_menu_item_id, 0);
performIdentifierAction
需要一个 Menu
项目 ID 和一个标志。
有关详细信息,请参阅 documentation。
对于仍在使用 SupportLibrary < 25.3.0 的用户
我不确定这是否是这个问题的完整答案,但我的问题非常相似 - 我必须处理 back
按钮按下并将用户带到他所在的上一个选项卡。所以,也许我的解决方案对某些人有用:
private void updateNavigationBarState(int actionId){
Menu menu = bottomNavigationView.getMenu();
for (int i = 0, size = menu.size(); i < size; i++) {
MenuItem item = menu.getItem(i);
item.setChecked(item.getItemId() == actionId);
}
}
请记住,如果用户按其他导航选项卡 BottomNavigationView
不会清除当前选择的项目,因此您需要在导航操作处理后在 onNavigationItemSelected
中调用此方法:
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.some_id_1:
// process action
break;
case R.id.some_id_2:
// process action
break;
...
default:
return false;
}
updateNavigationBarState(item.getItemId());
return true;
}
关于实例状态的保存,我认为您可以使用相同的 action id
导航视图并找到合适的解决方案。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bottomNavigationView.setOnNavigationItemSelectedListener(this);
Menu menu = bottomNavigationView.getMenu();
this.onNavigationItemSelected(menu.findItem(R.id.action_favorites));
}
似乎已在 SupportLibrary 25.1.0 中修复:)
编辑:似乎已修复,旋转屏幕时选择的状态被保存。
private void setSelectedItem(int actionId) {
Menu menu = viewBottom.getMenu();
for (int i = 0, size = menu.size(); i < size; i++) {
MenuItem menuItem = menu.getItem(i);
((MenuItemImpl) menuItem).setExclusiveCheckable(false);
menuItem.setChecked(menuItem.getItemId() == actionId);
((MenuItemImpl) menuItem).setExclusiveCheckable(true);
}
}
唯一的 'minus' 解决方案是使用 MenuItemImpl
,即 'internal' 到库(尽管 public)。
要以编程方式单击您需要使用的 BottomNavigationBar 项目:
View view = bottomNavigationView.findViewById(R.id.menu_action_item);
view.performClick();
这会正确排列所有带有标签的项目。
我向 Google 提出了一个错误,因为没有可靠的方法 select BottomNavigationView 上的页面:https://code.google.com/p/android/issues/detail?id=233697
NavigationView 显然有类似的问题,他们通过添加新的 setCheckedItem() 方法解决了这个问题。
从 25.3.0 版本开始可以调用 setSelectedItemId()
\o/
从 API 25.3.0 开始,引入了方法 setSelectedItemId(int id)
,让您可以将项目标记为选中状态,就像它被点击一样。
来自文档:
Set the selected menu item ID. This behaves the same as tapping on an item.
代码示例:
BottomNavigationView bottomNavigationView;
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(myNavigationItemListener);
bottomNavigationView.setSelectedItemId(R.id.my_menu_item_id);
重要
您必须已经将所有项目添加到菜单中(以防您以编程方式执行此操作)并在调用 setSelectedItemId 之前设置监听器(我相信您需要监听器中的代码到 运行 当你调用这个方法时)。如果您在添加菜单项和设置侦听器之前调用 setSelectedItemId,则不会发生任何事情。
超过API 25你可以使用setSelectedItemId(menu_item_id)
但在 API 25 下你必须做不同的事情,
用户菜单获取句柄然后设置检查到检查特定项目
将 android:enabled="true"
添加到 BottomNavigationMenu 项。
然后设置bottomNavigationView.setOnNavigationItemSelectedListener(mListener)
和
通过 bottomNavigationView.selectedItemId = R.id.your_menu_id
将其设置为选中状态
你可以试试performClick方法:
View view = bottomNavigationView.findViewById(R.id.YOUR_ACTION);
view.performClick();
编辑
从 API 25.3.0 开始,引入了方法 setSelectedItemId(int id)
,让您可以将项目标记为已选中,就像它被点击一样。
bottomNavigationView.setSelectedItemId(R.id.action_item1);
其中 action_item1
是菜单项 ID。
如果您需要动态传递片段参数,请执行此操作
这里有很多(大部分是重复的或过时的)答案,但 none 解决了一个非常普遍的需求:将不同的参数动态传递给加载到选项卡中的片段.
您不能使用 setSelectedItemId(R.id.second_tab)
将不同的参数动态传递给加载的 Fragment,这最终会调用静态 OnNavigationItemSelectedListener
。为了克服这个限制,我最终在包含选项卡的 MainActivity
中执行了此操作:
fun loadArticleTab(articleId: String) {
bottomNavigationView.menu.findItem(R.id.tab_article).isChecked = true // use setChecked() in Java
supportFragmentManager
.beginTransaction()
.replace(R.id.main_fragment_container, ArticleFragment.newInstance(articleId))
.commit()
}
ArticleFragment.newInstance()
方法照常实现:
private const val ARG_ARTICLE_ID = "ARG_ARTICLE_ID"
class ArticleFragment : Fragment() {
companion object {
/**
* @return An [ArticleFragment] that shows the article with the given ID.
*/
fun newInstance(articleId: String): ArticleFragment {
val args = Bundle()
args.putString(ARG_ARTICLE_ID, day)
val fragment = ArticleFragment()
fragment.arguments = args
return fragment
}
}
}
使用
bottomNavigationView.getMenu().getItem(POSITION).setChecked(true);
希望对您有所帮助
//Setting default selected menu item and fragment
bottomNavigationView.setSelectedItemId(R.id.action_home);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new HomeFragment()).commit();
更多的是确定与对应的底部导航菜单项同时加载的默认片段。
您可以在 OnResume 回调中包含相同的内容
使用它通过菜单 id 设置选定的底部导航菜单项
MenuItem item = mBottomNavView.getMenu().findItem(menu_id);
item.setChecked(true);
这个方法对我有用。
private fun selectBottomNavigationViewMenuItem(bottomNavigationView : BottomNavigationView,@IdRes menuItemId: Int) {
bottomNavigationView.setOnNavigationItemSelectedListener(null)
bottomNavigationView.selectedItemId = menuItemId
bottomNavigationView.setOnNavigationItemSelectedListener(this)
}
Example
override fun onBackPressed() {
replaceFragment(HomeFragment())
selectBottomNavigationViewMenuItem(navView, R.id.navigation_home)
}
private fun replaceFragment(fragment: Fragment) {
val transaction: FragmentTransaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.frame_container, fragment)
transaction.commit()
}
navigationView.getMenu().findItem(R.id.navigation_id).setChecked(true);
要更改选项卡,此代码有效!
activity?.supportFragmentManager?.beginTransaction().also { fragmentTransaction ->
fragmentTransaction?.replace(R.id.base_frame, YourFragment())?.commit()
}
val bottomNavigationView: BottomNavigationView = activity?.findViewById(R.id.bottomNavigationView) as BottomNavigationView
bottomNavigationView.menu.findItem(R.id.navigation_item).isChecked = true
我正在使用支持库中的新 android.support.design.widget.BottomNavigationView
。
如何从代码中设置当前选择?我意识到,旋转屏幕后,选择变回了第一项。当然,如果有人能告诉我,如何在 onPause
函数中 "save" BottomNavigationView
的当前状态以及如何在 onResume
中恢复它,当然也会有所帮助。
谢谢!
这可能会在未来的更新中添加。但与此同时,您可以使用反射来完成此操作。
创建一个从 BottomNavigationView 扩展的自定义视图并访问它的一些字段。
public class SelectableBottomNavigationView extends BottomNavigationView {
public SelectableBottomNavigationView(Context context) {
super(context);
}
public SelectableBottomNavigationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SelectableBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setSelected(int index) {
try {
Field f = BottomNavigationView.class.getDeclaredField("mMenuView");
f.setAccessible(true);
BottomNavigationMenuView menuView = (BottomNavigationMenuView) f.get(this);
try {
Method method = menuView.getClass().getDeclaredMethod("activateNewButton", Integer.TYPE);
method.setAccessible(true);
method.invoke(menuView, index);
} catch (SecurityException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
然后在您的 xml 布局文件中使用它。
<com.your.app.SelectableBottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemBackground="@color/primary"
app:itemIconTint="@drawable/nav_item_color_state"
app:itemTextColor="@drawable/nav_item_color_state"
app:menu="@menu/bottom_navigation_menu"/>
我不想修改你的代码。 如果是这样,我建议你试试BottomNavigationViewEx。
你只需要替换调用方法setCurrentItem(index);
和getCurrentItem()
。
反射不是个好主意。
前往此 gist。有一个方法执行选择但也调用回调:
@CallSuper
public void setSelectedItem(int position) {
if (position >= getMenu().size() || position < 0) return;
View menuItemView = getMenuItemView(position);
if (menuItemView == null) return;
MenuItemImpl itemData = ((MenuView.ItemView) menuItemView).getItemData();
itemData.setChecked(true);
boolean previousHapticFeedbackEnabled = menuItemView.isHapticFeedbackEnabled();
menuItemView.setSoundEffectsEnabled(false);
menuItemView.setHapticFeedbackEnabled(false); //avoid hearing click sounds, disable haptic and restore settings later of that view
menuItemView.performClick();
menuItemView.setHapticFeedbackEnabled(previousHapticFeedbackEnabled);
menuItemView.setSoundEffectsEnabled(true);
mLastSelection = position;
}
只是添加了另一种方式来以编程方式执行选择 - 这可能是最初的意图,也可能是后来添加的。
Menu bottomNavigationMenu = myBottomNavigationMenu.getMenu();
bottomNavigationMenu.performIdentifierAction(selected_menu_item_id, 0);
performIdentifierAction
需要一个 Menu
项目 ID 和一个标志。
有关详细信息,请参阅 documentation。
对于仍在使用 SupportLibrary < 25.3.0 的用户
我不确定这是否是这个问题的完整答案,但我的问题非常相似 - 我必须处理 back
按钮按下并将用户带到他所在的上一个选项卡。所以,也许我的解决方案对某些人有用:
private void updateNavigationBarState(int actionId){
Menu menu = bottomNavigationView.getMenu();
for (int i = 0, size = menu.size(); i < size; i++) {
MenuItem item = menu.getItem(i);
item.setChecked(item.getItemId() == actionId);
}
}
请记住,如果用户按其他导航选项卡 BottomNavigationView
不会清除当前选择的项目,因此您需要在导航操作处理后在 onNavigationItemSelected
中调用此方法:
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.some_id_1:
// process action
break;
case R.id.some_id_2:
// process action
break;
...
default:
return false;
}
updateNavigationBarState(item.getItemId());
return true;
}
关于实例状态的保存,我认为您可以使用相同的 action id
导航视图并找到合适的解决方案。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bottomNavigationView.setOnNavigationItemSelectedListener(this);
Menu menu = bottomNavigationView.getMenu();
this.onNavigationItemSelected(menu.findItem(R.id.action_favorites));
}
似乎已在 SupportLibrary 25.1.0 中修复:) 编辑:似乎已修复,旋转屏幕时选择的状态被保存。
private void setSelectedItem(int actionId) {
Menu menu = viewBottom.getMenu();
for (int i = 0, size = menu.size(); i < size; i++) {
MenuItem menuItem = menu.getItem(i);
((MenuItemImpl) menuItem).setExclusiveCheckable(false);
menuItem.setChecked(menuItem.getItemId() == actionId);
((MenuItemImpl) menuItem).setExclusiveCheckable(true);
}
}
唯一的 'minus' 解决方案是使用 MenuItemImpl
,即 'internal' 到库(尽管 public)。
要以编程方式单击您需要使用的 BottomNavigationBar 项目:
View view = bottomNavigationView.findViewById(R.id.menu_action_item);
view.performClick();
这会正确排列所有带有标签的项目。
我向 Google 提出了一个错误,因为没有可靠的方法 select BottomNavigationView 上的页面:https://code.google.com/p/android/issues/detail?id=233697
NavigationView 显然有类似的问题,他们通过添加新的 setCheckedItem() 方法解决了这个问题。
从 25.3.0 版本开始可以调用 setSelectedItemId()
\o/
从 API 25.3.0 开始,引入了方法 setSelectedItemId(int id)
,让您可以将项目标记为选中状态,就像它被点击一样。
来自文档:
Set the selected menu item ID. This behaves the same as tapping on an item.
代码示例:
BottomNavigationView bottomNavigationView;
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(myNavigationItemListener);
bottomNavigationView.setSelectedItemId(R.id.my_menu_item_id);
重要
您必须已经将所有项目添加到菜单中(以防您以编程方式执行此操作)并在调用 setSelectedItemId 之前设置监听器(我相信您需要监听器中的代码到 运行 当你调用这个方法时)。如果您在添加菜单项和设置侦听器之前调用 setSelectedItemId,则不会发生任何事情。
超过API 25你可以使用setSelectedItemId(menu_item_id) 但在 API 25 下你必须做不同的事情, 用户菜单获取句柄然后设置检查到检查特定项目
将 android:enabled="true"
添加到 BottomNavigationMenu 项。
然后设置bottomNavigationView.setOnNavigationItemSelectedListener(mListener)
和
通过 bottomNavigationView.selectedItemId = R.id.your_menu_id
你可以试试performClick方法:
View view = bottomNavigationView.findViewById(R.id.YOUR_ACTION);
view.performClick();
编辑
从 API 25.3.0 开始,引入了方法 setSelectedItemId(int id)
,让您可以将项目标记为已选中,就像它被点击一样。
bottomNavigationView.setSelectedItemId(R.id.action_item1);
其中 action_item1
是菜单项 ID。
如果您需要动态传递片段参数,请执行此操作
这里有很多(大部分是重复的或过时的)答案,但 none 解决了一个非常普遍的需求:将不同的参数动态传递给加载到选项卡中的片段.
您不能使用 setSelectedItemId(R.id.second_tab)
将不同的参数动态传递给加载的 Fragment,这最终会调用静态 OnNavigationItemSelectedListener
。为了克服这个限制,我最终在包含选项卡的 MainActivity
中执行了此操作:
fun loadArticleTab(articleId: String) {
bottomNavigationView.menu.findItem(R.id.tab_article).isChecked = true // use setChecked() in Java
supportFragmentManager
.beginTransaction()
.replace(R.id.main_fragment_container, ArticleFragment.newInstance(articleId))
.commit()
}
ArticleFragment.newInstance()
方法照常实现:
private const val ARG_ARTICLE_ID = "ARG_ARTICLE_ID"
class ArticleFragment : Fragment() {
companion object {
/**
* @return An [ArticleFragment] that shows the article with the given ID.
*/
fun newInstance(articleId: String): ArticleFragment {
val args = Bundle()
args.putString(ARG_ARTICLE_ID, day)
val fragment = ArticleFragment()
fragment.arguments = args
return fragment
}
}
}
使用
bottomNavigationView.getMenu().getItem(POSITION).setChecked(true);
希望对您有所帮助
//Setting default selected menu item and fragment
bottomNavigationView.setSelectedItemId(R.id.action_home);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new HomeFragment()).commit();
更多的是确定与对应的底部导航菜单项同时加载的默认片段。 您可以在 OnResume 回调中包含相同的内容
使用它通过菜单 id 设置选定的底部导航菜单项
MenuItem item = mBottomNavView.getMenu().findItem(menu_id);
item.setChecked(true);
这个方法对我有用。
private fun selectBottomNavigationViewMenuItem(bottomNavigationView : BottomNavigationView,@IdRes menuItemId: Int) {
bottomNavigationView.setOnNavigationItemSelectedListener(null)
bottomNavigationView.selectedItemId = menuItemId
bottomNavigationView.setOnNavigationItemSelectedListener(this)
}
Example
override fun onBackPressed() {
replaceFragment(HomeFragment())
selectBottomNavigationViewMenuItem(navView, R.id.navigation_home)
}
private fun replaceFragment(fragment: Fragment) {
val transaction: FragmentTransaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.frame_container, fragment)
transaction.commit()
}
navigationView.getMenu().findItem(R.id.navigation_id).setChecked(true);
要更改选项卡,此代码有效!
activity?.supportFragmentManager?.beginTransaction().also { fragmentTransaction ->
fragmentTransaction?.replace(R.id.base_frame, YourFragment())?.commit()
}
val bottomNavigationView: BottomNavigationView = activity?.findViewById(R.id.bottomNavigationView) as BottomNavigationView
bottomNavigationView.menu.findItem(R.id.navigation_item).isChecked = true