Modificare il carattere del testo della scheda nel supporto del design Android TabLayout


109

Sto cercando di lavorare sul nuovo TabLayoutdalla libreria di progettazione Android.

Voglio cambiare il testo della tabulazione in un carattere personalizzato . E ho provato a cercare alcuni stili relativi a TabLayout, ma sono finito a questo .

Per favore guida come posso cambiare i caratteri del testo della scheda.


3
Use Spannable String
NullByte

Risposte:


37

Crea un TextView da codice Java o XML come questo

<?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"
/>

Assicurati di mantenere l'ID così com'è perché il TabLayout controlla questo ID se utilizzi la visualizzazione di testo personalizzata

Quindi dal codice gonfiare questo layout e impostare l'abitudine Typefacesu quella visualizzazione di testo e aggiungere questa visualizzazione personalizzata alla scheda

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
Come posso impostare tabTextColore tabSelectedTextColorproprietà in questa situazione?
Alireza Noorali

Ottengo la soluzione dalla risposta di praveen Sharma
Alireza Noorali

162

Se stai usando TabLayoute vuoi cambiare il carattere devi aggiungere un nuovo ciclo for alla soluzione precedente in questo modo:

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);
                }
        }
    }
} 

Fare riferimento alla modifica dello stile del carattere nelle schede della barra delle azioni utilizzando sherlock


Non sto usando l'anteprima M. C'è un altro modo per farlo.
Dory

1
Non serve l'anteprima M, è valida per tutti coloro che utilizzanoTabLayout
Mario Velasco

Tuttavia, sto riscontrando una NullPointerException su android.view.View android.support.design.widget.TabLayout.getChildAt (int), puoi aiutarmi a risolverlo? Non riesco a trovare quello che mi manca sul mio codice.
brettbrdls

1
Il primo parametro di setTypeFaceè a TypeFace, nel caso in cui non riesci a trovare la Fontclasse (che non sembra esistere per me)
Vahid Amiri

104

Crea il tuo stile personalizzato e usa lo stile genitore come parent="@android:style/TextAppearance.Widget.TabWidget"

E nel layout della scheda usa questo stile come app:tabTextAppearance="@style/tab_text"

Esempio: Stile:

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

Esempio: componente layout scheda:

<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
Questo è corretto, sto usando parent="TextAppearance.Design.Tab"nel mio caso.
Javatar

1
Funziona molto meglio delle prime risposte e senza magia nera (api nascosta), che potrebbe rompere qualcosa in futuro
Sulfkain

2
funziona solo quando si usa fontFamily, non funziona quando si usa fontPath
Tram Nguyen

2
Stavo ricevendo strane eccezioni in modo irregolare durante l'utilizzo TextAppearance.Widget.TabWidget. La risposta di @Javatar l'ha risolto per me.
funct7

47

Ottima risposta da praveen Sharma. Solo una piccola aggiunta: invece di usare changeTabsFont()ovunque ti serva TabLayout, puoi semplicemente usare il tuo 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);
            }
        }
    }

}

E un'altra cosa. TabViewè un LinearLayoutcon TextViewdentro (può anche facoltativamente contenere ImageView). Quindi puoi rendere il codice ancora più semplice:

@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);
}

Ma non lo consiglierei in questo modo. Se l' TabLayoutimplementazione cambierà, questo codice può funzionare in modo improprio o addirittura bloccarsi.

Un altro modo per personalizzare TabLayoutè l'aggiunta di una visualizzazione personalizzata. Ecco il grande esempio .


addTab non verrà richiamato nel caso in cui si impostino schede come questa: mViewPager.setAdapter (new YourPagerAdapter (getChildFragmentManager ())); mTabLayout.setupWithViewPager (mViewPager);
Penzzz

2
@ Penzzz hai perfettamente ragione. In questo caso dovresti spostare il codice dal metodo addTab a un altro. Ad esempio onMeasure.
Andrei Aulaska

@AndreiAulaska grazie Mi hai salvato la giornata. Il tuo ultimo collegamento mi salva.
Amol Dale

questo non funziona più credo nell'ultima versione. La risposta di @ ejw ora funziona. è necessario aggiungerlo in addTab (Tab tab, boolean setSelected)
Sayem

3
Funziona bene. NOTA: a partire dalla libreria di supporto 25.x, è necessario eseguire l'override addTab(Tab tab, int position, boolean setSelected)anziché addTab(Tab tab).
Vicky Chijwani

20

Per utilizzare il supporto dei caratteri nella XMLfunzionalità sui dispositivi in ​​esecuzione Android 4.1(livello API 16) e versioni successive, utilizzare la libreria di supporto 26+.

  1. Fare clic con il tasto destro sulla cartella res
  2. Nuovo -> Directory delle risorse Android-> seleziona carattere -> Ok
  3. Metti il ​​tuo myfont.ttffile nella cartella dei font appena creata

In res/values/styles.xmlaggiunta:

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

Sul file di layout aggiungi l'app: 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" />

Fare riferimento a [caratteri in xml]. ( Https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml )


funziona su xamarin form e xamarin android.thanks
Esmail Jamshidiasl

Bella risposta! Dovrebbe però estendere "TextAppearance.Design.Tab"
XY

16

Il metodo seguente cambierà il carattere completamente in ViewGroupmodo ricorsivo. Ho scelto questo metodo perché non devi preoccuparti della struttura interna di TabLayout. Sto usando la libreria di calligrafia per impostare un carattere.

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
il problema è che se colleghi il layout a un Viewpager, perderai i caratteri personalizzati.
rupps

10

Per il supporto alla progettazione 23.2.0, utilizzando setupWithViewPager, dovrai spostare il codice da addTab (Tab tab) a addTab (Tab tab, boolean setSelected).


8

Puoi usarlo, per me funziona.

 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

Bene, l'ho trovato semplice nella 23.4.0 senza usare un ciclo. Basta sovrascrivere addTab (scheda @NonNull Tab, boolean setSelected) come suggerito da @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);
}

Ed ecco l'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" />

Spero che possa aiutare :)


1
Ma come impostare tabSelectedTextColor e tabTextColo?
Mostafa Imran

@MostafaImran la tua versione di android:textColor="@color/graylove"dovrebbe avere il selettore dell'elenco di stato per quello con il colore state_selected specificato
AA_PV

7

Come ha risposto Andrei , puoi cambiare il tipo di carattere estendendo la classe TabLayout . E come ha detto Penzzz , non puoi farlo con il metodo addTab . Esegui l' override del metodo onLayout come segue :

@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);
            }
        }
    }
}

Deve sovrascrivere il metodo onLayout, perché, quando si utilizza il metodo setupWithViewPager per associare TabLayout con ViewPager, è necessario impostare il testo delle tabulazioni con il metodo setText o nel PagerAdapter dopo di che e quando ciò è accaduto, il metodo onLayout viene chiamato sul ViewGroup genitore ( TabLayout) e questo è il posto dove inserire l'impostazione del fontface. (La modifica di un testo TextView causa la chiamata al metodo onLayout del suo genitore: un tabView ha due figli, uno è ImageView e un altro è TextView)

Un'altra soluzione:

Innanzitutto, queste righe di codice:

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

Nella soluzione sopra, dovrebbe essere scritto al di fuori di due cicli.

Ma la soluzione migliore per API> = 16 sta usando android: fontFamily :

Crea una directory di risorse Android denominata font e copia il font desiderato nella directory.

Quindi usa questi stili:

<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>

Questa è una cattiva correzione delle prestazioni, è onLayout()stata chiamata ad ogni cambio di layout come il cambio di scheda o anche lo scorrimento dell'elenco sotto le schede, con i messaggi nidificati forin TabLayoutun'app con molte schede sarà lento.
Amr Barakat

2
@Amr Barakat. Secondo questo link: developer.android.com/reference/android/view/… , int, int, int, int), questo non è vero. Anch'io l'ho provato. Ho inserito un punto di interruzione nel metodo onLayout e viene chiamato quando le schede vengono create non sul cambio di scheda o sullo scorrimento dell'elenco.
Arash

1
Per me onLayout()viene chiamato più volte quando si cambia scheda (non so perché esattamente), ma per tenerne conto ho impostato i caratteri solo quando boolean changedè vero. Ciò impedisce l'impostazione dei caratteri più volte.
Robert il

ottima soluzione, nessun codice richiesto, solo attributi xml
attenzione 7j

3

Il mio metodo Resolve proprio come questo, cambia il testo della scheda specificato,

 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

Estensione Kotlin che ha funzionato per me:

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

Il mio 2p, Kotlin con controllo dei riferimenti, applicabile ovunque in quanto si fermerà se qualcosa non va.

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

Ed ecco la mia implementazione in Kotlin che consente anche di cambiare il carattere per le schede selezionate e non selezionate.

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()
        }
    }
}

in 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 non cambia il testo dinamicamente, una volta impostato.
shanraisshan

0

Con le funzioni di estensione kotlin usa questo:

 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

Modificare

if (tabViewChild instanceof TextView) {

per

if (tabViewChild instanceof AppCompatTextView) { 

per farlo funzionare con android.support.design.widget.TabLayout (almeno da com.android.support:design:23.2.0)


4
ma AppCompatTextView estende TextView, quindi perché questo farebbe la differenza?
Shirane85
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.