How to highlight the item when pressed using Botto

2019-01-25 05:52发布

问题:

I have added Bottom Navigation View for my app but I need the Bottom Navigation View between activities instead of fragment so I have added this code to Java for all my 3 activities.

When I select Second or Third in my phone all things are correct but the problem is the highlight goes to the First item.

I need to highlight the item I press.

I have used fragment and it works perfectly but I am still beginner for using fragment so I am using activities.

The first activity code is:

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;
        }
    });


}}

The second activity is:

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;
        }
    });

}}

The third activity is:

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;
        }
    });


}}

The xml are the same for 3 activities:

<android.support.design.widget.BottomNavigationView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        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>

回答1:

You can use BottomNavigationView with activities representing tabs. The key is to repeat the navigation view component in each activity, and have the code of each activity control the navigation component: starting the right activity on navigation item clicks and selecting a proper navigation item after the activity has started.

You need to start newly selected activities (tabs) with a delay as to allow the tab switching animation to complete before the new activity replaces the previous one.

My approach was to have all activities representing tabs inherit from the same BaseActivity class implementing the common behavior.

This is the code of an example 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();

}

This is my whole example based on the Android Studio's Bottom Navigation Activity template:

https://github.com/ddekanski/BottomNavigationViewBetweenActivities



回答2:

To anyone still looking for this, @javazian's answer of extending each activity is real overkill in my opinion.

A much more succinct solution is to retrieve the nav menu and manually check the relevant menu item.

Note in the example below, INSERT_INDEX_HERE needs to be replaced with the index of the menu item, (e.g. the menu item on the far left would have index 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:

You absolutely can use BottomNavigationView with activities, but it's not recommended. Better is to use it with Fragments, main benefits are:

  • Animation in BottomNavigationView (without ugly delay in case of Activities)
  • Maintain state of Fragments easily
  • Flexible backstack

But if you want to stick with Activities, then @javaxian answer is very good, but we can improve it:

  1. If our layout file doesn't have a BottomNavigation with proper id, then we will have exception. Better is to have common layout file for activities with navigation.

Solution:

1) Rename BaseActivity to BaseNavigationActivity

2) Make single layout file for all your Activities (for example activity_navigation.xml), and explicitly call in BaseNavigationActivity setContentView(R.layout.activity_navigation);

3) Remove abstract int getContentViewId();

  1. Code in selectBottomNavigationBarItem(int itemId) is overhead, we can do it much more simplier

Solution (in Kotlin):

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