android - studio - fuentes para tarjetas
¿Cómo configurar tipos de letra personalizados para elementos en NavigationView? (15)
¿Hay una manera de hacerlo?
Si.
NavigationView
no proporciona una forma directa de manejar esto, pero se puede lograr fácilmente usando
View.findViewsWithText
.
Hay dos cosas que nos ayudarán a manejar esto.
-
Cada vista de
MenuItem
es unTextView
. Entonces, eso hace que aplicar tuTypeface
sea mucho más fácil. Para obtener más información sobreTextView
realmente utilizado porNavigationView
, consulteNavigationMenuItemView
. -
NavigationView
proporciona una devolución de llamada cuando se selecciona un elemento deMenuItem
. Tendremos que proporcionar a cadaMenuItem
una identificación única y esta devolución de llamada ayudará a generar esos identificadores tanto como sea posible, lo que significa un poco menos de código más adelante. Aunque, esto está más relacionado con si tiene o no unSubMenu
.
Implementación
Observe que cada ID de
MenuItem
es simplemente
menuItem+Position
.
Esto será útil más adelante cuando encontremos la
View
para cada elemento de
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);
}
}
});
}
Puede ver cómo el uso de un ID genérico de
MenuItem
permite utilizar
Resources.getIdentifier
y guardar algunas líneas de código.
Advertencia de
SubMenu
Algo para tener en cuenta.
Menu.size
explícitamente sus
N
elementos de menú en lugar de usar
Menu.size
.
De lo contrario, sus elementos
SubMenu
no serán reconocidos.
En otras palabras, si no tiene un
SubMenu
, otra forma de hacerlo sería:
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);
}
Y no tiene que preocuparse por aplicar una identificación única a cada elemento de
MenuItem
.
Resultados
La fuente que estoy usando en el ejemplo es: Smoothie Shoppe
Con el nuevo
NavigationView
, podemos configurar los elementos de un cajón a través de un recurso de menú en XML.
Con eso, podemos configurar cada elemento con algo como
<item
android:id="@+id/drawer_my_account"
android:icon="@drawable/ic_my_account"
android:title="@string/drawer_my_account" />
Pero ahora, quiero establecer un tipo de letra personalizado para cada uno de esos elementos en mi cajón, y no pude encontrar una manera de hacerlo, ya sea por XML o por código Java. ¿Hay una manera de hacerlo?
Es un poco tarde para responder, pero encontré una forma más limpia de hacerlo, así que me gustaría compartir.
-
Haga una vista personalizada
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); } }
-
Cree un archivo llamado
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://.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); } } }
-
Haga un diseño de
layout/design_navigation_item.xml
(el nombre debe ser exactamente el mismo):<?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" />
-
Coloque su archivo de fuente
SourceSansPro-Bold.ttf
en esta ruta:app/src/main/assets/fonts/SourceSansPro-Bold.ttf
¡Eres bueno para ir! De esta manera, puede mantener su actividad principal más limpia.
Este es otro enfoque:
Un NavigationView tiene hijos llamados NavigationMenuItemView . NavigationMenuItemView tiene dos hijos. Uno es AppCompatCheckedTextView .
Anule el método onLayout de NavigationView como se Typefase continuación y cambie 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);
}
}
}
}
He refactorizado la respuesta de @ adneal a esto. Recorre los elementos del menú (sin entrar en elementos secundarios, solo elementos de nivel superior) según el índice en lugar de la identificación y establece el Tipo de letra.
Reemplace rightNavigationView con su NavigationView y {TYPEFACE} con su TypeFace deseado
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);
}
}
});
He usado la aplicación: tema
<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>
No es un tipo de letra personalizado, sino otra forma de cambiar la fuente de los elementos de navegación.
Cree un diseño llamado
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" />
Luego cambie la fontFamily a la fuente deseada.
Realmente me encantó la solución de "Dragón que escupe fuego", pero no
textview
la vista de
textview
.
Esto podría hacerse haciendo lo siguiente:
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>
Una forma diferente de configurar su fuente personalizada:
1. Puede agregar sus fuentes en una carpeta de "fuentes", y luego puede usarlas en cualquier TextView (o donde lo necesite)
Un ejemplo 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. En su archivo styles.xml, puede personalizar el estilo de texto de su elemento con esa fuente y color, donde lo necesite (de la respuesta de @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. Ahora, solo tiene que especificar esto en su vista de navegación con 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"/>
// ------------- Además, si necesita usar esta fuente de otras TextViews, puede usarla como
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/nunito_bold"/>
Utilice la aplicación: itemTextAppearance = "" propiedad. Espero que esto ayude.
<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">
En styles.xml escribe
<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>
agregue el archivo de fuente en la carpeta res / font / para agrupar las fuentes como recursos
entonces
Puede cambiarlo utilizando recursos de estilo. En tu styles.xml:
<style name="Widget.BottomNavigationView"
parent="Widget.Design.BottomNavigationView">
<item name="fontFamily">@font/your_font</item>
</style>
Luego aplíquelo como tema en su vista:
<android.support.design.widget.BottomNavigationView
...
android:theme="@style/Widget.BottomNavigationView"
/>
esta trabajando para 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-> valores-> estilos
<style name="NavigationDrawerStyle">
<item name="android:textSize">18sp</item>
<item name="android:typeface">monospace</item>
</style>
// para configurar el tipo de letra personalizado 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();
}
}
}
para aquellos que usan la respuesta @Moinkhan, para aplicar la fuente a cada parte de sus menús, use esa solución y para cada sección de encabezado use id. tu menú así ...
<item android:title="@string/others" android:id="@+id/nav_others">
<menu>
<item
android:id="@+id/contact"
android:title="@string/contact"/>
</menu>
</item>
y una solución como esta ...
navMenu = navView.getMenu();
MenuItem item= navView.getMenu().findItem(R.id.nav_others);
applyFontToMenuItem(item);
Tal vez ayude a alguien.
simplemente agregue el siguiente archivo de clase a su proyecto.
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);
}
}
luego cree el siguiente método para su actividad
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);
}
y llamarlo desde la actividad.
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);
}
y aquí está mi salida
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);
}
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);
}