Changer la police du texte de l'onglet dans le support de conception Android TabLayout


109

J'essaie de travailler sur le nouveau TabLayoutde la bibliothèque de conception Android.

Je veux changer le texte de l'onglet en police personnalisée . Et, j'ai essayé de chercher un peu de style lié à TabLayout, mais a fini jusqu'à ce .

Veuillez indiquer comment modifier les polices du texte des onglets.


3
Use Spannable String
NullByte

Réponses:


37

Créez un TextView à partir de Java Code ou XML comme celui-ci

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:textSize="15sp"
    android:textColor="@color/tabs_default_color"
    android:gravity="center"
    android:layout_height="match_parent"
/>

Assurez-vous de conserver l'ID tel qu'il est ici car le TabLayout vérifie cet ID si vous utilisez une vue de texte personnalisée

Ensuite, à partir du code, gonflez cette mise en page et définissez la personnalisation Typefacesur cette vue de texte et ajoutez cette vue personnalisée à l'onglet

for (int i = 0; i < tabLayout.getTabCount(); i++) {
     //noinspection ConstantConditions
     TextView tv = (TextView)LayoutInflater.from(this).inflate(R.layout.custom_tab,null)
     tv.setTypeface(Typeface);       
     tabLayout.getTabAt(i).setCustomView(tv);
}

2
Comment puis-je définir tabTextColoret tabSelectedTextColorpropriété dans cette situation?
Alireza Noorali


162

Si vous utilisez TabLayoutet que vous souhaitez changer la police, vous devez ajouter une nouvelle boucle for à la solution précédente comme ceci:

private void changeTabsFont() {
    ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
        int tabsCount = vg.getChildCount();
        for (int j = 0; j < tabsCount; j++) {
            ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
            int tabChildsCount = vgTab.getChildCount();
            for (int i = 0; i < tabChildsCount; i++) {
                View tabViewChild = vgTab.getChildAt(i);
                if (tabViewChild instanceof TextView) {
                    ((TextView) tabViewChild).setTypeface(Font.getInstance().getTypeFace(), Typeface.NORMAL);
                }
        }
    }
} 

Veuillez vous référer au changement de style de police dans les onglets de la barre d'action à l'aide de Sherlock


Je n'utilise pas l'aperçu M. Y a-t-il un autre moyen de le faire.
Dory

1
Vous n'avez pas besoin de l'aperçu M, il est valable pour tous les utilisateursTabLayout
Mario Velasco

Cependant, je rencontre une exception NullPointerException sur android.view.View android.support.design.widget.TabLayout.getChildAt (int), pouvez-vous m'aider à le résoudre? Impossible de trouver ce que je manque dans mon code.
brettbrdls

1
Le premier paramètre de setTypeFaceest a TypeFace, au cas où vous ne trouvez pas la Fontclasse (qui ne semble pas exister pour moi)
Vahid Amiri

104

Créez votre propre style personnalisé et utilisez le style parent comme parent="@android:style/TextAppearance.Widget.TabWidget"

Et dans la mise en page de votre onglet, utilisez ce style comme app:tabTextAppearance="@style/tab_text"

Exemple: Style:

<style name="tab_text" parent="@android:style/TextAppearance.Widget.TabWidget">
    <item name="android:fontFamily">@font/poppins_regular</item>
</style>

Exemple: composant de mise en page des onglets:

<android.support.design.widget.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:tabTextAppearance="@style/tab_text" />

9
C'est correct, j'utilise parent="TextAppearance.Design.Tab"dans mon cas.
Javatar

1
Cela fonctionne beaucoup mieux que les premières réponses, et sans magie noire (api cachée), qui pourrait casser quelque chose à l'avenir
Sulfkain

2
il suffit de travailler lorsque vous utilisez fontFamily, ne fonctionne pas lorsque vous utilisez fontPath
Tram Nguyen

2
J'obtenais des exceptions étranges de manière erratique lors de l'utilisation TextAppearance.Widget.TabWidget. La réponse de @Javatar l'a corrigé pour moi.
funct7

47

Excellente réponse de praveen Sharma. Juste un petit ajout: au lieu d'utiliser changeTabsFont()partout où vous avez besoin TabLayout, vous pouvez simplement utiliser le vôtre CustomTabLayout.

import android.content.Context;
import android.graphics.Typeface;
import android.support.design.widget.TabLayout;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class CustomTabLayout extends TabLayout {
    private Typeface mTypeface;

    public CustomTabLayout(Context context) {
        super(context);
        init();
    }

    public CustomTabLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Regular.ttf");
    }

    @Override
    public void addTab(Tab tab) {
        super.addTab(tab);

        ViewGroup mainView = (ViewGroup) getChildAt(0);
        ViewGroup tabView = (ViewGroup) mainView.getChildAt(tab.getPosition());

        int tabChildCount = tabView.getChildCount();
        for (int i = 0; i < tabChildCount; i++) {
            View tabViewChild = tabView.getChildAt(i);
            if (tabViewChild instanceof TextView) {
                ((TextView) tabViewChild).setTypeface(mTypeface, Typeface.NORMAL);
            }
        }
    }

}

Et encore une chose. TabViewest un LinearLayoutavec à l' TextViewintérieur (il peut aussi éventuellement contenir ImageView). Ainsi, vous pouvez rendre le code encore plus simple:

@Override
public void addTab(Tab tab) {
    super.addTab(tab);

    ViewGroup mainView = (ViewGroup) getChildAt(0);
    ViewGroup tabView = (ViewGroup) mainView.getChildAt(tab.getPosition());
    View tabViewChild = tabView.getChildAt(1);
    ((TextView) tabViewChild).setTypeface(mTypeface, Typeface.NORMAL);
}

Mais je ne recommanderais pas cette façon. Si l' TabLayoutimplémentation change, ce code peut ne pas fonctionner correctement ou même planter.

Une autre façon de personnaliser TabLayoutconsiste à ajouter une vue personnalisée. Voici le bon exemple .


addTab ne sera pas appelé si vous définissez des onglets comme celui-ci: mViewPager.setAdapter (new YourPagerAdapter (getChildFragmentManager ())); mTabLayout.setupWithViewPager (mViewPager);
Penzzz

2
@Penzzz vous avez absolument raison. Dans ce cas, vous devez déplacer le code de la méthode addTab vers une autre. Par exemple onMeasure.
Andrei Aulaska

@AndreiAulaska thnx Vous sauvez ma journée. Votre dernier lien me sauve.
Amol Dale

cela ne fonctionne plus je pense dans la dernière version. La réponse de @ ejw fonctionne maintenant. besoin de l'ajouter dans addTab (Tab tab, boolean setSelected)
Sayem

3
Cela fonctionne bien. REMARQUE: à partir de la bibliothèque de support 25.x, vous devez remplacer addTab(Tab tab, int position, boolean setSelected)au lieu de addTab(Tab tab).
Vicky Chijwani

20

Pour utiliser la prise en charge des polices dans la XMLfonctionnalité sur les appareils exécutant Android 4.1(niveau d'API 16) et supérieur, utilisez la bibliothèque de support 26+.

  1. Cliquez avec le bouton droit sur le dossier res
  2. Nouveau -> répertoire de ressources Android-> sélectionnez la police -> Ok
  3. Placez votre myfont.ttffichier dans le dossier de polices nouvellement créé

Sur res/values/styles.xmlajouter:

<style name="customfontstyle" parent="@android:style/TextAppearance.Small">
    <item name="android:fontFamily">@font/myfont</item>
</style>

Sur le fichier de mise en page, ajoutez l'application: tabTextAppearance = "@ style / customfontstyle",

<android.support.design.widget.TabLayout
    android:id="@+id/tabs"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:tabGravity="fill"
    app:tabTextAppearance="@style/customfontstyle"
    app:tabMode="fixed" />

Veuillez vous référer à [fonts in xml]. ( Https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml )


cela fonctionne sur les formulaires xamarin et xamarin android.thanks
Esmail Jamshidiasl

Très bonne réponse! Devrait étendre "TextAppearance.Design.Tab" cependant
XY

16

La méthode suivante changera la police en entier de ViewGroupmanière récursive. J'ai choisi cette méthode parce que vous n'avez pas à vous soucier de la structure interne de TabLayout. J'utilise la bibliothèque de calligraphie pour définir une police.

void changeFontInViewGroup(ViewGroup viewGroup, String fontPath) {
    for (int i = 0; i < viewGroup.getChildCount(); i++) {
        View child = viewGroup.getChildAt(i);
        if (TextView.class.isAssignableFrom(child.getClass())) {
            CalligraphyUtils.applyFontToTextView(child.getContext(), (TextView) child, fontPath);
        } else if (ViewGroup.class.isAssignableFrom(child.getClass())) {
            changeFontInViewGroup((ViewGroup) viewGroup.getChildAt(i), fontPath);
        }
    }
}

1
problème avec ceci est que si vous attachez la mise en page à un Viewpager, vous perdrez les polices personnalisées.
rupps

10

Pour la prise en charge de la conception 23.2.0, à l'aide de setupWithViewPager, vous devrez déplacer le code de addTab (onglet Tab) vers addTab (onglet Tab, booléen setSelected).


8

Vous pouvez utiliser ceci, cela fonctionne pour moi.

 private void changeTabsFont() {
    ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
    int tabsCount = vg.getChildCount();
    for (int j = 0; j < tabsCount; j++) {
        ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
        int tabChildsCount = vgTab.getChildCount();
        for (int i = 0; i < tabChildsCount; i++) {
            View tabViewChild = vgTab.getChildAt(i);
            if (tabViewChild instanceof TextView) {
                AssetManager mgr = getActivity().getAssets();
                Typeface tf = Typeface.createFromAsset(mgr, "fonts/Roboto-Regular.ttf");//Font file in /assets
                ((TextView) tabViewChild).setTypeface(tf);
            }
        }
    }
}

7

Eh bien, je l'ai trouvé simple dans 23.4.0 sans utiliser de boucle. Remplacez simplement addTab (onglet @NonNull Tab, booléen setSelected) comme suggéré par @ejw.

@Override
public void addTab(@NonNull Tab tab, boolean setSelected) {
    CoralBoldTextView coralTabView = (CoralBoldTextView) View.inflate(getContext(), R.layout.coral_tab_layout_view, null);
    coralTabView.setText(tab.getText());
    tab.setCustomView(coralTabView);

    super.addTab(tab, setSelected);
}

Et voici le XML

<?xml version="1.0" encoding="utf-8"?>
<id.co.coralshop.skyfish.ui.CoralBoldTextView
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/custom_text"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:ellipsize="end"
   android:gravity="center"
   android:singleLine="true"
   android:textColor="@color/graylove"
   android:textSize="@dimen/tab_text_size" />

J'espère que cela pourrait aider :)


1
Mais comment définir tabSelectedTextColor et tabTextColo?
Mostafa Imran

@MostafaImran votre version de android:textColor="@color/graylove"devrait avoir le sélecteur de liste d'état pour celui avec la couleur state_selected spécifiée
AA_PV

7

Comme Andrei a répondu, vous pouvez changer la police en étendant la classe TabLayout . Et comme Penzzz l'a dit, vous ne pouvez pas le faire avec la méthode addTab . Remplacez la méthode onLayout comme ci-dessous:

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom){
    super.onLayout(changed, left, top, right, bottom);

    final ViewGroup tabStrip = (ViewGroup)getChildAt(0);
    final int tabCount = tabStrip.getChildCount();
    ViewGroup tabView;
    int tabChildCount;
    View tabViewChild;

    for(int i=0; i<tabCount; i++){
        tabView = (ViewGroup)tabStrip.getChildAt(i);
        tabChildCount = tabView.getChildCount();
        for(int j=0; j<tabChildCount; j++){
            tabViewChild = tabView.getChildAt(j);
            if(tabViewChild instanceof AppCompatTextView){
                if(fontFace == null){
                    fontFace = Typeface.createFromAsset(context.getAssets(), context.getString(R.string.IranSans));
                }
                ((TextView) tabViewChild).setTypeface(fontFace, Typeface.BOLD);
            }
        }
    }
}

Doit remplacer la méthode onLayout, car, lorsque vous utilisez la méthode setupWithViewPager pour lier le TabLayout avec le ViewPager, vous devez définir le texte des tabulations soit avec la méthode setText, soit dans le PagerAdapter après cela et lorsque cela se produit, la méthode onLayout est appelée sur le ViewGroup parent ( TabLayout) et c'est l'endroit où mettre le paramètre fontface. (La modification d'un texte TextView provoque l'appel de la méthode onLayout de son parent - Un tabView a deux enfants, l'un est ImageView et l'autre TextView)

Une autre solution:

Tout d'abord, ces lignes de code:

    if(fontFace == null){
        fontFace = Typeface.createFromAsset(context.getAssets(), context.getString(R.string.IranSans));
    }

Dans la solution ci-dessus, doit être écrit en dehors de deux boucles.

Mais une meilleure solution pour l' API> = 16 utilise android: fontFamily :

Créez un répertoire de ressources Android nommé police et copiez la police souhaitée dans le répertoire.

Ensuite, utilisez ces styles:

<style name="tabLayoutTitles">
    <item name="android:textColor">@color/white</item>
    <item name="android:textSize">@dimen/appFirstFontSize</item>
    <item name="android:fontFamily">@font/vazir_bold</item>
</style>

<style name="defaultTabLayout">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">@dimen/defaultTabLayoutHeight</item>
    <item name="android:gravity">right</item>
    <item name="tabTextAppearance">@style/tabLayoutTitles</item>
    <item name="tabSelectedTextColor">@color/white</item>
    <item name="tabIndicatorColor">@color/white</item>
    <item name="tabIndicatorHeight">@dimen/accomTabIndicatorHeight</item>
    <item name="tabMode">fixed</item>
    <item name="tabGravity">fill</item>
    <item name="tabBackground">@drawable/rectangle_white_ripple</item>
    <item name="android:background">@color/colorPrimary</item>
</style>

Il s'agit d'un correctif de mauvaise performance, onLayout()appelé à chaque changement de mise en page comme le changement d'onglet ou même le défilement de la liste sous les onglets, avec des fors imbriqués dans de nombreux onglets, l' TabLayoutapplication sera retardée.
Amr Barakat

2
@Amr Barakat. D'après ce lien: developer.android.com/reference/android/view/… , int, int, int, int), ce n'est pas vrai. Je l'ai testé aussi. J'ai mis un point d' arrêt dans la méthode onLayout et il est appelé lorsque les onglets sont créés et non sur le changement d'onglet ou le défilement de la liste.
Arash

1
Pour moi, je suis onLayout()appelé plusieurs fois lors du changement d'onglet (je ne sais pas pourquoi exactement), mais pour en tenir compte, je ne définis les polices que lorsque le boolean changedest vrai. Cela empêche de définir les polices plusieurs fois.
Robert

excellente solution, aucun code requis, seulement des attributs xml
Attention7j

3

Ma méthode Resolve comme ceci, changez le texte de l'onglet spécifié,

 ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
 ViewGroup vgTab = (ViewGroup) vg.getChildAt(1);
 View tabViewChild = vgTab.getChildAt(1);
 if (tabViewChild instanceof TextView) {
      ((TextView) tabViewChild).setText(str);
 }

2
I think this is easier way.

<android.support.design.widget.TabLayout
   android:id="@+id/tabs"
   app:tabTextColor="@color/lightPrimary"
   app:tabSelectedTextColor="@color/white"
   style="@style/CustomTabLayout"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"/>
<style name="CustomTabLayout" parent="Widget.Design.TabLayout">
   <item name="tabMaxWidth">20dp</item>
   <item name="tabMode">scrollable</item>
   <item name="tabIndicatorColor">?attr/colorAccent</item>
   <item name="tabIndicatorHeight">2dp</item>
   <item name="tabPaddingStart">12dp</item>
   <item name="tabPaddingEnd">12dp</item>
   <item name="tabBackground">?attr/selectableItemBackground</item>
   <item name="tabTextAppearance">@style/CustomTabTextAppearance</item>
   <item name="tabSelectedTextColor">?android:textColorPrimary</item>
</style>
<style name="CustomTabTextAppearance" parent="TextAppearance.Design.Tab">
   <item name="android:textSize">16sp</item>
   <item name="android:textStyle">bold</item>
   <item name="android:textColor">?android:textColorSecondary</item>
   <item name="textAllCaps">false</item>
</style>

2

Extension Kotlin qui a fonctionné pour moi:

fun TabLayout.setFont(font: FontUtils.Fonts) {
    val vg = this.getChildAt(0) as ViewGroup
    for (i: Int in 0..vg.childCount) {
        val vgTab = vg.getChildAt(i) as ViewGroup?
        vgTab?.let {
            for (j: Int in 0..vgTab.childCount) {
                val tab = vgTab.getChildAt(j)
                if (tab is TextView) {
                    tab.typeface = FontUtils.getTypeFaceByFont(FontUtils.Fonts.BOLD, context)
                }
            }
        }
    }
}

1

Mon 2p, Kotlin avec vérification des références, applicable partout car il s'arrêtera si quelque chose ne va pas.

private fun setTabLayouFont(tabLayout: TabLayout) {
    val viewGroupTabLayout = tabLayout.getChildAt(0) as? ViewGroup?
    (0 until (viewGroupTabLayout?.childCount ?: return))
            .map { viewGroupTabLayout.getChildAt(it) as? ViewGroup? }
            .forEach { viewGroupTabItem ->
                (0 until (viewGroupTabItem?.childCount ?: return))
                        .mapNotNull { viewGroupTabItem.getChildAt(it) as? TextView }
                        .forEach { applyDefaultFontToTextView(it) }
            }
}

1

Et voici mon implémentation dans Kotlin qui permet également de changer de police pour les onglets sélectionnés et non sélectionnés.

class FontTabLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    @AttrRes defStyleAttr: Int = 0
) : TabLayout(context, attrs, defStyleAttr) {

    private var textSize = 14f

    private var defaultSelectedPosition = 0

    private var selectedTypeFace: Typeface? = ResourcesCompat.getFont(context, R.font.muli_bold)
    private var normalTypeFace: Typeface? = ResourcesCompat.getFont(context, R.font.muli_regular)

    @ColorInt private var selectedColor = 0
    @ColorInt private var normalTextColor = 0

    init {
        attrs?.let { initAttrs(it) }
        addOnTabSelectedListener()
    }

    private fun initAttrs(attrs: AttributeSet) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.FontTabLayout)

        textSize = a.getDimensionPixelSize(R.styleable.FontTabLayout_textSize, 14).toFloat()

        defaultSelectedPosition = a.getInteger(R.styleable.FontTabLayout_defaultSelectedPosition, 0)
        val selectedResourceId = a.getResourceId(R.styleable.FontTabLayout_selectedTypeFace, R.font.muli_bold)
        val normalResourceId = a.getResourceId(R.styleable.FontTabLayout_normalTypeFace, R.font.muli_regular)

        selectedColor = a.getColor(com.google.android.material.R.styleable.TabLayout_tabSelectedTextColor, 0)
        normalTextColor = a.getColor(R.styleable.FontTabLayout_normalTextColor, 0)

        selectedTypeFace = ResourcesCompat.getFont(context, selectedResourceId)
        normalTypeFace = ResourcesCompat.getFont(context, normalResourceId)

        a.recycle()
    }

    private fun addOnTabSelectedListener() {
        addOnTabSelectedListener(object : OnTabSelectedListenerAdapter() {

            override fun onTabUnselected(tab: Tab?) {
                getCustomViewFromTab(tab)?.apply {
                    setTextColor(normalTextColor)
                    typeface = normalTypeFace
                }
            }

            override fun onTabSelected(tab: Tab?) {

                getCustomViewFromTab(tab)?.apply {
                    setTextColor(selectedColor)
                    typeface = selectedTypeFace
                }
            }

            private fun getCustomViewFromTab(tab: Tab?) = tab?.customView as? AppCompatTextView

        })
    }

    override fun setupWithViewPager(viewPager: ViewPager?, autoRefresh: Boolean) {
        super.setupWithViewPager(viewPager, autoRefresh)
        addViews(viewPager)
    }

    private fun addViews(viewPager: ViewPager?) {
        for (i in 0 until tabCount) {
            val customTabView = getCustomTabView(i).apply {
                typeface = if (i == defaultSelectedPosition) selectedTypeFace else normalTypeFace
                val color = if (i == defaultSelectedPosition) selectedColor else normalTextColor
                setTextColor(color)
                text = viewPager?.adapter?.getPageTitle(i)
            }

            getTabAt(i)?.customView = customTabView
        }
    }

    private fun getCustomTabView(position: Int): AppCompatTextView {
        return AppCompatTextView(context).apply {
            gravity = Gravity.CENTER
            textSize = this@FontTabLayout.textSize
            text = position.toString()
        }
    }
}

dans attrs.xml:

<declare-styleable name="FontTabLayout">
    <attr name="normalTextColor" format="reference|color" />
    <attr name="textSize" format="dimension" />
    <attr name="defaultSelectedPosition" format="integer" />
    <attr name="selectedTypeFace" format="reference" />
    <attr name="normalTypeFace" format="reference" />
</declare-styleable>

tabs.getTabAt (1)?. text ne modifie pas le texte dynamiquement, une fois défini.
shanraisshan

0

Avec les fonctions d'extension kotlin, utilisez ceci:

 fun TabLayout.setFontSizeAndColor(typeface: Typeface, @DimenRes textSize: Int, @ColorRes textColor: Int) {
val viewGroup: ViewGroup = this.getChildAt(0) as ViewGroup
val tabsCount: Int = viewGroup.childCount
for (j in 0 until tabsCount) {
    val viewGroupTab: ViewGroup = viewGroup.getChildAt(j) as ViewGroup
    val tabChildCount: Int = viewGroupTab.childCount
    for (i in 0 until tabChildCount) {
        val tabViewChild: View = viewGroupTab.getChildAt(i) as View
        if ( tabViewChild is TextView) {
            tabViewChild.typeface = typeface
            tabViewChild.gravity = Gravity.FILL
            tabViewChild.maxLines = 1
            tabViewChild.setTextSize(TypedValue.COMPLEX_UNIT_PX, this.resources.getDimension(textSize))
            tabViewChild.setTextColor(ContextCompat.getColor(this.context, textColor))
        }
    }
}

}


-2

Changement

if (tabViewChild instanceof TextView) {

pour

if (tabViewChild instanceof AppCompatTextView) { 

pour le faire fonctionner avec android.support.design.widget.TabLayout (au moins à partir de com.android.support:design:23.2.0)


4
mais AppCompatTextView étend TextView, alors pourquoi cela ferait-il une différence?
Shirane85
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.