删除 BottomNavigationView 标签

Google 发布了带有 BottomNavigationView 的新支持库 v25

enter image description here

有没有办法去掉商品标签?

66610 次浏览

Unfortunately this first version of BottomNavigationView came with a lot of limitations. And for now you can't remove the titles just using the support design API. So to solve this limitation while google doesn't implement it, you can do (using reflection):

1. Set the titles empty in from bottom_navigation_menu.xml file.

2. Extends the BottomNavigationView:

    public class MyBottomNavigationView extends BottomNavigationView {


public MyBottomNavigationView(Context context, AttributeSet attrs) {
super(context, attrs);
centerMenuIcon();
}


private void centerMenuIcon() {
BottomNavigationMenuView menuView = getBottomMenuView();


if (menuView != null) {
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView menuItemView = (BottomNavigationItemView) menuView.getChildAt(i);


AppCompatImageView icon = (AppCompatImageView) menuItemView.getChildAt(0);


FrameLayout.LayoutParams params = (LayoutParams) icon.getLayoutParams();
params.gravity = Gravity.CENTER;


menuItemView.setShiftingMode(true);
}
}
}


private BottomNavigationMenuView getBottomMenuView() {
Object menuView = null;
try {
Field field = BottomNavigationView.class.getDeclaredField("mMenuView");
field.setAccessible(true);
menuView = field.get(this);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}


return (BottomNavigationMenuView) menuView;
}
}

3. Add to the layout.xml this customView

For more details I have implemented this on Github

Reflectionless approach:

private void removeTextLabel(@NonNull BottomNavigationView bottomNavigationView, @IdRes int menuItemId) {
View view = bottomNavigationView.findViewById(menuItemId);
if (view == null) return;
if (view instanceof MenuView.ItemView) {
ViewGroup viewGroup = (ViewGroup) view;
int padding = 0;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View v = viewGroup.getChildAt(i);
if (v instanceof ViewGroup) {
padding = v.getHeight();
viewGroup.removeViewAt(i);
}
}
viewGroup.setPadding(view.getPaddingLeft(), (viewGroup.getPaddingTop() + padding) / 2, view.getPaddingRight(), view.getPaddingBottom());
}
}

This is a temporary fix. Just add: app:itemTextColor="@android:color/transparent" That'll make it whatever the background color is, appearing disabled. It does make the icon look elevated.

Would you want to this style ?

If so, I recommend you try BottomNavigationViewEx.

I'd recommend to implement it by yourself as sanf0rd gave in his answer. But AppCompatImageView is not working for me. I've changed it to ImageView. And changed getChildAt to findViewById.

Also I hide all labels of unselected items.

private void centerMenuIcon() {
BottomNavigationMenuView menuView = getBottomMenuView();
if (menuView != null) {
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView menuItemView = (BottomNavigationItemView) menuView.getChildAt(i);
TextView smallText = (TextView) menuItemView.findViewById(R.id.smallLabel);
smallText.setVisibility(View.INVISIBLE);
//TextView largeText = (TextView) menuItemView.findViewById(R.id.largeLabel);
ImageView icon = (ImageView) menuItemView.findViewById(R.id.icon);
FrameLayout.LayoutParams params = (LayoutParams) icon.getLayoutParams();
params.gravity = Gravity.CENTER;
menuItemView.setShiftingMode(true);
}
}
}

1. Set android:title=""; in menu/abc.xml

2. Create the below helper class which is using reflection

import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.widget.AppCompatImageView;
import android.util.Log;
import android.view.Gravity;
import android.widget.FrameLayout;


import java.lang.reflect.Field;


public class BottomNavigationViewHelper {
public static void disableShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
try {
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView, false);
shiftingMode.setAccessible(false);
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
//noinspection RestrictedApi
item.setShiftingMode(false);
item.setPadding(0, 15, 0, 0);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
item.setChecked(item.getItemData().isChecked());
}
} catch (NoSuchFieldException e) {
Log.e("BNVHelper", "Unable to get shift mode field", e);
} catch (IllegalAccessException e) {
Log.e("BNVHelper", "Unable to change value of shift mode", e);
}
}
}

3. In your main activity, add these lines:

mBottomNav = (BottomNavigationView) findViewById(R.id.navigation);
BottomNavigationViewHelper.disableShiftMode(mBottomNav);

I wanted to remove both the shift animation and the labels and none of the solutions here worked well for me, so here's the one I built based on everything I learned here:

public void removeLabels(@IdRes int... menuItemIds) {
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);


// this only needs to be calculated once for an unchecked item, it'll be the same value for all items
ViewGroup uncheckedItem = findFirstUncheckedItem(menuItemIds);
View icon = uncheckedItem.getChildAt(0);
int iconTopMargin = ((LayoutParams) uncheckedItem.getChildAt(0).getLayoutParams()).topMargin;
int desiredTopMargin = (uncheckedItem.getHeight() - uncheckedItem.getChildAt(0).getHeight()) / 2;
int itemTopPadding = desiredTopMargin - iconTopMargin;


for (int id : menuItemIds) {
ViewGroup item = findViewById(id);
// remove the label
item.removeViewAt(1);
// and then center the icon
item.setPadding(item.getPaddingLeft(), itemTopPadding, item.getPaddingRight(),
item.getPaddingBottom());
}


return true;
}
});
}


@SuppressLint("RestrictedApi")
private ViewGroup findFirstUncheckedItem(@IdRes int... menuItemIds) {
BottomNavigationItemView item = findViewById(menuItemIds[0]);
int i = 1;
while (item.getItemData().isChecked()) {
item = findViewById(menuItemIds[i++]);
}
return item;
}

Just add this method to your custom BottomNavigationView and call it passing the ids of the menu items.

I hope I am not too late to the party here.

But as of Design Support Library 28.0.0-alpha1 you can use the property

app:labelVisibilityMode="unlabeled"

BottomNavigationView without labels

you can use other values "auto", "labeled" and "selected" as well.