Ubah font teks tab dalam dukungan desain android TabLayout


Jawaban:


37

Buat TextView dari Kode Java atau XML seperti ini

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

Pastikan untuk menyimpan ID seperti di sini karena TabLayout memeriksa ID ini jika Anda menggunakan textview kustom

Kemudian dari kode Typefaceperbesar tata letak ini dan setel kustom pada textview itu dan tambahkan tampilan kustom ini ke tab

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
Bagaimana saya bisa mengatur tabTextColordan tabSelectedTextColorproperti dalam situasi ini?
Alireza Noorali

Saya mendapatkan solusi dari jawaban praveen Sharma
Alireza Noorali

162

Jika Anda menggunakan TabLayoutdan ingin mengubah font, Anda harus menambahkan loop for baru ke solusi sebelumnya seperti ini:

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

Silakan merujuk untuk mengubah gaya font di tab bilah tindakan menggunakan sherlock


Saya tidak menggunakan pratinjau M. Apakah ada cara lain untuk melakukannya.
Dory

1
Anda tidak memerlukan pratinjau M, ini berlaku untuk semua orang yang menggunakanTabLayout
Mario Velasco

Namun, saya menemukan NullPointerException di android.view.View android.support.design.widget.TabLayout.getChildAt (int), dapatkah Anda membantu saya memperbaikinya? Tidak dapat menemukan apa yang saya lewatkan pada kode saya.
brettbrdls

1
Parameter pertama setTypeFaceadalah a TypeFace, jika Anda tidak dapat menemukan Fontkelas (yang tampaknya tidak ada untuk saya)
Vahid Amiri

104

Buat gaya kustom Anda sendiri dan gunakan gaya induk sebagai parent="@android:style/TextAppearance.Widget.TabWidget"

Dan dalam tata letak tab Anda, gunakan gaya ini sebagai app:tabTextAppearance="@style/tab_text"

Contoh: Gaya:

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

Contoh: Komponen tata letak tab:

<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
Ini benar, saya gunakan parent="TextAppearance.Design.Tab"dalam kasus saya.
Javatar

1
Ini bekerja jauh lebih baik daripada jawaban pertama, dan tanpa ilmu hitam (api tersembunyi), yang dapat merusak sesuatu di masa depan
Sulfkain

2
hanya berfungsi saat menggunakan fontFamily, tidak berfungsi saat menggunakan fontPath
Trem Nguyen

2
Saya mendapatkan pengecualian aneh secara tidak menentu saat menggunakan TextAppearance.Widget.TabWidget. Jawaban @Javatar memperbaikinya untuk saya.
funct7

47

Jawaban bagus dari Praveen Sharma. Hanya sedikit tambahan: Daripada menggunakan di changeTabsFont()mana pun Anda butuhkan TabLayout, Anda dapat menggunakan milik Anda sendiri 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);
            }
        }
    }

}

Dan satu hal lagi. TabViewadalah LinearLayoutdengan TextViewdalam (dapat juga berisi opsional ImageView). Jadi Anda dapat membuat kode lebih sederhana:

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

Tetapi saya tidak akan merekomendasikan cara ini. Jika TabLayoutimplementasi akan berubah, kode ini dapat bekerja tidak semestinya atau bahkan crash.

Cara lain untuk menyesuaikan TabLayoutadalah menambahkan tampilan kustom ke dalamnya. Inilah contoh yang bagus .


addTab tidak akan dipanggil jika Anda menyetel tab seperti ini: mViewPager.setAdapter (new YourPagerAdapter (getChildFragmentManager ())); mTabLayout.setupWithViewPager (mViewPager);
Penzzz

2
@Penzz Anda benar sekali. Dalam hal ini Anda harus memindahkan kode dari metode addTab ke metode lain. Misalnya onMeasure.
Andrei Aulaska

@AndreiAulaska thnx Anda menyelamatkan hari saya. Tautan terakhir Anda menyelamatkan saya.
Amol Dale

ini tidak berfungsi lagi saya pikir di versi terbaru. Jawaban @ ejw sekarang berfungsi. perlu menambahkannya di addTab (Tab tab, boolean setSelected)
Sayem

3
Ini bekerja dengan baik. CATATAN: pada pustaka dukungan 25.x, Anda perlu mengganti, addTab(Tab tab, int position, boolean setSelected)bukan addTab(Tab tab).
Vicky Chijwani

20

Untuk menggunakan dukungan font dalam XMLfitur pada perangkat yang menjalankan Android 4.1(API level 16) dan lebih tinggi, gunakan Support Library 26+.

  1. Klik kanan folder res
  2. Baru -> Direktori sumber daya Android-> pilih font -> Ok
  3. Letakkan myfont.ttffile Anda di folder font yang baru dibuat

Di res/values/styles.xmltambahkan:

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

Pada file tata letak, tambahkan aplikasi: 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" />

Silakan lihat [font dalam xml]. ( Https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml )


ini berfungsi pada formulir xamarin dan xamarin android.thanks
Esmail Jamshidiasl

Jawaban yang bagus! Harus memperpanjang "TextAppearance.Design.Tab" meskipun
XY

16

Metode berikut akan mengubah font secara keseluruhan ViewGroupsecara rekursif. Saya memilih metode ini karena Anda tidak perlu peduli dengan struktur dalam TabLayout. Saya menggunakan perpustakaan Kaligrafi untuk mengatur font.

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
Masalahnya adalah, jika Anda melampirkan tata letak ke Viewpager, Anda akan kehilangan font yang disesuaikan.
rupps

10

Untuk dukungan desain 23.2.0, menggunakan setupWithViewPager, Anda harus memindahkan kode dari addTab (Tab tab) ke addTab (Tab tab, boolean setSelected).


8

Anda dapat menggunakan ini, ini berhasil untuk saya.

 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

Yah, saya merasa sederhana di 23.4.0 tanpa menggunakan loop. Timpa saja addTab (tab Tab @NonNull, boolean setSelected) seperti yang disarankan oleh @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);
}

Dan ini XML-nya

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

Semoga bisa membantu :)


1
Tapi bagaimana cara mengatur tabSelectedTextColor dan tabTextColo?
Mostafa Imran

@MostafaImran versi Anda android:textColor="@color/graylove"harus memiliki pemilih daftar negara untuk itu dengan warna state_selected ditentukan
AA_PV

7

Saat Andrei menjawab, Anda dapat mengubah fontface dengan memperluas kelas TabLayout . Dan seperti yang dikatakan Penzzz , Anda tidak dapat melakukannya dengan metode addTab . Ganti metode onLayout seperti di bawah ini:

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

Harus Menimpa metode onLayout, karena, saat Anda menggunakan metode setupWithViewPager untuk mengikat TabLayout dengan ViewPager, Anda harus menyetel teks tab baik dengan metode setText atau di PagerAdapter setelah itu dan ketika ini terjadi, metode onLayout dipanggil pada ViewGroup induk ( TabLayout) dan itulah tempat untuk meletakkan pengaturan fontface. (Mengubah teks TextView menyebabkan memanggil metode onLayout dari induknya - TabView memiliki dua anak, satu adalah ImageView dan yang lainnya adalah TextView)

Solusi Lain:

Pertama, baris kode berikut:

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

Dalam solusi di atas, harus ditulis di luar dua loop.

Tetapi solusi yang lebih baik untuk API> = 16 adalah menggunakan android: fontFamily :

Buat Direktori Sumber Daya Android bernama font dan salin font yang Anda inginkan ke direktori.

Kemudian gunakan gaya ini:

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

Ini adalah perbaikan kinerja yang buruk, onLayout()dipanggil dengan setiap perubahan tata letak seperti peralihan tab atau bahkan daftar gulir di bawah tab, dengan bersarang fordi banyak TabLayoutaplikasi tab akan menjadi lamban.
Amr Barakat

2
@Ar Barakat. Menurut tautan ini: developer.android.com/reference/android/view/… , int, int, int, int), ini tidak benar. Saya mengujinya juga. Saya meletakkan titik jeda dalam metode onLayout dan itu dipanggil ketika tab sedang dibuat bukan pada pengalihan tab atau pengguliran daftar.
Arash

1
Bagi saya onLayout()memang dipanggil beberapa kali ketika beralih tab (tidak yakin mengapa tepatnya), tetapi untuk memperhitungkan ini saya hanya mengatur font ketika boolean changedbenar. Melakukan itu mencegah pengaturan font beberapa kali.
Robert

solusi hebat, tidak diperlukan kode, hanya atribut xml
hati

3

Metode Resolve saya seperti ini, ubah teks tab Tertentu,

 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

Ekstensi Kotlin yang berhasil untuk saya:

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

2p saya, Kotlin dengan pemeriksaan referensi, berlaku di mana saja karena akan berhenti jika ada yang salah.

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

Dan inilah implementasi saya di Kotlin yang juga memungkinkan perubahan font untuk tab yang dipilih dan tidak dipilih.

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

di 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) ?. teks tidak mengubah teks secara dinamis, setelah disetel.
shanraisshan

0

Dengan fungsi ekstensi kotlin gunakan ini:

 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

Perubahan

if (tabViewChild instanceof TextView) {

untuk

if (tabViewChild instanceof AppCompatTextView) { 

untuk membuatnya berfungsi dengan android.support.design.widget.TabLayout (setidaknya dari com.android.support:design:23.2.0)


4
tetapi AppCompatTextView memperluas TextView, jadi mengapa hal ini membuat perbedaan?
Shirane85
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.