Source code
package android.support.design.widget;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable.Creator;
import android.support.annotation.DrawableRes;
import android.support.annotation.IdRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.support.design.R;
import android.support.design.internal.NavigationMenu;
import android.support.design.internal.NavigationMenuPresenter;
import android.support.design.internal.ScrimInsetsFrameLayout;
import android.support.v4.content.ContextCompat;
import android.support.v4.os.ParcelableCompat;
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.ViewCompat;
import android.support.v7.internal.view.SupportMenuInflater;
import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.internal.view.menu.MenuBuilder.Callback;
import android.support.v7.internal.view.menu.MenuItemImpl;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.BaseSavedState;
import android.view.View.MeasureSpec;
public class NavigationView extends ScrimInsetsFrameLayout {
private static final int[] CHECKED_STATE_SET = new int[]{16842912};
private static final int[] DISABLED_STATE_SET = new int[]{-16842910};
private static final int PRESENTER_NAVIGATION_VIEW_ID = 1;
private OnNavigationItemSelectedListener mListener;
private int mMaxWidth;
private final NavigationMenu mMenu;
private MenuInflater mMenuInflater;
private final NavigationMenuPresenter mPresenter;
public interface OnNavigationItemSelectedListener {
boolean onNavigationItemSelected(MenuItem menuItem);
}
public static class SavedState extends BaseSavedState {
public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
public SavedState createFromParcel(Parcel parcel, ClassLoader loader) {
return new SavedState(parcel, loader);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
});
public Bundle menuState;
public SavedState(Parcel in, ClassLoader loader) {
super(in);
this.menuState = in.readBundle(loader);
}
public SavedState(Parcelable superState) {
super(superState);
}
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeBundle(this.menuState);
}
}
public NavigationView(Context context) {
this(context, null);
}
public NavigationView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
ColorStateList itemIconTint;
super(context, attrs, defStyleAttr);
this.mPresenter = new NavigationMenuPresenter();
ThemeUtils.checkAppCompatTheme(context);
this.mMenu = new NavigationMenu(context);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NavigationView, defStyleAttr, R.style.Widget_Design_NavigationView);
setBackgroundDrawable(a.getDrawable(R.styleable.NavigationView_android_background));
if (a.hasValue(R.styleable.NavigationView_elevation)) {
ViewCompat.setElevation(this, (float) a.getDimensionPixelSize(R.styleable.NavigationView_elevation, 0));
}
ViewCompat.setFitsSystemWindows(this, a.getBoolean(R.styleable.NavigationView_android_fitsSystemWindows, false));
this.mMaxWidth = a.getDimensionPixelSize(R.styleable.NavigationView_android_maxWidth, 0);
if (a.hasValue(R.styleable.NavigationView_itemIconTint)) {
itemIconTint = a.getColorStateList(R.styleable.NavigationView_itemIconTint);
} else {
itemIconTint = createDefaultColorStateList(16842808);
}
boolean textAppearanceSet = false;
int textAppearance = 0;
if (a.hasValue(R.styleable.NavigationView_itemTextAppearance)) {
textAppearance = a.getResourceId(R.styleable.NavigationView_itemTextAppearance, 0);
textAppearanceSet = true;
}
ColorStateList itemTextColor = null;
if (a.hasValue(R.styleable.NavigationView_itemTextColor)) {
itemTextColor = a.getColorStateList(R.styleable.NavigationView_itemTextColor);
}
if (!textAppearanceSet && itemTextColor == null) {
itemTextColor = createDefaultColorStateList(16842806);
}
Drawable itemBackground = a.getDrawable(R.styleable.NavigationView_itemBackground);
this.mMenu.setCallback(new Callback() {
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
return NavigationView.this.mListener != null && NavigationView.this.mListener.onNavigationItemSelected(item);
}
public void onMenuModeChange(MenuBuilder menu) {
}
});
this.mPresenter.setId(1);
this.mPresenter.initForMenu(context, this.mMenu);
this.mPresenter.setItemIconTintList(itemIconTint);
if (textAppearanceSet) {
this.mPresenter.setItemTextAppearance(textAppearance);
}
this.mPresenter.setItemTextColor(itemTextColor);
this.mPresenter.setItemBackground(itemBackground);
this.mMenu.addMenuPresenter(this.mPresenter);
addView((View) this.mPresenter.getMenuView(this));
if (a.hasValue(R.styleable.NavigationView_menu)) {
inflateMenu(a.getResourceId(R.styleable.NavigationView_menu, 0));
}
if (a.hasValue(R.styleable.NavigationView_headerLayout)) {
inflateHeaderView(a.getResourceId(R.styleable.NavigationView_headerLayout, 0));
}
a.recycle();
}
protected Parcelable onSaveInstanceState() {
SavedState state = new SavedState(super.onSaveInstanceState());
state.menuState = new Bundle();
this.mMenu.savePresenterStates(state.menuState);
return state;
}
protected void onRestoreInstanceState(Parcelable savedState) {
SavedState state = (SavedState) savedState;
super.onRestoreInstanceState(state.getSuperState());
this.mMenu.restorePresenterStates(state.menuState);
}
public void setNavigationItemSelectedListener(OnNavigationItemSelectedListener listener) {
this.mListener = listener;
}
protected void onMeasure(int widthSpec, int heightSpec) {
switch (MeasureSpec.getMode(widthSpec)) {
case Integer.MIN_VALUE:
widthSpec = MeasureSpec.makeMeasureSpec(Math.min(MeasureSpec.getSize(widthSpec), this.mMaxWidth), 1073741824);
break;
case 0:
widthSpec = MeasureSpec.makeMeasureSpec(this.mMaxWidth, 1073741824);
break;
}
super.onMeasure(widthSpec, heightSpec);
}
public void inflateMenu(int resId) {
this.mPresenter.setUpdateSuspended(true);
getMenuInflater().inflate(resId, this.mMenu);
this.mPresenter.setUpdateSuspended(false);
this.mPresenter.updateMenuView(false);
}
public Menu getMenu() {
return this.mMenu;
}
public View inflateHeaderView(@LayoutRes int res) {
return this.mPresenter.inflateHeaderView(res);
}
public void addHeaderView(@NonNull View view) {
this.mPresenter.addHeaderView(view);
}
public void removeHeaderView(@NonNull View view) {
this.mPresenter.removeHeaderView(view);
}
@Nullable
public ColorStateList getItemIconTintList() {
return this.mPresenter.getItemTintList();
}
public void setItemIconTintList(@Nullable ColorStateList tint) {
this.mPresenter.setItemIconTintList(tint);
}
@Nullable
public ColorStateList getItemTextColor() {
return this.mPresenter.getItemTextColor();
}
public void setItemTextColor(@Nullable ColorStateList textColor) {
this.mPresenter.setItemTextColor(textColor);
}
public Drawable getItemBackground() {
return this.mPresenter.getItemBackground();
}
public void setItemBackgroundResource(@DrawableRes int resId) {
setItemBackground(ContextCompat.getDrawable(getContext(), resId));
}
public void setItemBackground(Drawable itemBackground) {
this.mPresenter.setItemBackground(itemBackground);
}
public void setCheckedItem(@IdRes int id) {
MenuItem item = this.mMenu.findItem(id);
if (item != null) {
this.mPresenter.setCheckedItem((MenuItemImpl) item);
}
}
public void setItemTextAppearance(@StyleRes int resId) {
this.mPresenter.setItemTextAppearance(resId);
}
private MenuInflater getMenuInflater() {
if (this.mMenuInflater == null) {
this.mMenuInflater = new SupportMenuInflater(getContext());
}
return this.mMenuInflater;
}
private ColorStateList createDefaultColorStateList(int baseColorThemeAttr) {
TypedValue value = new TypedValue();
if (!getContext().getTheme().resolveAttribute(baseColorThemeAttr, value, true)) {
return null;
}
ColorStateList baseColor = getResources().getColorStateList(value.resourceId);
if (!getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true)) {
return null;
}
int colorPrimary = value.data;
int defaultColor = baseColor.getDefaultColor();
return new ColorStateList(new int[][]{DISABLED_STATE_SET, CHECKED_STATE_SET, EMPTY_STATE_SET}, new int[]{baseColor.getColorForState(DISABLED_STATE_SET, defaultColor), colorPrimary, defaultColor});
}
}