在活动之间使用 BottomNavigationView 按下时如何突出显示项目?

Posted

技术标签:

【中文标题】在活动之间使用 BottomNavigationView 按下时如何突出显示项目?【英文标题】:How to highlight the item when pressed using BottomNavigationView between activities? 【发布时间】:2017-06-04 07:05:25 【问题描述】:

我为我的应用添加了底部导航视图,但我需要活动之间的底部导航视图而不是片段,因此我已将此代码添加到 Java 中以用于我的所有 3 个活动。

当我在手机中选择“第二”或“第三”时,一切都正确,但问题是突出显示第一项。

我需要突出显示我按下的项目。

我已经使用了片段,它工作得很好,但我仍然是使用片段的初学者,所以我正在使用活动。

第一个活动代码是:

BottomNavigationView mBottomNavigation;

    mBottomNavigation =(BottomNavigationView) findViewById(R.id.BottomNavigator);

    mBottomNavigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() 
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) 
            switch (item.getItemId())
                case R.id.Nav_Second:
                    Intent Second= new Intent(First.this, Second.class);
                    startActivity(Second);
                    break;
                case R.id.Nav_Third:
                    Intent Third= new Intent(First.this, Third.class);
                    startActivity(Third);
                    break;
            

            return true;
        
    );



第二个活动是:

BottomNavigationView mBottomNavigation;

    mBottomNavigation =(BottomNavigationView) findViewById(R.id.BottomNavigator);

    mBottomNavigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() 
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) 
            switch (item.getItemId())
                case R.id.Nav_First:
                    Intent First= new Intent(Second.this, First.class);
                    startActivity(First);
                    break;
                case R.id.Nav_Third:
                    Intent Third= new Intent(Second.this, Third.class);
                    startActivity(Third);
                    break;
            

            return true;
        
    );


第三个活动是:

BottomNavigationView mBottomNavigation;

    mBottomNavigation =(BottomNavigationView) findViewById(R.id.BottomNavigator);

    mBottomNavigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() 
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) 
            switch (item.getItemId())
                case R.id.Nav_First:
                    Intent First= new Intent(Third.this, First.class);
                    startActivity(First);
                    break;
                case R.id.Nav_Second:
                    Intent Second= new Intent(Third.this, Second.class);
                    startActivity(Second);
                    break;
            

            return true;
        
    );



3 个活动的 xml 相同:

<android.support.design.widget.BottomNavigationView
        android:layout_
        android:layout_
        android:id="@+id/BottomNavigator"
        android:background="@color/colorPrimaryDark"
        android:layout_alignParentBottom="true"
        app:itemTextColor="@drawable/item_bg"
        app:itemIconTint="@drawable/item_bg"
        app:menu="@menu/navigate_items">
    </android.support.design.widget.BottomNavigationView>

【问题讨论】:

除非我遗漏了什么,否则这是使用 Fragments 的好场景(而且效果很好),那么为什么不坚持下去呢? 因为片段比主要活动难... 如何使用 AppCompatActivity 扩展应用程序 试试看this example 我很高兴听到这个消息。您应该考虑添加一个答案,以便对其他人有所帮助。 【参考方案1】:

您可以将 BottomNavigationView 与表示选项卡的活动一起使用。关键是在每个活动中重复导航视图组件,并让每个活动的代码控制导航组件:在导航项点击时启动正确的活动,并在活动启动后选择合适的导航项。

您需要延迟启动新选择的活动(选项卡),以允许选项卡切换动画在新活动替换前一个活动之前完成。

我的方法是让所有代表选项卡的活动都继承自同一个实现公共行为的 BaseActivity 类。

这是一个示例 BaseActivity 的代码:

public abstract class BaseActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener 

    protected BottomNavigationView navigationView;

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

        navigationView = (BottomNavigationView) findViewById(R.id.navigation);
        navigationView.setOnNavigationItemSelectedListener(this);
    

    @Override
    protected void onStart() 
        super.onStart();
        updateNavigationBarState();
    

    // Remove inter-activity transition to avoid screen tossing on tapping bottom navigation items
    @Override
    public void onPause() 
        super.onPause();
        overridePendingTransition(0, 0);
    

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) 
        navigationView.postDelayed(() -> 
            int itemId = item.getItemId();
            if (itemId == R.id.navigation_home) 
                startActivity(new Intent(this, HomeActivity.class));
             else if (itemId == R.id.navigation_dashboard) 
                    startActivity(new Intent(this, DashboardActivity.class));
             else if (itemId == R.id.navigation_notifications) 
                    startActivity(new Intent(this, NotificationsActivity.class));
            
            finish();
        , 300);
        return true;
    

    private void updateNavigationBarState()
        int actionId = getNavigationMenuItemId();
        selectBottomNavigationBarItem(actionId);
    

    void selectBottomNavigationBarItem(int itemId) 
        Menu menu = navigationView.getMenu();
        for (int i = 0, size = menu.size(); i < size; i++) 
            MenuItem item = menu.getItem(i);
            boolean shouldBeChecked = item.getItemId() == itemId;
            if (shouldBeChecked) 
                item.setChecked(true);
                break;
            
        
    

    abstract int getContentViewId();

    abstract int getNavigationMenuItemId();


这是我基于 Android Studio 的底部导航活动模板的整个示例:

https://github.com/ddekanski/BottomNavigationViewBetweenActivities

【讨论】:

我看到你编写了如何在我按下选项卡 1 向下滚动然后按下选项卡 2 并按下选项卡 1 时保持活动内部片段状态的代码? 而不是使用 overridePendingTransition(0, 0);在 onPause() 中,在主题中使用 @null。在此处查看完整的解决方案 - ***.com/questions/6972295/… 很好的答案,但如果它已经创建,任何不重新创建活动的方法。例如,使用这种方法,如果我喜欢特定活动中的两个或更多级别,并且我选择了另一个活动并且它们返回到先前选择的活动,则 startActivity 调用将重新创建它,因此将带我回到顶层那个活动【参考方案2】:

对于仍在寻找这个的人来说,@javazian 扩展每个活动的答案在我看来真的是矫枉过正。

更简洁的解决方案是检索导航菜单并手动检查相关菜单项。

请注意,在下面的示例中,INSERT_INDEX_HERE 需要替换为菜单项的索引(例如,最左侧的菜单项的索引为 0)。

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_connections);

    BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
    navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);

    // Ensure correct menu item is selected (where the magic happens)
    Menu menu = navigation.getMenu();
    MenuItem menuItem = menu.getItem(INSERT_INDEX_HERE);
    menuItem.setChecked(true);

【讨论】:

【参考方案3】:

您绝对可以将 BottomNavigationView 与活动一起使用,但不建议这样做。 更好的是与 Fragments 一起使用,主要好处是:

BottomNavigationView 中的动画(在活动的情况下没有丑陋的延迟) 轻松维护 Fragments 的状态 灵活的后台堆栈

但如果你想坚持使用Activities,那么@javaxian 的回答非常好,但我们可以改进它:

    如果我们的布局文件没有具有正确 id 的 BottomNavigation,那么我们将出现异常。更好的是为带有导航的活动提供通用布局文件。

解决方案

1) 将 BaseActivity 重命名为 BaseNavigationActivity

2) 为所有活动制作单个布局文件(例如activity_navigation.xml),并显式调用 BaseNavigationActivity setContentView(R.layout.activity_navigation);

3) 删除abstract int getContentViewId();

    selectBottomNavigationBarItem(int itemId) 中的代码是开销,我们可以更简单地做到这一点

解决方案(在 Kotlin 中):

private fun selectBottomNavigationBarItem(itemId: Int) 
    val menuItem = navigationView.menu.findItem(itemId)
    menuItem.isChecked = true

【讨论】:

【参考方案4】:

您可以在每个活动开始时使用setSelectedItemId

bottomNavigationView.setSelectedItemId(R.id.menu_item_id);

其中 R.id.menu_item_id 位于 menu/navigate_items

【讨论】:

以上是关于在活动之间使用 BottomNavigationView 按下时如何突出显示项目?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用接口在两个活动之间进行通信

在片段和活动之间导航

在活动之间使用 BottomNavigationView 按下时如何突出显示项目?

在活动之间切换而不关闭它们

如何使用接口在片段和活动之间进行通信?

在活动之间发送监听器