Как установить пользовательский шрифт для элементов в NavigationView?
новая NavigationView
, мы можем установить элементы ящика через ресурс меню в XML.
С этим, мы можем установить каждый элемент с чем-то вроде
<item
android:id="@+id/drawer_my_account"
android:icon="@drawable/ic_my_account"
android:title="@string/drawer_my_account" />
но теперь я хочу установить пользовательский шрифт для каждого из этих пунктов в моем ящике, и я не мог найти способ сделать это, либо с помощью XML или Java-кода. Есть ли способ сделать это?
14 ответов:
просто добавьте следующий файл класса в свой проект.
import android.graphics.Paint; import android.graphics.Typeface; import android.text.TextPaint; import android.text.style.TypefaceSpan; public class CustomTypefaceSpan extends TypefaceSpan { private final Typeface newType; public CustomTypefaceSpan(String family, Typeface type) { super(family); newType = type; } @Override public void updateDrawState(TextPaint ds) { applyCustomTypeFace(ds, newType); } @Override public void updateMeasureState(TextPaint paint) { applyCustomTypeFace(paint, newType); } private static void applyCustomTypeFace(Paint paint, Typeface tf) { 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.setTypeface(tf); } }
затем создайте следующий метод для вашей деятельности
private void applyFontToMenuItem(MenuItem mi) { Typeface font = Typeface.createFromAsset(getAssets(), "ds_digi_b.TTF"); SpannableString mNewTitle = new SpannableString(mi.getTitle()); mNewTitle.setSpan(new CustomTypefaceSpan("" , font), 0 , mNewTitle.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); mi.setTitle(mNewTitle); }
и вызвать его из деятельности.
navView = (NavigationView) findViewById(R.id.navView); Menu m = navView.getMenu(); for (int i=0;i<m.size();i++) { MenuItem mi = m.getItem(i); //for aapplying a font to subMenu ... SubMenu subMenu = mi.getSubMenu(); if (subMenu!=null && subMenu.size() >0 ) { for (int j=0; j <subMenu.size();j++) { MenuItem subMenuItem = subMenu.getItem(j); applyFontToMenuItem(subMenuItem); } } //the method we have create in activity applyFontToMenuItem(mi); }
и вот мой вывод
этот работает на меня
<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:background="#4A4444" android:clipToPadding="false" android:paddingBottom="50dp" app:itemIconTint="@color/white" app:menu="@menu/drawer_home" app1:itemTextAppearance="@style/NavigationDrawerStyle" > </android.support.design.widget.NavigationView>
res - > значения - > стили
<style name="NavigationDrawerStyle"> <item name="android:textSize">18sp</item> <item name="android:typeface">monospace</item> </style>
//для установки пользовательского шрифта MainApplication.java
public class MainApplication extends Application { @Override public void onCreate() { super.onCreate(); //set Custom Typeface FontsOverride.setDefaultFont(this, "MONOSPACE", "OpenSans-Semibold.ttf"); } }
/ / FontsOverride.java
public final class FontsOverride { public static void setDefaultFont(Context context, String staticTypefaceFieldName, String fontAssetName) { final Typeface regular = Typeface.createFromAsset(context.getAssets(), fontAssetName); replaceFont(staticTypefaceFieldName, regular); } protected static void replaceFont(String staticTypefaceFieldName, final Typeface newTypeface) { try { final Field staticField = Typeface.class .getDeclaredField(staticTypefaceFieldName); staticField.setAccessible(true); staticField.set(null, newTypeface); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
есть ли способ сделать это?
да. Элемент
NavigationView
не обеспечивает прямой способ обработки этого, но это может быть легко достигнуто с помощьюView.findViewsWithText
.есть две вещи, которые помогут нам справиться с этим.
- каждого
MenuItem
посмотреть этоTextView
. Итак, что делает применение вашегоTypeface
это намного проще. Для получения дополнительной информации оTextView
фактически используетсяNavigationView
см.NavigationMenuItemView
.NavigationView
обеспечивает обратный вызов когда aMenuItem
выбран. Мы собираемся поставить каждыйMenuItem
с уникальным идентификатором, и этот обратный вызов поможет максимально обобщить эти идентификаторы, что означает немного меньше кода позже. Хотя, это больше связано с тем, есть ли у васSubMenu
.реализация
обратите внимание на каждый
MenuItem
ID-это простоmenuItem+Position
. Этот пригодится позже, когда мы найдемView
для каждогоMenuItem
.<group android:checkableBehavior="single"> <item android:id="@+id/menuItem1" android:icon="@drawable/ic_dashboard" android:title="MenuItem 1" /> <item android:id="@+id/menuItem2" android:icon="@drawable/ic_event" android:title="MenuItem 2" /> <item android:id="@+id/menuItem3" android:icon="@drawable/ic_headset" android:title="MenuItem 3" /> <item android:id="@+id/menuItem4" android:icon="@drawable/ic_forum" android:title="MenuItem 4" /> </group> <item android:title="Sub items" > <menu> <item android:id="@+id/menuItem5" android:icon="@drawable/ic_dashboard" android:title="Sub item 5" /> <item android:id="@+id/menuItem6" android:icon="@drawable/ic_forum" android:title="Sub item 6" /> </menu> </item>
/** The total number of menu items in the {@link NavigationView} */ private static final int MENU_ITEMS = 6; /** Contains the {@link MenuItem} views in the {@link NavigationView} */ private final ArrayList<View> mMenuItems = new ArrayList<>(MENU_ITEMS); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... final NavigationView navView = ... // Grab the NavigationView Menu final Menu navMenu = navView.getMenu(); // Install an OnGlobalLayoutListener and wait for the NavigationMenu to fully initialize navView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // Remember to remove the installed OnGlobalLayoutListener navView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // Loop through and find each MenuItem View for (int i = 0, length = MENU_ITEMS; i < length; i++) { final String id = "menuItem" + (i + 1); final MenuItem item = navMenu.findItem(getResources().getIdentifier(id, "id", getPackageName())); navView.findViewsWithText(mMenuItems, item.getTitle(), View.FIND_VIEWS_WITH_TEXT); } // Loop through each MenuItem View and apply your custom Typeface for (final View menuItem : mMenuItems) { ((TextView) menuItem).setTypeface(yourTypeface, Typeface.BOLD); } } }); }
вы можете видеть, как с помощью общего
MenuItem
id позволяет использоватьResources.getIdentifier
и сохранить несколько строк кода.
SubMenu
будьте осторожнычто-то, чтобы иметь в виду. Вам нужно явно перебирать ваш
N
пункты меню вместо использованияMenu.size
. В противном случае, вашSubMenu
элементы не будут распознаны. Другими словами, если у вас нетSubMenu
другой способ сделать это было бы:for (int i = 0, length = navMenu.size(); i < length; i++) { final MenuItem item = navMenu.getItem(i); navigationView.findViewsWithText(mMenuItems, item.getTitle(), View.FIND_VIEWS_WITH_TEXT); }
и вам не нужно беспокоиться о применении уникального идентификатора к каждому
MenuItem
.результаты
шрифт, который я использую в Примере:Smoothie Shoppe
использовать app: itemTextAppearance="" собственность. Надеюсь, это поможет.
<android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_main" android:background="@drawable/nav_bg_gradient" android:theme="@style/NavigationView" app:itemIconTint="@color/colorWhite" app:itemTextColor="@color/colorWhite" app:itemTextAppearance="@style/NavigationText" app:menu="@menu/main_drawer">
в стилях.xml write
<style name="NavigationText" parent="@android:style/TextAppearance.Medium"> <item name="android:textColor">@color/colorWhite</item> <item name="android:textSize">12sp</item> <item name="android:fontFamily">sans-serif-thin</item> </style>
я использовал приложение:тема
<android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:background="@color/colorMenuBackground" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_main" app:menu="@menu/activity_main_drawer" app:theme="@style/NavigationViewTextAppearance" />
стили.XML-код :
<style name="NavigationViewTextAppearance"> <item name="android:ellipsize">end</item> <item name="android:fontFamily">@font/badscript_regular</item> </style>
не пользовательский шрифт, а другой способ изменить шрифт элементов навигации. Создайте макет с именем
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" />
затем измените fontFamily на нужный шрифт.
немного поздно отвечать, но я нашел более чистый способ сделать это, поэтому я хотел бы поделиться.
сделать пользовательский вид
NavFontTextView.java
:import android.content.Context; import android.support.design.internal.NavigationMenuItemView; import android.util.AttributeSet; import utils.CustomFontHelper; public class NavFontTextView extends NavigationMenuItemView { Context mContext; public NavFontTextView(Context context) { super(context); mContext = context; setDefaultFont(); } public NavFontTextView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; setDefaultFont(); CustomFontHelper.setCustomFont(this, context, attrs); } public NavFontTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; setDefaultFont(); CustomFontHelper.setCustomFont(this, context, attrs); } public void setDefaultFont() { CustomFontHelper.setCustomFont(this, "fonts/SourceSansPro-Regular.ttf", mContext); } }
создайте файл с именем
CustomFontHelper.java
:import android.content.Context; import android.content.res.TypedArray; import android.graphics.Typeface; import android.util.AttributeSet; import android.widget.TextView; /** * Taken from: http://stackoverflow.com/a/16648457/75579 */ public class CustomFontHelper { /** * Sets a font on a textview based on the custom com.my.package:font attribute * If the custom font attribute isn't found in the attributes nothing happens * @param textview * @param context * @param attrs */ public static void setCustomFont(TextView textview, Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomFont); String font = a.getString(R.styleable.CustomFont_font); setCustomFont(textview, font, context); a.recycle(); } /** * Sets a font on a textview * @param textview * @param font * @param context */ public static void setCustomFont(TextView textview, String font, Context context) { if(font == null) { return; } Typeface tf = FontCache.get(font, context); if(tf != null) { textview.setTypeface(tf); } } }
сделать разметку
layout/design_navigation_item.xml
(имя должно быть точно таким же):<?xml version="1.0" encoding="utf-8"?> <custom_view.NavFontTextView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="?attr/listPreferredItemHeightSmall" android:drawablePadding="10dp" android:gravity="center_vertical|start" android:maxLines="1" android:paddingLeft="?attr/listPreferredItemPaddingLeft" android:paddingRight="?attr/listPreferredItemPaddingRight" app:font="fonts/SourceSansPro-Bold.ttf" />
разместить файл шрифта
SourceSansPro-Bold.ttf
в:app/src/main/assets/fonts/SourceSansPro-Bold.ttf
вы хорошо идти! Таким образом, вы можете сохранить свою основную деятельность чище.
для тех, кто использует @Moinkhan ответ, для применения шрифта к каждой части вашего меню используйте это решение и для каждого раздела заголовка используйте id. ваше меню Вот так..
<item android:title="@string/others" android:id="@+id/nav_others"> <menu> <item android:id="@+id/contact" android:title="@string/contact"/> </menu> </item>
и подобное решение..
navMenu = navView.getMenu(); MenuItem item= navView.getMenu().findItem(R.id.nav_others); applyFontToMenuItem(item);
может быть, это поможет кому-то.
мне очень понравилось решение "дракон, который плюет огнем", но я не получил
textview
. Это можно сделать, выполнив следующие действия:TextView textView = (CheckedTextView) findViewById(android.support.design.R.id.design_menu_item_text); public class StyledMenuItem extends NavigationMenuItemView { public StyledMenuItem(Context context) { super(context); } public StyledMenuItem(Context context, AttributeSet attrs) { super(context, attrs); if (!isInEditMode()) { setCustomFont(context, attrs); setFilterTouchesWhenObscured(true); } } public StyledMenuItem(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); if (!isInEditMode()) { setCustomFont(context, attrs); setFilterTouchesWhenObscured(true); } } private void setCustomFont(Context ctx, AttributeSet attrs) { TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.ProjectView); String customFont = a.getString(R.styleable.ProjectView_projectFont); setCustomFont(ctx, customFont); a.recycle(); } private void setCustomFont(Context ctx, String asset) { Typeface typeFace = TypeFaceProvider.getTypeFace(ctx, asset); TextView textView = (CheckedTextView) findViewById(android.support.design.R.id.design_menu_item_text); if (typeFace != null && textView != null) { textView.setTypeface(typeFace); } }
design_navigation_item.XML-код:
<?xml version="1.0" encoding="utf-8"?>
стиль.XML-код:
<style name="Body1" parent="Base.TextAppearance.AppCompat.Body1"> <item name="projectFont">Quicksand-Regular.otf</item> </style>
attrs.XML-код:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="ProjectView"> <attr name="projectFont" format="string" /> </declare-styleable> </resources>
Я рефакторингу @adneal это ответ на этот вопрос. Он перебирает пункты меню (не вдаваясь в подпункты, только элементы верхнего уровня) в соответствии с индексом вместо идентификатора и устанавливает шрифт.
заменить rightNavigationView С помощью NavigationView и {шрифт} С нужным шрифтом
final Menu navMenu = rightNavigationView.getMenu(); rightNavigationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { ArrayList<View> menuItems = new ArrayList<>(); // save Views in this array rightNavigationView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // remove the global layout listener for (int i = 0; i < navMenu.size(); i++) {// loops over menu items to get the text view from each menu item final MenuItem item = navMenu.getItem(i); rightNavigationView.findViewsWithText(menuItems, item.getTitle(), View.FIND_VIEWS_WITH_TEXT); } for (final View menuItem : menuItems) {// loops over the saved views and sets the font ((TextView) menuItem).setTypeface({TYPE}, Typeface.BOLD); } } });
другой способ установить свой собственный шрифт:
1. вы можете добавить свои шрифты в папку "шрифт", а затем вы можете использовать их в любом TextView (или там, где вам нужно)
пример шрифта.XML-код:
<?xml version="1.0" encoding="utf-8"?> <font-family xmlns:android="http://schemas.android.com/apk/res/android"> <font android:font="@font/nunito_bold" android:fontStyle="normal" android:fontWeight="400" /> </font-family>
2. в своем стили.xml-файл, вы можете настроить свой текстовый стиль элемента с этим шрифтом и цветом, где вам нужно (от @Moonis Abidi ответ)
<style name="NavigationText" parent="@android:style/TextAppearance.Medium"> <item name="android:textColor">@android:color/white</item> <item name="android:textSize">12sp</item> <item name="android:fontFamily">@font/nunito_semibold</item> </style>
3. теперь вам нужно только указать это в своем навигационном представлении с помощью приложение:itemTextAppearance:
<android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header" app:menu="@menu/main_menu" app:itemTextAppearance="@style/NavigationText"/>
// ------------- Кроме того, если вам нужно использовать этот шрифт из других TextViews, вы можете использовать его как
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/nunito_bold"/>
Это другой подход:
A NavigationView дети называют NavigationMenuItemView. У NavigationMenuItemView есть два ребенка. Один из них AppCompatCheckedTextView.
переопределить onLayout метод NavigationView, как ниже и изменить Typefase из AppCompatCheckedTextView:
public final class NavigationViewWithCustomFont extends NavigationView{ private final Context context; private Typeface fontFace; public NavigationViewWithCustomFont(Context context, AttributeSet attrs){ super(context, attrs); this.context = context; this.fontFace = null; } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom){ super.onLayout(changed, left, top, right, bottom); final ViewGroup navMenuView = (ViewGroup)getChildAt(0); final int navMenuItemsCount = navMenuView.getChildCount(); ViewGroup itemView; if(fontFace == null){ fontFace = Typeface.createFromAsset(context.getAssets(), context.getString(R.string.BTrafficBold)); } for(int i=0; i<navMenuItemsCount; i++){ itemView = (ViewGroup)navMenuView.getChildAt(i); if(itemView instanceof NavigationMenuItemView ){ CheckedTextView checkedTextView = (CheckedTextView)itemView.getChildAt(0); checkedTextView.setTypeface(fontFace, Typeface.BOLD); } } } }
BottomNavigationView bottom_nav = findViewById(R.id.bottom_nav); Typeface font = Typeface.createFromAsset(getAssets(), "--your customized font file--"); for (int i = 0; i <bottom_nav.getMenu().size(); i++) { MenuItem menuItem = bottom_nav.getMenu().getItem(i); SpannableStringBuilder spannableTitle = new SpannableStringBuilder(menuItem.getTitle()); spannableTitle.setSpan(font.getStyle(), 0, spannableTitle.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); menuItem.setTitle(spannableTitle); }
applyFontToMenuItem(popup.getMenu().getItem(0)); private void applyFontToMenuItem(MenuItem mi) { Typeface font = Typeface.createFromAsset(getAssets(), "fonts/Redressed.ttf"); SpannableString mNewTitle = new SpannableString(mi.getTitle()); mNewTitle.setSpan(new CustomTypefaceSpan("", font), 0, mNewTitle.length(),pannable.SPAN_INCLUSIVE_INCLUSIVE); mi.setTitle(mNewTitle); }