Apakah mungkin untuk mengatur font khusus untuk seluruh aplikasi?

270

Saya perlu menggunakan font tertentu untuk seluruh aplikasi saya. Saya memiliki file .ttf untuk hal yang sama. Apakah mungkin untuk menetapkan ini sebagai font default, saat aplikasi dihidupkan dan kemudian menggunakannya di tempat lain dalam aplikasi? Saat diatur, bagaimana cara menggunakannya di tata letak XML saya?

Samuh
sumber
di android studio 3.0 Anda dapat dengan mudah mengatur font khusus: developer.android.com/guide/topics/ui/look-and-feel/…
MHSFisher
@MHSFisher Fonts dalam XML adalah fitur untuk Android 8.0 (API level 26)
Emi Raz
1
@EmiRaz silakan baca doc developer.android.com/guide/topics/ui/look-and-feel/… . fitur ini ditambahkan di perpustakaan dukungan 26, tetapi dukungan dari API 16.
MHSFisher

Jawaban:

450

Ya dengan refleksi. Ini berfungsi ( berdasarkan jawaban ini ):

(Catatan: ini adalah solusi karena kurangnya dukungan untuk font khusus, jadi jika Anda ingin mengubah situasi ini, silakan beri tanda bintang untuk memperbarui masalah android di sini ). Catatan: Jangan tinggalkan komentar "saya juga" tentang masalah itu, semua orang yang melihatnya mendapat email saat Anda melakukannya. Jadi tolong beri "bintang" saja.

import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.Typeface;

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

Anda kemudian perlu membebani beberapa font default, misalnya di kelas aplikasi :

public final class Application extends android.app.Application {
    @Override
    public void onCreate() {
        super.onCreate();
        FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");
        FontsOverride.setDefaultFont(this, "MONOSPACE", "MyFontAsset2.ttf");
        FontsOverride.setDefaultFont(this, "SERIF", "MyFontAsset3.ttf");
        FontsOverride.setDefaultFont(this, "SANS_SERIF", "MyFontAsset4.ttf");
    }
}

Atau tentu saja jika Anda menggunakan file font yang sama, Anda dapat meningkatkan ini untuk memuatnya sekali saja.

Namun saya cenderung hanya menimpa satu, katakanlah "MONOSPACE", kemudian mengatur gaya untuk memaksa aplikasi font typeface yang luas:

<resources>
    <style name="AppBaseTheme" parent="android:Theme.Light">
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <item name="android:typeface">monospace</item>
    </style>
</resources>

API 21 Android 5.0

Saya telah menyelidiki laporan dalam komentar yang tidak berfungsi dan tampaknya tidak sesuai dengan tema android:Theme.Material.Light.

Jika tema itu tidak penting bagi Anda, gunakan tema yang lebih lama, misalnya:

<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
    <item name="android:typeface">monospace</item>
</style>
weston
sumber
11
bagaimana Anda akan mengesampingkan monospace yang tebal atau miring?
Christopher Rivera
2
@ChristopherRivera Ada "DEFAULT_BOLD"tetapi juga bidang pribadi: private static Typeface[] sDefaults;Anda dapat mencoba mengakses ini dengan refleksi dan pengaturan sDefaults[Typeface.ITALIC]ke yourTypeface. Lihat ini.
weston
5
@weston Sudahlah. Saya telah mencapainya. Ada kesalahan dalam pemahaman saya. Anda telah melakukan pekerjaan dengan baik. Bisakah Anda memberi tahu saya satu hal? Mengapa ini tidak berfungsi untuk DEFAULT Typeface? Saya telah mengubah Typeface menjadi MONOSPACE sebagai saran Anda dan kemudian menerapkan loginc, itu berhasil. Tetapi tidak bekerja untuk DEFAULT
Jay Pandya
2
Jenis huruf asli tidak dapat dibuat kesalahan. Diperbaiki, dengan menambahkan jalur font. "FontsOverride.setDefaultFont (ini," DEFAULT "," fonts / MyFontAsset.ttf ");"
Sai
3
Saya merasa sangat menjengkelkan harus menukar default di TextViewmana-mana untuk menggunakan font khusus atau menggunakan solusi berbasis refleksi seperti ini. Dikombinasikan dengan set font yang tersedia di android, itu membuat mengembangkan aplikasi yang tampak baik banyak kerja keras. Saya telah menambahkan permintaan fitur ke pelacak masalah android. Jika Anda ingin melihat fitur ini, Anda dapat membintangi masalah ini di sini: code.google.com/p/android/issues/…
Sam
64

Ada perpustakaan yang bagus untuk font khusus di android: Kaligrafi

di sini adalah contoh cara menggunakannya.

di Gradle Anda harus meletakkan baris ini ke file build.gradle aplikasi Anda:

dependencies {
    compile 'uk.co.chrisjenx:calligraphy:2.2.0'
}

dan kemudian membuat kelas yang meluas Application dan menulis kode ini:

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
                        .setDefaultFontPath("your font path")
                        .setFontAttrId(R.attr.fontPath)
                        .build()
        );
    }
} 

dan di kelas aktivitas, tempatkan metode ini di depan onCreate:

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}

dan hal terakhir file manifes Anda akan terlihat seperti ini:

<application
   .
   .
   .
   android:name=".App">

dan itu akan mengubah seluruh aktivitas menjadi font Anda! sederhana dan bersih!

Shia G
sumber
1
Ini solusi sempurna.
nizam.sp
1
Benar, solusi yang sangat sempurna, dengan cara ini saya tidak perlu menulis kelas yang berbeda untuk memperbarui font untuk item menu, tombol radio atau kotak centang. Itu berlaku untuk semua !! terima kasih :)
Manisha
2
Jelas bukan solusi yang sempurna: Gaya cetak tebal / miring / tebal dicetak ulang. Saat ini tidak ada cara mudah untuk mengatur keluarga-keluarga itu.
0101100101
2
Jika saya melakukannya, Bagaimana saya bisa beralih dari Bold ke Reguler?
GMX
2
Untuk mendapatkan fitur tebal, miring atau garis bawah, saya telah menggunakan <b></b>, <u></u>dan <i></i>dalam strings.xmlfile dan sejauh ini berfungsi.
gembira
47

Meskipun ini tidak akan berfungsi untuk seluruh aplikasi, itu akan berfungsi untuk suatu Aktivitas dan dapat digunakan kembali untuk Kegiatan lainnya. Saya telah memperbarui kode saya terima kasih kepada @ FR073N untuk mendukung Tampilan lain. Saya tidak yakin tentang masalah dengan Buttons, RadioGroups, dll karena orang-orang kelas semua memperpanjangTextView sehingga mereka harus bekerja dengan baik. Saya menambahkan persyaratan boolean untuk menggunakan refleksi karena tampaknya sangat retas dan mungkin mengganggu kinerja.

Catatan: seperti yang ditunjukkan, ini tidak akan berfungsi untuk konten dinamis! Untuk itu, mungkin memanggil metode ini dengan say an onCreateViewatau getViewmetode, tetapi membutuhkan upaya tambahan.

/**
 * Recursively sets a {@link Typeface} to all
 * {@link TextView}s in a {@link ViewGroup}.
 */
public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect)
{
    if (mContainer == null || mFont == null) return;

    final int mCount = mContainer.getChildCount();

    // Loop through all of the children.
    for (int i = 0; i < mCount; ++i)
    {
        final View mChild = mContainer.getChildAt(i);
        if (mChild instanceof TextView)
        {
            // Set the font if it is a TextView.
            ((TextView) mChild).setTypeface(mFont);
        }
        else if (mChild instanceof ViewGroup)
        {
            // Recursively attempt another ViewGroup.
            setAppFont((ViewGroup) mChild, mFont);
        }
        else if (reflect)
        {
            try {
                Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);
                mSetTypeface.invoke(mChild, mFont); 
            } catch (Exception e) { /* Do something... */ }
        }
    }
}

Kemudian untuk menggunakannya Anda akan melakukan sesuatu seperti ini:

final Typeface mFont = Typeface.createFromAsset(getAssets(),
"fonts/MyFont.ttf"); 
final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
HomeActivity.setAppFont(mContainer, mFont);

Semoga itu bisa membantu.

Tom
sumber
4
Saya pikir cara terbaik adalah mengganti textview. Metode ini bisa menjadi agak berlebihan jika Anda memiliki aplikasi dengan banyak tampilan.
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
1
Itu bisa ... tetapi menurut spesifikasi Android Anda ingin menghindari tata letak yang lebih dalam dari 4 level dan lebar 100 tampilan (bahkan itu cukup sedikit). Rekursi bisa jadi buruk dalam hal kinerja, tetapi bahkan jika tata letak Anda adalah 20 level, itu bahkan tidak signifikan.
Tom
Saya setuju bahwa itu tidak memiliki dampak nyata pada kinerja dan saya tidak mencoba mengatakan jawaban Anda salah. Saya hanya tidak suka bersepeda melalui setiap tampilan di tata letak jika saya tidak perlu. Juga, dengan memperluas TextView, jika Anda ingin memodifikasi tampilan dengan cara lain, Anda hanya perlu mengubah kode di satu tempat.
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
1
Hanya ingin menambahkan bahwa kode di atas hanya mencakup TextViews tetapi ListViews, Alerts, Toasts, Map Markers dll. Masih akan menggunakan font sistem.
CC
2
guys fungsi ini membutuhkan 3 parameter, ketika Anda menyebutnya secara rekursif Anda melewati 2 parameter ??? mana yang benar? apa yang mencerminkan ??
MBH
34

Singkatnya:

Opsi # 1: Gunakan refleksi untuk menerapkan font (menggabungkan jawaban weston & Roger Huang ):

import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.Typeface;

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) {
        if (isVersionGreaterOrEqualToLollipop()) {
            Map<String, Typeface> newMap = new HashMap<String, Typeface>();
            newMap.put("sans-serif", newTypeface);
            try {
                final Field staticField = Typeface.class.getDeclaredField("sSystemFontMap");
                staticField.setAccessible(true);
                staticField.set(null, newMap);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else {
            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();
            } 
        }
    }

} 

Penggunaan di kelas Aplikasi:

public final class Application extends android.app.Application {
    @Override 
    public void onCreate() { 
        super.onCreate(); 
        FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");
        FontsOverride.setDefaultFont(this, "MONOSPACE", "MyFontAsset2.ttf");
        FontsOverride.setDefaultFont(this, "SERIF", "MyFontAsset3.ttf");
        FontsOverride.setDefaultFont(this, "SANS_SERIF", "MyFontAsset4.ttf");
    } 
} 

mengatur gaya untuk memaksa aplikasi jenis huruf yang lebar (berdasarkan lovefish ):

Pra-Lollipop:

<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:typeface">monospace</item>
   </style>
</resources>

Lollipop (API 21):

<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:textAppearance">@style/CustomTextAppearance</item>
   </style>

   <style name="CustomTextAppearance">
       <item name="android:typeface">monospace</item>
   </style>
</resources>

Option2: Subkelas masing-masing dan setiap Lihat di mana Anda perlu menyesuaikan font, yaitu. ListView, EditTextView, Tombol, dll. ( Jawaban Palani ):

public class CustomFontView extends TextView {

public CustomFontView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(); 
} 

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

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

private void init() { 
    if (!isInEditMode()) {
        Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
        setTypeface(tf);
    } 
} 

Opsi 3: Terapkan View Crawler yang melintasi hierarki tampilan layar Anda saat ini:

Variasi # 1 ( jawaban Tom ):

public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect)
{ 
    if (mContainer == null || mFont == null) return;

    final int mCount = mContainer.getChildCount();

    // Loop through all of the children. 
    for (int i = 0; i < mCount; ++i)
    { 
        final View mChild = mContainer.getChildAt(i);
        if (mChild instanceof TextView)
        { 
            // Set the font if it is a TextView. 
            ((TextView) mChild).setTypeface(mFont);
        } 
        else if (mChild instanceof ViewGroup)
        { 
            // Recursively attempt another ViewGroup. 
            setAppFont((ViewGroup) mChild, mFont);
        } 
        else if (reflect)
        { 
            try { 
                Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);
                mSetTypeface.invoke(mChild, mFont); 
            } catch (Exception e) { /* Do something... */ }
        } 
    } 
} 

Penggunaan:

final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
HomeActivity.setAppFont(mContainer, Typeface.createFromAsset(getAssets(),
"fonts/MyFont.ttf"));

Variasi # 2: https://coderwall.com/p/qxxmaa/android-use-a-custom-font-everywhere .

Opsi # 4: Gunakan Lib Pihak ke-3 yang disebut Kaligrafi .

Secara pribadi, saya akan merekomendasikan Opsi # 4, karena menghemat banyak sakit kepala.

Phileo99
sumber
Dalam Opsi # 1 , apa yang Anda maksud dengan "sans-serif"in newMap.put(, and monospacein styles?! Saya ingin menggunakan font khusus yang dinamai barana.ttf.
Dr.jacky
dalam opsi 1, cuplikan kode pertama tidak berfungsi dengan API level 22, Android 5.1.1. Tetapi bagian kode lain tidak. Apa yang harus tepat jika kondisinya demikian?
user1510006
28

Saya ingin meningkatkan jawaban weston untuk API 21 Android 5.0.

Sebab

Di bawah API 21, sebagian besar gaya teks menyertakan pengaturan fontFamily, seperti:

<style name="TextAppearance.Material">
     <item name="fontFamily">@string/font_family_body_1_material</item>
</style>

Yang menerapkan font Roboto Regular default:

<string name="font_family_body_1_material">sans-serif</string>

Jawaban asli gagal menerapkan font monospace, karena android: fontFamily memiliki prioritas lebih besar untuk android: atribut typeface ( referensi ). Menggunakan Theme.Holo. * Adalah solusi yang valid, karena tidak ada pengaturan android: fontFamily di dalamnya.

Larutan

Karena Android 5.0 memasukkan tipografi sistem ke dalam variabel statis Typeface.sSystemFontMap ( referensi ), kita dapat menggunakan teknik refleksi yang sama untuk menggantinya:

protected static void replaceFont(String staticTypefaceFieldName,
        final Typeface newTypeface) {
    if (isVersionGreaterOrEqualToLollipop()) {
        Map<String, Typeface> newMap = new HashMap<String, Typeface>();
        newMap.put("sans-serif", newTypeface);
        try {
            final Field staticField = Typeface.class
                    .getDeclaredField("sSystemFontMap");
            staticField.setAccessible(true);
            staticField.set(null, newMap);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    } else {
        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();
        }
    }
}
Roger Huang
sumber
4
solusi yang bagus untuk L. Namun, saya bertanya-tanya mengapa ini sepertinya tidak berhasil untuk Buttonjudul s dan Tool Bar saya. Saya mengganti font default di MainApplication sebagai berikut:FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf"); . Saya menggunakan Nexus 5, v5.1.1
kip2
3
Hai, Terima kasih. Ini sangat membantu, hanya satu hal: ini tidak berfungsi di Android 6 (API 22). Maka haruskah kode diubah menjadi ini: Build.VERSION.SDK_INT == 21- Itu hanya dalam API 21 pengujian I di Nexus dengan API 22
Saeid
Namun saya masih tidak dapat mengatur font khusus menggunakan metode ini di Nexus 9
Rahul Upadhyay
2
Siapa pun yang mengalami masalah tidak bekerja untuk 5.1+. Jangan timpa jenis huruf pada gaya values-v21 Anda.
Muhammad Babar
@MuhammadBabar Terima kasih solusi Anda membuat hari saya
M.Yogeshwaran
15

sangat sederhana ... 1.Unduh dan letakkan font kustom Anda dalam aset..kemudian tulis satu kelas terpisah untuk tampilan teks sebagai berikut: di sini saya menggunakan font futura

public class CusFntTextView extends TextView {

public CusFntTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

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

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

private void init() {
    if (!isInEditMode()) {
        Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
        setTypeface(tf);
    }
}

}

dan lakukan hal berikut dalam xml:

 <com.packagename.CusFntTextView
        android:id="@+id/tvtitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"         
        android:text="Hi Android"           
        android:textAppearance="?android:attr/textAppearanceLarge"
      />
Palani
sumber
Ya, itu bekerja :) Tapi, bagaimana jika saya ingin menerapkan font yang sama untuk tampilan / widget lainnya? Apakah saya perlu menulis kelas terpisah untuk semua tampilan lain (termasuk dialog / toasts / actionbars) juga?
Narendra Singh 3-15
Ya, untuk solusi ini Anda perlu menulis kelas terpisah untuk setiap tampilan Anda.
Saad Bilal
9

Saya juga menyarankan untuk memperluas TextView dan kontrol lainnya, tetapi akan lebih baik saya mempertimbangkan untuk mengatur font dalam konstruksi.

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

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

public FontTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

protected void init() {
    setTypeface(Typeface.createFromAsset(getContext().getAssets(), AppConst.FONT));
}
Andrey Mischenko
sumber
2
Hati-hati saat melakukan ini pada platform sebelum 4.0 - ini akan membocorkan banyak sumber daya karena bug di Android: code.google.com/p/android/issues/detail?id=9904
Ryan M
bagaimana kita dapat kembali ke default. Saya melakukan sesuatu seperti ini: if (configShared.getString ("storeId", AppCredentials.DEFAULT_STORE_ID). Equals ("2")) {final Field staticField = Typeface.class.getDeclaredField (staticTypefaceFieldName); staticField.setAccessible (true); staticField.set (null, newTypeface); } else {final Field staticField = Typeface.class.getDeclaredField (staticTypefaceFieldName); staticField.setAccessible (true); staticField.set (null, null); }
Pembunuh
8

Saya ingin meningkatkan jawaban weston dan Roger Huang untuk lebih dari API 21 Android lollipop dengan tema " Theme.AppCompat ".

Di bawah Android 4.4

<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:typeface">monospace</item>
   </style>
</resources>

Lebih dari (sama) API 5.0

<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:textAppearance">@style/CustomTextAppearance</item>
   </style>

   <style name="CustomTextAppearance">
       <item name="android:typeface">monospace</item>
   </style>
</resources>

Dan file util FontsOverride sama dengan apa yang ada di jawaban weston . Saya sudah menguji di ponsel ini:

Nexus 5 (Android 5.1 Sistem Android Utama)

ZTE V5 (android 5.1 CM12.1)

Catatan XIAOMI (android 4.4 MIUI6)

HUAWEI C8850 (android 2.3.5 UNKNOWN)

ikan cinta
sumber
8

Solusi brilian dapat ditemukan di sini: https://coderwall.com/p/qxxmaa/android-use-a-custom-font-everywhere .

Cukup rentangkan kegiatan dari BaseActivity dan tulis metode itu. Anda juga harus mem-cache font yang lebih baik seperti yang dijelaskan di sini: https://stackoverflow.com/a/16902532/2914140 .


Setelah beberapa penelitian saya menulis kode yang bekerja di Samsung Galaxy Tab A (Android 5.0). Kode yang digunakan weston dan Roger Huang serta https://stackoverflow.com/a/33236102/2914140 . Juga diuji pada Lenovo TAB 2 A10-70L, di mana itu tidak berfungsi. Saya memasukkan font 'Sans Komik' di sini untuk melihat perbedaan.

import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
import android.util.Log;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class FontsOverride {
    private static final int BOLD = 1;
    private static final int BOLD_ITALIC = 2;
    private static final int ITALIC = 3;
    private static final int LIGHT = 4;
    private static final int CONDENSED = 5;
    private static final int THIN = 6;
    private static final int MEDIUM = 7;
    private static final int REGULAR = 8;

    private Context context;

    public FontsOverride(Context context) {
        this.context = context;
    }

    public void loadFonts() {
        Map<String, Typeface> fontsMap = new HashMap<>();
        fontsMap.put("sans-serif", getTypeface("comic.ttf", REGULAR));
        fontsMap.put("sans-serif-bold", getTypeface("comic.ttf", BOLD));
        fontsMap.put("sans-serif-italic", getTypeface("comic.ttf", ITALIC));
        fontsMap.put("sans-serif-light", getTypeface("comic.ttf", LIGHT));
        fontsMap.put("sans-serif-condensed", getTypeface("comic.ttf", CONDENSED));
        fontsMap.put("sans-serif-thin", getTypeface("comic.ttf", THIN));
        fontsMap.put("sans-serif-medium", getTypeface("comic.ttf", MEDIUM));
        overrideFonts(fontsMap);
    }

    private void overrideFonts(Map<String, Typeface> typefaces) {
        if (Build.VERSION.SDK_INT == 21) {
            try {
                final Field field = Typeface.class.getDeclaredField("sSystemFontMap");
                field.setAccessible(true);
                Map<String, Typeface> oldFonts = (Map<String, Typeface>) field.get(null);
                if (oldFonts != null) {
                    oldFonts.putAll(typefaces);
                } else {
                    oldFonts = typefaces;
                }
                field.set(null, oldFonts);
                field.setAccessible(false);
            } catch (Exception e) {
                Log.e("TypefaceUtil", "Cannot set custom fonts");
            }
        } else {
            try {
                for (Map.Entry<String, Typeface> entry : typefaces.entrySet()) {
                    final Field staticField = Typeface.class.getDeclaredField(entry.getKey());
                    staticField.setAccessible(true);
                    staticField.set(null, entry.getValue());
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    private Typeface getTypeface(String fontFileName, int fontType) {
        final Typeface tf = Typeface.createFromAsset(context.getAssets(), "fonts/" + fontFileName);
        return Typeface.create(tf, fontType);
    }
}

Untuk menjalankan kode di seluruh aplikasi Anda harus menulis di beberapa kelas seperti Aplikasi berikut ini:

    new FontsOverride(this).loadFonts();

Buat folder 'font' di dalam 'aset' dan letakkan font yang diperlukan di sana. Instruksi sederhana dapat ditemukan di sini: https://stackoverflow.com/a/31697103/2914140 .

Perangkat Lenovo juga mendapatkan nilai jenis huruf yang salah. Di sebagian besar waktu itu mengembalikan Typeface.NORMAL, kadang-kadang nol. Bahkan jika TextView dicetak tebal (dalam tata letak file xml). Lihat di sini: TextView isBold selalu mengembalikan NORMAL . Dengan cara ini teks pada layar selalu dalam font biasa, tidak dicetak tebal atau miring. Jadi saya pikir itu adalah bug dari produser.

CoolMind
sumber
Saya mempelajari kode sumber android, jawaban Anda adalah yang terbaik. Itu bisa menggantikan yang tipis, sedang, ringan atau apa pun. Terima kasih banyak!
Mohammad Omidvar
6

Bekerja untuk Xamarin. Android:

Kelas:

public class FontsOverride
{
    public static void SetDefaultFont(Context context, string staticTypefaceFieldName, string fontAssetName)
    {
        Typeface regular = Typeface.CreateFromAsset(context.Assets, fontAssetName);
        ReplaceFont(staticTypefaceFieldName, regular);
    }

    protected static void ReplaceFont(string staticTypefaceFieldName, Typeface newTypeface)
    {
        try
        {
            Field staticField = ((Java.Lang.Object)(newTypeface)).Class.GetDeclaredField(staticTypefaceFieldName);
            staticField.Accessible = true;
            staticField.Set(null, newTypeface);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

Implementasi Aplikasi:

namespace SomeAndroidApplication
{
    [Application]
    public class App : Application
    {
        public App()
        {

        }

        public App(IntPtr handle, JniHandleOwnership transfer)
            : base(handle, transfer)
        {

        }

        public override void OnCreate()
        {
            base.OnCreate();

            FontsOverride.SetDefaultFont(this, "MONOSPACE", "fonts/Roboto-Light.ttf");
        }
    }
}

Gaya:

<style name="Theme.Storehouse" parent="Theme.Sherlock">
    <item name="android:typeface">monospace</item>
</style>
Guy Micciche
sumber
6

Pada Android O ini sekarang mungkin untuk menentukan langsung dari XML dan bug saya sekarang ditutup!

Lihat di sini untuk detailnya

TL; DR:

Pertama, Anda harus menambahkan font Anda ke proyek

Kedua, Anda menambahkan keluarga font, seperti:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
    <font
        android:fontStyle="normal"
        android:fontWeight="400"
        android:font="@font/lobster_regular" />
    <font
        android:fontStyle="italic"
        android:fontWeight="400"
        android:font="@font/lobster_italic" />
</font-family>

Terakhir, Anda dapat menggunakan font dalam tata letak atau gaya:

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="@font/lobster"/>

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

Nikmati!

Sam
sumber
Terima kasih. Kita harus menggunakan Android Studio 2.4 untuk dapat menambahkan folder font.
Titik Foton
sebenarnya saya hanya perlu menerapkannya ke gaya saya dan itu akan diterapkan melalui aplikasi. tetapi beberapa (kontrol yang ditambahkan secara program perlu diterapkan melalui kode java)
SolidSnake
4

Anda dapat mengatur font khusus untuk setiap tata letak satu per satu, hanya dengan satu panggilan fungsi dari setiap tata letak dengan melewatkan root view-nya. Pertama, buat pendekatan singelton untuk mengakses objek font seperti ini

 public class Font {
    private static Font font;
    public Typeface ROBO_LIGHT;

    private Font() {

    }

    public static Font getInstance(Context context) {
        if (font == null) {
            font = new Font();
            font.init(context);
        }
        return font;

    }

    public void init(Context context) {

        ROBO_LIGHT = Typeface.createFromAsset(context.getAssets(),
                "Roboto-Light.ttf");
    }

}

Anda dapat mendefinisikan berbagai font di kelas di atas, Sekarang Tentukan font Helper class yang akan menerapkan font:

   public class FontHelper {

    private static Font font;

    public static void applyFont(View parentView, Context context) {

        font = Font.getInstance(context);

        apply((ViewGroup)parentView);

    }

    private static void apply(ViewGroup parentView) {
        for (int i = 0; i < parentView.getChildCount(); i++) {

            View view = parentView.getChildAt(i);

//You can add any view element here on which you want to apply font 

            if (view instanceof EditText) {

                ((EditText) view).setTypeface(font.ROBO_LIGHT);

            }
            if (view instanceof TextView) {

                ((TextView) view).setTypeface(font.ROBO_LIGHT);

            }

            else if (view instanceof ViewGroup
                    && ((ViewGroup) view).getChildCount() > 0) {
                apply((ViewGroup) view);
            }

        }

    }

}

Dalam kode di atas, saya menerapkan font pada textView dan EditText saja, Anda dapat menerapkan font pada elemen tampilan lain juga dengan cara yang sama. Anda hanya perlu meneruskan id dari grup Tampilan root Anda ke metode font berlaku di atas. misalnya tata letak Anda adalah:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/mainParent"
    tools:context="${relativePackage}.${activityClass}" >

    <RelativeLayout
        android:id="@+id/mainContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/homeFooter"
        android:layout_below="@+id/edit" >

        <ImageView
            android:id="@+id/PreviewImg"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/abc_list_longpressed_holo"
            android:visibility="gone" />

        <RelativeLayout
            android:id="@+id/visibilityLayer"
            android:layout_width="match_parent"
            android:layout_height="fill_parent" >

            <ImageView
                android:id="@+id/UseCamera"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:src="@drawable/camera" />

            <TextView
                android:id="@+id/tvOR"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/UseCamera"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="20dp"
                android:text="OR"
                android:textSize="30dp" />

            <TextView
                android:id="@+id/tvAND"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="20dp"
                android:text="OR"
                android:textSize="30dp" />

</RelativeLayout>

Di Above Layout, id induk root adalah "Induk Utama" sekarang mari kita terapkan font

public class MainActivity extends BaseFragmentActivity {

    private EditText etName;
    private EditText etPassword;
    private TextView tvTitle;
    public static boolean isHome = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       Font font=Font.getInstance(getApplicationContext());
        FontHelper.applyFont(findViewById(R.id.mainParent),          getApplicationContext());
   }    
}

Bersulang :)

Ajji
sumber
Bagus .. tidak ada lagi pembuatan font yang sama, hanya 1 font yang digunakan untuk semua bidang. :)
Arfan Mirza
3

Saya akan menyarankan memperluas TextView, dan selalu menggunakan TextView kustom Anda dalam layout XML Anda atau di mana pun Anda membutuhkan TextView. Di TextView khusus Anda, timpasetTypeface

@Override
public void setTypeface(Typeface tf, int style) {
    //to handle bold, you could also handle italic or other styles here as well
    if (style == 1){
        tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans700.otf");
    }else{
        tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans500.otf");
    }
    super.setTypeface(tf, 0);
}
Sam Dozor
sumber
2

Solusi Tom bekerja dengan baik, tetapi hanya bekerja dengan TextView dan EditText.

Jika Anda ingin menutupi sebagian besar tampilan (RadioGroup, TextView, Checkbox ...), saya membuat metode melakukan itu:

protected void changeChildrenFont(ViewGroup v, Typeface font){
    for(int i = 0; i < v.getChildCount(); i++){

        // For the ViewGroup, we'll have to use recursivity
        if(v.getChildAt(i) instanceof ViewGroup){
            changeChildrenFont((ViewGroup) v.getChildAt(i), font);
        }
        else{
            try {
                Object[] nullArgs = null;
                //Test wether setTypeface and getTypeface methods exists
                Method methodTypeFace = v.getChildAt(i).getClass().getMethod("setTypeface", new Class[] {Typeface.class, Integer.TYPE});
                //With getTypefaca we'll get back the style (Bold, Italic...) set in XML
                Method methodGetTypeFace = v.getChildAt(i).getClass().getMethod("getTypeface", new Class[] {});
                Typeface typeFace = ((Typeface)methodGetTypeFace.invoke(v.getChildAt(i), nullArgs));
                //Invoke the method and apply the new font with the defined style to the view if the method exists (textview,...)
                methodTypeFace.invoke(v.getChildAt(i), new Object[] {font, typeFace == null ? 0 : typeFace.getStyle()});
            }
            //Will catch the view with no such methods (listview...)
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Metode ini akan mendapatkan kembali gaya tampilan yang ditetapkan dalam XML (tebal, miring ...) dan menerapkannya jika ada.

Untuk ListView, saya selalu membuat adaptor, dan saya mengatur font di dalam getView.

FR073N
sumber
2

Saya menulis sebuah kelas yang menetapkan jenis huruf ke tampilan dalam hierarki tampilan saat ini dan berdasarkan pada properti jenis huruf saat ini (tebal, normal, Anda dapat menambahkan gaya lain jika Anda mau):

public final class TypefaceAssigner {

public final Typeface DEFAULT;
public final Typeface DEFAULT_BOLD;

@Inject
public TypefaceAssigner(AssetManager assetManager) {
    DEFAULT = Typeface.createFromAsset(assetManager, "TradeGothicLTCom.ttf");
    DEFAULT_BOLD = Typeface.createFromAsset(assetManager, "TradeGothicLTCom-Bd2.ttf");
}

public void assignTypeface(View v) {
    if (v instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) v).getChildCount(); i++) {
            View view = ((ViewGroup) v).getChildAt(i);
            if (view instanceof ViewGroup) {
                setTypeface(view);
            } else {
                setTypeface(view);
            }
        }
    } else {
        setTypeface(v);
    }
}

private void setTypeface(View view) {
    if (view instanceof TextView) {
        TextView textView = (TextView) view;
        Typeface typeface = textView.getTypeface();
        if (typeface != null && typeface.isBold()) {
            textView.setTypeface(DEFAULT_BOLD);
        } else {
            textView.setTypeface(DEFAULT);
        }
    }
}
}

Sekarang di semua fragmen di onViewCreated atau onCreateView, di semua aktivitas di onCreate, dan di semua adaptor tampilan di getView atau newView, panggil saja:

typefaceAssigner.assignTypeface(view);
Ivan Kravchenko
sumber
2

di api 26 dengan build.gradle 3.0.0 dan lebih tinggi Anda dapat membuat direktori font di res dan menggunakan baris ini dalam gaya Anda

<item name="android:fontFamily">@font/your_font</item>

untuk perubahan build.gradle gunakan ini di dependecies build.gradle Anda

classpath 'com.android.tools.build:gradle:3.0.0'
Mohammad Hosein Heidari
sumber
dan bagaimana cara memasukkan font ke dalam proyek?
azerafati
@azerafati salin font Anda ke res / font
Mohammad Hosein Heidari
ya, tanx. Saya sudah mendapatkannya. Tapi itu itemsaja tidak mengatur font untuk seluruh aplikasi. ada petunjuk?
azerafati
1

Akhirnya, Google menyadari beratnya masalah ini (menerapkan font khusus untuk komponen UI) dan mereka menemukan solusi bersih untuknya.

Pertama, Anda perlu memperbarui untuk mendukung perpustakaan 26+ (Anda mungkin juga perlu memperbarui gradle {4.0+} Anda, studio android), kemudian Anda dapat membuat folder sumber daya baru yang disebut font. Dalam folder ini, Anda dapat meletakkan sumber daya font Anda (.tff, ...). Maka Anda perlu mengganti aplikasi default mereka dan memaksa font khusus Anda ke dalamnya :)

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:fontFamily">@font/my_custom_font</item>
</style>

Catatan: jika Anda ingin mendukung perangkat dengan API lebih lama dari 16, Anda harus menggunakan namespace aplikasi alih-alih android!

Mr.Q
sumber
0

Saya juga ingin meningkatkan jawaban weston untuk API 21 Android 5.0.

Saya memiliki masalah yang sama pada Samsung S5 saya, ketika menggunakan font DEFAULT. (dengan font lain berfungsi dengan baik)

Saya berhasil membuatnya bekerja dengan mengatur jenis huruf ("sans" misalnya) dalam file XML, untuk setiap Textview atau Tombol

<TextView
android:layout_width="match_parent"
android:layout_height="39dp"
android:textColor="@color/abs__background_holo_light"
android:textSize="12sp"
android:gravity="bottom|center"
android:typeface="sans" />

dan di Kelas Aplikasi Saya:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
    TypefaceUtil.overrideFont(getApplicationContext(), "SANS_SERIF",
    "fonts/my_font.ttf");
    }
}

Semoga ini bisa membantu.

kayu steven
sumber
0

Kaligrafi berfungsi dengan baik, tetapi tidak cocok untuk saya, karena tidak mendukung bobot yang berbeda (tebal, miring, dll) untuk font-family.

Jadi saya mencoba Fontain , yang memungkinkan Anda untuk menentukan Tampilan kustom dan menerapkannya keluarga font kustom.

untuk menggunakan Fontain, Anda harus menambahkan yang berikut ke build.gradle modul aplikasi Anda:

compile 'com.scopely:fontain:1.0.0'

Kemudian, alih-alih menggunakan TextView biasa, Anda harus menggunakan FontTextView

Contoh FontTextView dengan konten huruf besar dan tebal:

 <com.scopely.fontain.views.FontTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/black"
            android:textColor="@android:color/white"
            android:textSize="11dp"
            android:gravity="center"
            android:id="@+id/tv1"
            app:font_family="myCustomFont"
            app:caps_mode="characters"
            app:font_weight="BOLD"/>
Cris
sumber
0
package com.theeasylearn.demo.designdemo;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;

public class MyButton extends TextView {

    public MyButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

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

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

    private void init() {

            Typeface tf =
                    Typeface.createFromAsset(
                            getContext().getAssets(), "angelina.TTF");
            setTypeface(tf);

    }

}
Akademi EasyLearn
sumber
Bukan solusi yang sempurna. Menggunakan solusi ini akan memerlukan workarounds kustom untuk akses default Android TextViews
blueware
0

Untuk mengubah keluarga font default dari TextViews, ganti textViewStyle di tema aplikasi Anda.

Untuk menggunakan font khusus di fontFamily, gunakan sumber daya font yang ada di perpustakaan dukungan.

Fitur ini ditambahkan di Android 26 tetapi di-backport ke versi yang lebih lama melalui supportlib.

https://developer.android.com/guide/topics/resources/font-resource.html https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html # using-support-lib

Siyamed
sumber
0

Sejak rilis Android Oreo dan perpustakaan pendukungnya (26.0.0), Anda dapat melakukan ini dengan mudah. Lihat jawaban ini dalam pertanyaan lain.

Pada dasarnya gaya akhir Anda akan terlihat seperti ini:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
   <item name="fontFamily">@font/your_font</item> <!-- target android sdk versions < 26 and > 14 -->
</style>
João Magalhães
sumber
-15

Ya, dimungkinkan untuk mengatur font ke seluruh aplikasi.

Cara termudah untuk mencapai ini adalah mengemas font yang diinginkan dengan aplikasi Anda.

Untuk melakukan ini, cukup buat aset / folder di root proyek, dan letakkan font Anda (dalam bentuk TrueType, atau TTF) di aset.

Anda mungkin, misalnya, membuat aset / font / dan meletakkan file TTF Anda di sana.

public class FontSampler extends Activity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView tv=(TextView)findViewById(R.id.custom);

Typeface face=Typeface.createFromAsset(getAssets(), "fonts/HandmadeTypewriter.ttf");
tv.setTypeface(face);
}
}
Selvakumar
sumber