Avec la nouvelle NavigationView
, nous sommes en mesure de définir les éléments d'un tiroir via une ressource de menu au format XML.
Avec cela, nous pouvons définir chaque élément avec quelque chose comme
<item
Android:id="@+id/drawer_my_account"
Android:icon="@drawable/ic_my_account"
Android:title="@string/drawer_my_account" />
Mais maintenant, je veux définir une police de caractères personnalisée pour chacun de ces éléments dans mon tiroir, et je ne pouvais pas trouver un moyen de le faire, ni par XML ni par du code Java. Y a-t-il un moyen de le faire?
ajoutez simplement le fichier de classe suivant à votre projet.
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);
}
}
puis créez la méthode suivante pour votre activité
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);
}
et appelez-le de l'activité.
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);
}
et voici ma sortie
celui-ci travaille pour moi
<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-> valeurs-> styles
<style name="NavigationDrawerStyle">
<item name="Android:textSize">18sp</item>
<item name="Android:typeface">monospace</item>
</style>
// pour définir une police de caractères personnalisée 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();
}
}
}
Utilisez leapp: itemTextAppearance = ""property . J'espère que cela vous aidera.
<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">
Dans styles.xml, écrivez
<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>
Y a-t-il un moyen de le faire?
Oui. La NavigationView
ne fournit pas un moyen direct de gérer cela, mais elle peut être facilement réalisée avec View.findViewsWithText
.
Deux choses nous aideront à gérer cela.
MenuItem
est une TextView
. Cela facilite donc beaucoup l'application de votre Typeface
. Pour plus d'informations sur la TextView
réellement utilisée par NavigationView
, voir NavigationMenuItemView
. NavigationView
fournit un rappel quand une MenuItem
est sélectionnée. Nous allons devoir fournir à chaque MenuItem
un identifiant unique. Ce rappel aidera à générer ces identifiants autant que possible, ce qui signifie un peu moins de code par la suite. Bien que cela soit davantage lié au fait que vous ayez ou non une SubMenu
.La mise en oeuvre
Notez que chaque ID MenuItem
est simplement menuItem+Position
. Cela nous sera utile plus tard, lorsque nous aurons trouvé la View
pour chaque 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);
}
}
});
}
Vous pouvez voir comment l’utilisation d’un identifiant MenuItem
générique vous permet d’utiliser Resources.getIdentifier
et d’économiser quelques lignes de code.
SubMenu
mise en garde
Quelque chose à garder à l'esprit. Vous devez explicitement boucler sur vos éléments de menu N
plutôt que d'utiliser Menu.size
. Sinon, vos éléments SubMenu
ne seront pas reconnus. En d'autres termes, si vous n'avez pas de SubMenu
, une autre façon de procéder serait:
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);
}
Et vous n'avez pas à vous soucier d'appliquer un identifiant unique à chaque MenuItem
.
Résultats
La police que j'utilise dans l'exemple est la suivante: Smoothie Shoppe
J'ai utilisé app: theme
<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"
/>
Styles.xml:
<style name="NavigationViewTextAppearance">
<item name="Android:ellipsize">end</item>
<item name="Android:fontFamily">@font/badscript_regular</item>
</style>
C'est un peu tard pour répondre mais j'ai trouvé une façon plus propre de le faire, alors j'aimerais partager.
Créer une vue personnalisée 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);
}
}
Créez un fichier appelé 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);
}
}
}
Créez un layout layout/design_navigation_item.xml
(le nom doit être exactement le même):
<?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" />
Placez votre fichier de police SourceSansPro-Bold.ttf
dans ce chemin: app/src/main/assets/fonts/SourceSansPro-Bold.ttf
Vous êtes prêt à partir! De cette façon, vous pouvez garder votre activité principale plus propre.
Pas une police de caractères personnalisée, mais un autre moyen de changer la police des éléments de navigation. Créez une mise en page nommée 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" />
Puis changez la police fontFamily en la police souhaitée.
pour ceux qui utilisent @Moinkhan answer, pour appliquer la police à chaque partie de vos menus, utilisez cette solution et pour chaque section d'en-tête, utilisez id .
<item Android:title="@string/others" Android:id="@+id/nav_others">
<menu>
<item
Android:id="@+id/contact"
Android:title="@string/contact"/>
</menu>
</item>
et solution comme ça ..
navMenu = navView.getMenu();
MenuItem item= navView.getMenu().findItem(R.id.nav_others);
applyFontToMenuItem(item);
peut-être que ça aide quelqu'un.
J'ai vraiment adoré la solution de "Dragon qui crache du feu" mais je n'ai pas eu le textview
. Cela pourrait être fait en procédant comme suit:
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>
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ProjectView">
<attr name="projectFont" format="string" />
</declare-styleable>
</resources>
J'ai refactored @ adneal's répondre à cela. Il boucle sur les éléments de menu (sans entrer dans les sous-éléments, mais uniquement les éléments de niveau supérieur) en fonction de l'index au lieu de l'id et définit le type de caractère.
RemplacezrightNavigationViewpar votre NavigationView et{TYPEFACE}par votre TypeFace souhaité.
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);
}
}
});
Une autre façon de définir votre police personnalisée:
1. Vous pouvez ajouter vos polices dans un dossier "police", puis les utiliser dans n’importe quel TextView (ou là où vous en avez besoin).
Un exemple de font.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. Dans votre fichier styles.xml, vous pouvez personnaliser le style de texte de votre article avec cette police et cette couleur, où vous le souhaitez (à partir de @Moonis Abidi answer)
<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. Maintenant, il vous suffit de spécifier ceci dans votre vue de navigation avec 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"
app:menu="@menu/main_menu"
app:itemTextAppearance="@style/NavigationText"/>
// ------------- En outre, si vous devez utiliser cette police à partir d'autres TextViews, vous pouvez l'utiliser comme
<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);
}
C'est une autre approche:
Un NavigationView a des enfants appelés NavigationMenuItemView. Un NavigationMenuItemView a deux enfants. On est AppCompatCheckedTextView.
Remplacer la méthode onLayout de NavigationView comme ci-dessous et changer Typefase de 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);
}
}
}
}
ajoutez le fichier de police dans le dossier res/font/pour regrouper les polices en tant que ressources
puis
Vous pouvez le changer en utilisant des ressources de style. Dans votre styles.xml:
<style name="Widget.BottomNavigationView"
parent="Widget.Design.BottomNavigationView">
<item name="fontFamily">@font/your_font</item>
</style>
Puis appliquez-le comme thème dans votre vue:
<Android.support.design.widget.BottomNavigationView
...
Android:theme="@style/Widget.BottomNavigationView"
/>