我该如何改变NavigationView的项目文本大小?

72

Google 最近发布了 android.support.design.widget.NavigationView 小部件作为 com.android.support:design:22.2.0 库的一部分,这大大简化(并标准化)了创建 NavigationDrawer 的过程。

然而根据设计规范, 列表项应该是Roboto Medium, 14sp, 87% #000000NavigationView 没有暴露 textSizetextStyle 来自定义此内容。

Material design specs Font style info

如果我非常注重使用谷歌提供的 NavigationView(或以其他方式自定义它)来保持正确的设计规范,那么我有哪些选择?

你知道我们是否可以用 awsomeFont 图标替换这些图标吗? - Thiago
哈哈,完全不相关的问题!抱歉,除了下载PNG文件并使用它们之外,我不知道其他方法。您可以直接从Google上下载符合Material Design标准的图标,网址为https://www.google.com/design/icons/。 - Jay Wick
请查看此评论链接 - pablopatarca
11个回答

121
在文件app/src/main/res/values/styles.xml中创建新的样式。
<style name="NavigationDrawerStyle">

        <item name="android:textSize">20sp</item><!-- text size in menu-->

        <!-- item size in menu-->
        <item name="android:listPreferredItemHeightSmall">40dp</item>
        <item name="listPreferredItemHeightSmall">40dp</item>

        <!-- item padding left in menu-->
        <item name="android:listPreferredItemPaddingLeft">8dp</item>
        <item name="listPreferredItemPaddingLeft">8dp</item>

        <!-- item padding right in menu-->
        <item name="android:listPreferredItemPaddingRight">8dp</item>
        <item name="listPreferredItemPaddingRight">8dp</item>
    </style>

将其添加到您的main_layout.xml中。

  <android.support.design.widget.NavigationView
       ...
        app:theme="@style/NavigationDrawerStyle"
       ....>


    </android.support.design.widget.NavigationView>

导航项的所有参数(可更改)都在此处(文件路径:...\sdk\extras\android\support\design\res\layout\design_navigation_item.xml)。

design_navigation_item.xml

<android.support.design.internal.NavigationMenuItemView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?attr/listPreferredItemHeightSmall"
    android:paddingLeft="?attr/listPreferredItemPaddingLeft"
    android:paddingRight="?attr/listPreferredItemPaddingRight"
    android:drawablePadding="@dimen/navigation_icon_padding"
    android:gravity="center_vertical|start"
    android:maxLines="1"
    android:fontFamily="sans-serif-thin"
    android:textSize="22sp"
    android:textAppearance="?attr/textAppearanceListItem" />

您还可以覆盖*.xml文件(从...\sdk\extras\android\support\design\res\layout\design_navigation_item.xml复制文件),只需在您的app/src/main/res/layout文件夹中创建一个同名design_navigation_item.xml布局即可。

所有可以被重写的布局都在此处...\sdk\extras\android\support\design\res\layout\

design_layout_snackbar.xml
design_layout_snackbar_include.xml
design_layout_tab_icon.xml
design_layout_tab_text.xml
design_navigation_item.xml
design_navigation_item_header.xml
design_navigation_item_separator.xml
design_navigation_item_subheader.xml
design_navigation_menu.xml

[更新] 每个版本的com.android.support:design-{version}库都有不同的项目需要覆盖。请在此处检查你需要的所有内容。

[更新 04/14/2020]

如果你正在使用com.google.android.material.navigation.NavigationView,那么打开这个类,你会看到:

public NavigationView(@NonNull Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, R.attr.navigationViewStyle);
  }

因此,您可以使用属性navigationViewStyle通过应用程序的主题设置自己的NavigationView样式:

NB:AppTheme的父级主题应为 Theme.MaterialComponents

    <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">
   ...
<item name="navigationViewStyle">@style/AppNavigationViewStyle</item>
   ...
    </style>

<style name="AppNavigationViewStyle" parent="Widget.MaterialComponents.NavigationView">
        <item name="itemTextAppearance">@style/AppNavigationViewItemTextAppearance</item>
   </style>
<style name="AppNavigationViewItemTextAppearance" parent="@style/TextAppearance.MaterialComponents.Subtitle2">
         <item name="android:textSize">18sp</item>
   </style>

只需打开父主题,即可查看所有<item name属性以进行覆盖。


你是在建议我覆盖所有这些XML并创建自己的XML,还是只使用这些参数并将其放入样式中?此外,我能否指定自己的字体? - Akhil Dad
这就是我需要的回复,为这些值添加自定义样式非常有帮助。谢谢。 - Sierisimo

65
你可以在 style.xml 中自定义一切,从文本颜色到大小和字体。
<style name="NavDrawerTextStyle" parent="Base.TextAppearance.AppCompat">
    <item name="android:textColor">@color/colorPrimaryDark</item>
    <item name="android:textSize">16sp</item>
    <item name="android:textStyle">bold</item>
</style>

然后在你的NavigationView中:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">

<android.support.design.widget.NavigationView
    ...
    android:itemTextAppearance="@style/NavDrawerTextStyle"
     />

如何为项目标题设置Roboto-Medium字体? - Akshatha S R
我有一个导航头,改变textSize会改变菜单项文本的大小,但改变textColor会改变标题文本的颜色。 <style name="NavigationDrawer" > <item name="android:textSize">20sp</item> <item name="android:textColor">@color/white</item> </style>我想改变菜单项文本的颜色。有什么建议吗? - Mrinal
这实际上是有效的,但如果我们想应用自定义ttf,该怎么做呢? - sagar.android
@ojonugwaochalifu 我们可以将layout_gravity设置为center_horizontal来使项目水平居中吗? - Vivek Pratap Singh
4
当我将 android:itemTextAppearance="@style/NavDrawerTextStyle"/> 修改为 app:itemTextAppearance="@style/NavDrawerTextStyle"/> 时,这对我起了作用。 - Akanshi Srivastava

63
自从 Android Support Library 22.2.1 版本开始,Google 将 NavigationView 中的默认 textSize 从 16sp 改为 14sp,这符合 Material Design 指南。然而,在某些情况下(例如您希望支持中文语言时),似乎更大的 textSize 更好。解决方案很简单:
  1. 在您的 layout.xml 文件中的 NavigationView 中添加 app:theme="@style/yourStyle.Drawer"
  2. 在 styles.xml 文件中,在样式 yourStyle.Drawer 中添加 android:textSize="16sp"

看起来像是个bug啊!很酷!如果有人因为某些原因卡在22.2.0,请参考我的答案 - Jay Wick

19

您可以在XML文件中使用这些属性

app:itemTextAppearance="?android:attr/textAppearanceMedium"

或用于小文本

app:itemTextAppearance="?android:attr/textAppearance"

或者用于大段文本

app:itemTextAppearance="?android:attr/textAppearanceLarge"

16
这对我有用: activity_main.xml
<android.support.design.widget.NavigationView
    android:id="@+id/navigation_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:theme="@style/NavigationDrawerStyle"
    app:headerLayout="@layout/navdrawer_header"
    app:menu="@menu/navdrawer_menu" />

样式.xml

<style name="NavigationDrawerStyle">
    <item name="android:textSize">16sp</item>
</style>

10

在浏览源代码时,我找到了这个布局文件:

/platform/frameworks/support/.../design/res/layout/design_drawer_item.xml

其中包含以下属性:

<android.support.design.internal.NavigationMenuItemView
    ...
    android:textAppearance="?attr/textAppearanceListItem"

这意味着我们只需要在项目中覆盖textAppearanceListItem样式即可。


res/values/styles.xml

<style name="AppTheme" ... >
    ...
    <item name="textAppearanceListItem">@style/list_item_appearance</item>
</style>

<style name="list_item_appearance">
    <item name="android:textSize">14sp</item>
    <item name="android:fontFamily">sans-serif-medium</item>
</style>

我不完全确定这还会影响什么,但如果有更好的答案,我愿意接受。


对我来说,sans-serif-medium选项不可用。 - Akshatha S R

3
也许这会有所帮助。最近我需要以编程方式实现这个功能。我使用了这个类:
public class CustomTypefaceSpan extends TypefaceSpan {

private final Typeface newType;
private final float newSp;

public CustomTypefaceSpan(String family, Typeface type, float sp) {
    super(family);
    newType = type;
    newSp = sp;
}

@Override
public void updateDrawState(TextPaint ds) {
    applyCustomTypeFace(ds, newType, newSp);
}

@Override
public void updateMeasureState(TextPaint paint) {
    applyCustomTypeFace(paint, newType, newSp);
}

private static void applyCustomTypeFace(Paint paint, Typeface tf, float sp) {
    int oldStyle;
    Typeface old = paint.getTypeface();
    if (old == null) {
        oldStyle = 0;
    } else {
        oldStyle = old.getStyle();
    }

    int fake = oldStyle & ~tf.getStyle();
    if ((fake & Typeface.BOLD) != 0) {
        paint.setFakeBoldText(true);
    }

    if ((fake & Typeface.ITALIC) != 0) {
        paint.setTextSkewX(-0.25f);
    }

    paint.setTextSize(sp);
    paint.setTypeface(tf);
}

@SuppressWarnings("unused")
public static final Parcelable.Creator<CustomTypefaceSpan> CREATOR = new Parcelable.Creator<CustomTypefaceSpan>() {
    @Override
    public CustomTypefaceSpan createFromParcel(Parcel in) {
        return null;
    }

    @Override
    public CustomTypefaceSpan[] newArray(int size) {
        return new CustomTypefaceSpan[size];
    }
};
}

然后我像这样使用:
// This is for color
SpannableString s = new SpannableString(item.getTitle().toString());
                    s.setSpan(new ForegroundColorSpan(Color.RED), 0, s.length(), 0);

// This is for typeface and size
Typeface typeFace = Functions.getTypeface(this, "Avenir");

if (typeFace != null) {
    int size = 19;
    float scaledSizeInPixels = size * getResources().getDisplayMetrics().scaledDensity;
    CustomTypefaceSpan spanTypeFace = new CustomTypefaceSpan(item.getTitle().toString(), typeFace, scaledSizeInPixels);
    s.setSpan(spanTypeFace, 0, s.length(), 0);
}
item.setTitle(s);

希望这能帮到你。

谢谢你,虽然不是针对解决方案本身,但感谢提供实现 Parcelable.Creator 方法的示例。 - iSofia

2

打开activity_main.xml文件,选择design视图下的nav_view,你可以通过更新itemTextAppearanceitemTextColor来更改菜单项的文本大小,如下图所示:navigation_view_item_style


(译注:该段文字介绍了在Android开发中如何修改导航栏菜单项的文本样式)

2
对于com.google.android.material.navigation.NavigationView,您应该使用app命名空间与您的自定义样式一起使用:app:itemTextAppearance="@style/NavDrawerTextStyle"

1
谢谢,完美的答案。 - Wowo Ot

0

导航栏的列表适配器布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content" 
    android:padding="10dp"
    android:orientation="horizontal"
    android:background="@drawable/pressed_state">

    <TextView
        android:id="@+id/textView_list_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/imageView_icons"
        android:textStyle="bold"
        android:layout_marginLeft="10dp"
        android:textColor="@color/white"
        android:textSize="17sp" />


    <ImageView 
        android:id="@+id/list_adapter_image"
        android:layout_width="10dp"
        android:layout_height="10dp"
        android:layout_centerVertical="true"
        android:layout_alignParentRight="true"
        android:visibility="visible"
        android:layout_marginRight="50dp"
        android:background="@drawable/circle_orange"/>

</RelativeLayout>

<LinearLayout 
    android:layout_height="1dp"
    android:layout_width="match_parent"
    android:background="#EC1294"></LinearLayout>

</LinearLayout>

在RelativeLayout中,这个参数设置了背景颜色 --> android:background="@drawable/pressed_state"

在drawable文件夹中创建一个名为"pressed_state.xml"的文件。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >

 <item android:drawable="@color/light_blue" android:state_pressed="true"/>

抱歉我的英语不好。


嘿,非常感谢你的回答,不过我已经从实现自己的导航抽屉转而使用 Google 提供的支持库了。我希望能够通过 NavigationView 自身来实现这一点。 - Jay Wick
兄弟,你需要先创建一个布局,并将其放入适配器中。 - Chaudhary Amar
我认为我们正在以不同的方式实现导航抽屉。我不确定你所说的“列表适配器布局”是什么意思。使用设计支持库的NavigationView时,没有列表适配器在起作用,但是app:menu="@menu/drawer"引用了一个标准菜单。请参见http://goo.gl/D0kVBH的第一个代码片段以获取更多详细信息。如果我理解错误,请原谅 :) - Jay Wick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接