Android 如何为NavigationView中的项目设置自定义字体?
使用新的Android 如何为NavigationView中的项目设置自定义字体?,android,android-design-library,navigationview,Android,Android Design Library,Navigationview,使用新的导航视图,我们可以通过XML中的菜单资源设置抽屉中的项目 有了它,我们可以将每个项目设置为 <item android:id="@+id/drawer_my_account" android:icon="@drawable/ic_my_account" android:title="@string/drawer_my_account" /> 但现在,我想为抽屉中的每一项设置一个自定义字体,但我找不到一种方法,不管是通过XML还是Java代码。有办法吗 有办法
导航视图
,我们可以通过XML中的菜单资源设置抽屉中的项目
有了它,我们可以将每个项目设置为
<item
android:id="@+id/drawer_my_account"
android:icon="@drawable/ic_my_account"
android:title="@string/drawer_my_account" />
但现在,我想为抽屉中的每一项设置一个自定义字体,但我找不到一种方法,不管是通过XML还是Java代码。有办法吗
有办法吗
对。虽然没有提供一种直接的处理方法,但是可以使用
有两件事可以帮助我们解决这个问题
MenuItem
视图都是TextView
。因此,这使得应用字体
变得更加容易。有关导航视图实际使用的文本视图
的更多信息,请参阅李>
NavigationView
当选择MenuItem
时。我们必须为每个MenuItem
提供一个唯一的id,这个回调将尽可能多地帮助生成这些id,这意味着以后代码会少一些。尽管如此,这与您是否有子菜单有关
实施
请注意,每个MenuItem
id只是MenuItem+Position
。稍后,当我们为每个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>
您不必担心对每个菜单项应用唯一的id
<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>
结果
我在示例中使用的字体是:只需将以下类文件添加到项目中即可
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);
}
navView=(NavigationView)findviewbyd(R.id.navView);
Menu m=navView.getMenu();
对于(int i=0;i0){
对于(int j=0;j不是自定义字体,而是更改导航项字体的另一种方式。创建名为design\u navigation\u 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更改为所需字体。对于使用@Moinkhan answer的用户,对于将字体应用到菜单的每个部分,请使用该解决方案,对于每个标题部分,请使用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);
也许它对某人有帮助。这个对我有用
<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>
//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();
}
}
}
现在回答有点晚,但我找到了一个更干净的方法,所以我想与大家分享
- 创建自定义视图
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\u navigation\u item.xml
(名称必须完全相同):
- 将字体文件
SourceSansPro Bold.ttf
放在以下路径中:app/src/main/assets/fonts/SourceSansPro Bold.ttf
你可以走了!这样,你可以保持你的主要活动更干净
以下是一个屏幕截图:
我非常喜欢“喷火龙”的解决方案,但我没有得到文本视图
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"?>
style.xml:
<style name="Body1" parent="Base.TextAppearance.AppCompat.Body1">
<item name="projectFont">Quicksand-Regular.otf</item>
</style>
Quicksand-Regular.otf
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ProjectView">
<attr name="projectFont" format="string" />
</declare-styleable>
</resources>
我已经重构了@adneal对此的回答。它根据索引(而不是id)循环菜单项(不进入子项,只有顶级项),并设置字体
用导航视图替换rightNavigationView,用所需字体替换{TYPEFACE}
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);
}
}
});
final Menu navMenu=rightNavigationView.getMenu();
rightNavigationView.getViewTreeObserver().addOnGlobalLayoutListener(新ViewTreeObserver.OnGlobalLayoutListener()){
@凌驾
公共图书馆{
ArrayList menuItems=新建ArrayList();//在此数组中保存视图
rightNavigationView.getViewTreeObserver()
for(int i=0;i
使用应用程序: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">
在styles.xml中编写
<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>
@彩色/彩色白色
12便士
无衬线薄
这是另一种方法:
具有名为NavigationMenuItemView的子项。NavigationMenuItemView具有两个子项。一个子项为
覆盖导航视图的onLayout方法,如下图和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);
}
}
}
}
public final class NavigationView with CustomFont扩展了NavigationView{
私人最终语境;
私人字体字体;
带有自定义字体的公共导航视图(上下文、属性集属性){
超级(上下文,attrs);
this.context=上下文;
this.fontFace=null;
}
@凌驾
仅限受保护的空心布局(布尔值已更改、整数左侧、整数顶部、整数右侧、整数底部){
超级。仅限布局(已更改、左、上、右、下);
最终视图组navMenuView=(视图组)getChildAt(0);
final int NavMenuItemScont=navMenuView.getChildCount();
视图组项目视图;
如果(fontFace==null){
fontFace=Typeface.createFromAsset(context.getAssets(),context.getString(R.string.BTrafficBold));
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);
}
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);
}
}
});
<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">
<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>
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);
}
}
}
}
<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"
/>
<style name="NavigationViewTextAppearance">
<item name="android:ellipsize">end</item>
<item name="android:fontFamily">@font/badscript_regular</item>
</style>
<?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>
<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>
<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"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/nunito_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);
}
<style name="Widget.BottomNavigationView"
parent="Widget.Design.BottomNavigationView">
<item name="fontFamily">@font/your_font</item>
</style>
<android.support.design.widget.BottomNavigationView
...
android:theme="@style/Widget.BottomNavigationView"
/>