Menggunakan jenis huruf khusus di Android

111

Saya ingin menggunakan font khusus untuk aplikasi android saya yang saya buat.
Saya dapat mengubah jenis huruf setiap objek dari Code secara individual, tetapi saya memiliki ratusan.

Begitu,

  • Apakah ada cara untuk melakukan ini dari XML? [Menyetel jenis huruf khusus]
  • Apakah ada cara untuk melakukannya dari kode di satu tempat, untuk mengatakan bahwa seluruh aplikasi dan semua komponen harus menggunakan jenis huruf kustom, bukan yang default?
Codevalley
sumber
stackoverflow.com/questions/5541058/… Lihat posting ini saya memposting kode lengkap di sini mengenai masalah ini
Manish Singla
Anda dapat menggunakan variabel statis pada aktivitas utama Anda untuk menyimpan referensi ke font yang disematkan. Itu akan menyebabkan ada satu set font tetap yang tidak akan diambil oleh GC.
Jacksonkr
Metode pabrik. Atau metode yang sesuai dengan pandangan Anda dan menyetel semua setelan font dan jenis huruf.
mtmurdock
Pustaka dukungan 26 baru sekarang memungkinkan Anda menggunakan font dalam XML. Berikut adalah cara membuat Font dalam XML
Vinicius Silva

Jawaban:

80

Apakah ada cara untuk melakukan ini dari XML?

Tidak, maaf. Anda hanya dapat menentukan tipografi bawaan melalui XML.

Apakah ada cara untuk melakukannya dari kode di satu tempat, untuk mengatakan bahwa seluruh aplikasi dan semua komponen harus menggunakan jenis huruf kustom, bukan yang default?

Aku tidak menyadarinya.

Ada berbagai opsi untuk ini saat ini:

  • Sumber daya font dan backport di Android SDK, jika Anda menggunakan appcompat

  • Pustaka pihak ketiga untuk mereka yang tidak menggunakan appcompat, meskipun tidak semua akan mendukung pendefinisian font di sumber tata letak

CommonsWare
sumber
4
@ Codevalley: Nah, dalam banyak hal, jawaban yang lebih baik adalah tidak repot dengan font khusus. Mereka cenderung besar, membuat unduhan Anda lebih besar dan mengurangi jumlah orang yang akan mengunduh dan tetap menggunakan aplikasi Anda.
CommonsWare
22
@CommonsWare: Saya belum tentu setuju. Typeface adalah bagian integral dari Styling UI seperti yang Anda lakukan dengan gambar latar belakang dll. Dan ukurannya tidak selalu besar. Misalnya, font dalam kasus saya hanya 19.6KB :)
Codevalley
2
@Amit: Tidak ada perubahan pada masalah ini. Ada banyak potongan kode untuk membantu menyederhanakan penerapan jenis huruf ke UI Anda di Java, tetapi tidak ada cara untuk melakukannya dari XML.
CommonsWare
1
@Amit: "Tapi apakah itu berarti saya harus membuat file .ttf atau .otf saya sendiri untuk font kustom?" - um, tidak. Anda dapat menggunakan font TTF / OTF yang ada, meskipun mungkin tidak semuanya berfungsi. Masalah pada pertanyaan ini adalah bagaimana menerapkan font tersebut di seluruh aplikasi, yang masih tidak memungkinkan, dan itulah yang saya maksud dalam komentar saya.
CommonsWare
1
Jawaban yang diterima ini sudah usang, dan akan sangat bagus untuk memperbaruinya atau menghapusnya.
Sky Kelsey
109

Ya itu mungkin.

Anda harus membuat tampilan kustom yang memperluas tampilan teks.

Di attrs.xmldalam valuesfolder:

<resources>
    <declare-styleable name="MyTextView">
        <attr name="first_name" format="string"/>
        <attr name="last_name" format="string"/>
        <attr name="ttf_name" format="string"/>
    </declare-styleable>
</resources>

Masuk main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:lht="http://schemas.android.com/apk/res/com.lht"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView  android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Hello"/>
    <com.lht.ui.MyTextView  
        android:id="@+id/MyTextView"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Hello friends"
        lht:ttf_name="ITCBLKAD.TTF"
        />   
</LinearLayout>

Masuk MyTextView.java:

package com.lht.ui;

import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class MyTextView extends TextView {

    Context context;
    String ttfName;

    String TAG = getClass().getName();

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;

        for (int i = 0; i < attrs.getAttributeCount(); i++) {
            Log.i(TAG, attrs.getAttributeName(i));
            /*
             * Read value of custom attributes
             */

            this.ttfName = attrs.getAttributeValue(
                    "http://schemas.android.com/apk/res/com.lht", "ttf_name");
            Log.i(TAG, "firstText " + firstText);
            // Log.i(TAG, "lastText "+ lastText);

            init();
        }

    }

    private void init() {
        Typeface font = Typeface.createFromAsset(context.getAssets(), ttfName);
        setTypeface(font);
    }

    @Override
    public void setTypeface(Typeface tf) {

        // TODO Auto-generated method stub
        super.setTypeface(tf);
    }

}
Manish Singla
sumber
4
Ini akan berhasil, tetapi hanya untuk TextView. Ini akan membutuhkan subclass khusus untuk setiap kelas widget yang mewarisi dari TextViewmana kemampuan yang sama diinginkan.
CommonsWare
Hai Manish, Terima kasih atas solusinya. Meskipun saya menghadapi masalah dalam menggunakan ini. Saya terus mendapatkan 'tidak ada pengenal sumber daya yang ditemukan untuk atribut ttf_name dalam paket com.lht.android'
Kshitij Aggarwal
17
Ini akan bekerja, tetapi pra-ICS itu akan mengalokasikan memori untuk font untuk setiap tampilan yang Anda buat: code.google.com/p/android/issues/detail?id=9904 Cara untuk memperbaikinya adalah dengan membuat yang dapat diakses secara global hashmap statis dari semua font yang dipakai: code.google.com/p/android/issues/detail?id=9904#c7
Ken Van Hoeylandt
Mengapa kita membutuhkan loop ?, Haruskah itu tidak berfungsi dengan satu panggilan?
Guillermo Tobar
1
@Kartun_anak. jika Anda perlu menyetel tipografi yang berbeda ke TextView yang berbeda ...
Nick
49

Saya melakukan ini dengan cara yang lebih "brute force" yang tidak memerlukan perubahan pada layout xml atau Activities.

Diuji pada Android versi 2.1 hingga 4.4. Jalankan ini saat memulai aplikasi, di kelas Aplikasi Anda:

private void setDefaultFont() {

    try {
        final Typeface bold = Typeface.createFromAsset(getAssets(), DEFAULT_BOLD_FONT_FILENAME);
        final Typeface italic = Typeface.createFromAsset(getAssets(), DEFAULT_ITALIC_FONT_FILENAME);
        final Typeface boldItalic = Typeface.createFromAsset(getAssets(), DEFAULT_BOLD_ITALIC_FONT_FILENAME);
        final Typeface regular = Typeface.createFromAsset(getAssets(),DEFAULT_NORMAL_FONT_FILENAME);

        Field DEFAULT = Typeface.class.getDeclaredField("DEFAULT");
        DEFAULT.setAccessible(true);
        DEFAULT.set(null, regular);

        Field DEFAULT_BOLD = Typeface.class.getDeclaredField("DEFAULT_BOLD");
        DEFAULT_BOLD.setAccessible(true);
        DEFAULT_BOLD.set(null, bold);

        Field sDefaults = Typeface.class.getDeclaredField("sDefaults");
        sDefaults.setAccessible(true);
        sDefaults.set(null, new Typeface[]{
                regular, bold, italic, boldItalic
        });

    } catch (NoSuchFieldException e) {
        logFontError(e);
    } catch (IllegalAccessException e) {
        logFontError(e);
    } catch (Throwable e) {
        //cannot crash app if there is a failure with overriding the default font!
        logFontError(e);
    }
}

Untuk contoh yang lebih lengkap, lihat http://github.com/perchrh/FontOverrideExample

Per Christian Henden
sumber
Ini adalah solusi terbaik untuk saya.
Igor K
2
default tidak bekerja untuk saya. jika saya menggunakan monospace lalu menyetel code<style name = "AppTheme" parent = "AppBaseTheme"> <item name = "android: typeface"> monospace </item> </style>, codeini berfungsi tetapi tidak untuk huruf tebal. saya menambahkan kode ini di kelas yang memperluas Aplikasi. apakah itu tempat yang benar? @ P-chan
Christopher Rivera
2
@ChristopherRivera Ya, tambahkan ke kelas Aplikasi aplikasi Anda, pastikan ia berjalan di onCreate. Lihat grepcode.com/file/repository.grepcode.com/java/ext/… Saya sarankan Anda mengganti field tambahan untuk monospace serta yang ada di kode contoh saya di atas!
Per Christian Henden
2
Oke, saya mengganti bidang SERIF dan berhasil :)
Abdullah Umer
3
Jawaban ini mereferensikan jawaban ini, dan memberikan pendekatan yang lebih bersih.
adamdport
36

Meskipun saya meningkatkan jawaban Manish sebagai metode tercepat dan paling bertarget, saya juga telah melihat solusi naif yang hanya berulang secara rekursif melalui hierarki tampilan dan memperbarui tipografi semua elemen secara bergantian. Sesuatu seperti ini:

public static void applyFonts(final View v, Typeface fontToSet)
{
    try {
        if (v instanceof ViewGroup) {
            ViewGroup vg = (ViewGroup) v;
            for (int i = 0; i < vg.getChildCount(); i++) {
                View child = vg.getChildAt(i);
                applyFonts(child, fontToSet);
            }
        } else if (v instanceof TextView) {
            ((TextView)v).setTypeface(fontToSet);
        }
    } catch (Exception e) {
        e.printStackTrace();
        // ignore
    }
}

Anda perlu memanggil fungsi ini pada tampilan Anda baik setelah memekarkan tata letak dan dalam onContentChanged()metode Aktivitas Anda .

pospi
sumber
Kurang lebih. Pada saat itu, itu adalah satu-satunya cara untuk melakukannya dalam kerangka waktu proyek. Pintasan praktis jika diperlukan (:
pospi
23

Saya bisa melakukan ini secara terpusat, inilah hasilnya:

masukkan deskripsi gambar di sini

Saya telah mengikuti Activitydan saya memperpanjang darinya jika saya membutuhkan font khusus:

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater.Factory;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class CustomFontActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    getLayoutInflater().setFactory(new Factory() {

        @Override
        public View onCreateView(String name, Context context,
                AttributeSet attrs) {
            View v = tryInflate(name, context, attrs);
            if (v instanceof TextView) {
                setTypeFace((TextView) v);
            }
            return v;
        }
    });
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

private View tryInflate(String name, Context context, AttributeSet attrs) {
    LayoutInflater li = LayoutInflater.from(context);
    View v = null;
    try {
        v = li.createView(name, null, attrs); 
    } catch (Exception e) {
        try {
            v = li.createView("android.widget." + name, null, attrs);
        } catch (Exception e1) {
        }
    }
    return v;
}

private void setTypeFace(TextView tv) {
    tv.setTypeface(FontUtils.getFonts(this, "MTCORSVA.TTF"));
}
}

Tetapi jika saya menggunakan aktivitas dari paket dukungan misalnya, FragmentActivitymaka saya menggunakan ini Activity:

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class CustomFontFragmentActivity extends FragmentActivity {

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

// we can't setLayout Factory as its already set by FragmentActivity so we
// use this approach
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    View v = super.onCreateView(name, context, attrs);
    if (v == null) {
        v = tryInflate(name, context, attrs);
        if (v instanceof TextView) {
            setTypeFace((TextView) v);
        }
    }
    return v;
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public View onCreateView(View parent, String name, Context context,
        AttributeSet attrs) {
    View v = super.onCreateView(parent, name, context, attrs);
    if (v == null) {
        v = tryInflate(name, context, attrs);
        if (v instanceof TextView) {
            setTypeFace((TextView) v);
        }
    }
    return v;
}

private View tryInflate(String name, Context context, AttributeSet attrs) {
    LayoutInflater li = LayoutInflater.from(context);
    View v = null;
    try {
        v = li.createView(name, null, attrs);
    } catch (Exception e) {
        try {
            v = li.createView("android.widget." + name, null, attrs);
        } catch (Exception e1) {
        }
    }
    return v;
}

private void setTypeFace(TextView tv) {
    tv.setTypeface(FontUtils.getFonts(this, "MTCORSVA.TTF"));
}
}

Saya belum menguji kode ini dengan Fragments, tapi semoga bisa berhasil.

My FontUtilsis simple yang juga memecahkan masalah pra-ICS yang disebutkan di sini https://code.google.com/p/android/issues/detail?id=9904 :

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.graphics.Typeface;

public class FontUtils {

private static Map<String, Typeface> TYPEFACE = new HashMap<String, Typeface>();

public static Typeface getFonts(Context context, String name) { 
    Typeface typeface = TYPEFACE.get(name);
    if (typeface == null) {
        typeface = Typeface.createFromAsset(context.getAssets(), "fonts/"
                + name);
        TYPEFACE.put(name, typeface);
    }
    return typeface;
}
}
M-WaJeEh
sumber
2
Ini harus mendapatkan lebih banyak suara. Ini berfungsi dan memiliki tangkapan layar untuk demonstrasi
ericn
10

Hai, saya juga membutuhkan 2 font berbeda di aplikasi saya untuk widget berbeda! Saya menggunakan cara ini:

Di kelas Aplikasi saya, saya membuat metode statis:

public static Typeface getTypeface(Context context, String typeface) {
    if (mFont == null) {
        mFont = Typeface.createFromAsset(context.getAssets(), typeface);
    }
    return mFont;
}

Jenis huruf String mewakili xyz.ttf di folder aset. (Saya membuat Kelas Konstanta) Sekarang Anda dapat menggunakan ini di mana saja di aplikasi Anda:

mTextView = (TextView) findViewById(R.id.text_view);
mTextView.setTypeface(MyApplication.getTypeface(this, Constants.TYPEFACE_XY));

Satu-satunya masalah adalah, Anda memerlukan ini untuk setiap widget di mana Anda ingin menggunakan Font! Tapi saya pikir ini cara terbaik.

Informatic0re
sumber
4

Menggunakan saran pospi dan bekerja dengan properti 'tag' seperti yang dilakukan Richard , saya membuat kelas khusus yang memuat font khusus saya dan menerapkannya ke tampilan sesuai dengan tag mereka.

Jadi pada dasarnya, alih-alih menyetel TypeFace dalam atribut android: fontFamily Anda menggunakan android: tag attritube dan menyetelnya ke salah satu enum yang ditentukan.

public class Fonts {
    private AssetManager mngr;

    public Fonts(Context context) {
        mngr = context.getAssets();
    }
    private enum AssetTypefaces {
        RobotoLight,
        RobotoThin,
        RobotoCondensedBold,
        RobotoCondensedLight,
        RobotoCondensedRegular
    }

    private Typeface getTypeface(AssetTypefaces font) {
        Typeface tf = null;
        switch (font) {
            case RobotoLight:
                tf = Typeface.createFromAsset(mngr,"fonts/Roboto-Light.ttf");
                break;
            case RobotoThin:
                tf = Typeface.createFromAsset(mngr,"fonts/Roboto-Thin.ttf");
                break;
            case RobotoCondensedBold:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Bold.ttf");
                break;
            case RobotoCondensedLight:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Light.ttf");
                break;
            case RobotoCondensedRegular:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Regular.ttf");
                break;
            default:
                tf = Typeface.DEFAULT;
                break;
        }
        return tf;
    }
    public void setupLayoutTypefaces(View v) {
        try {
            if (v instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) v;
                for (int i = 0; i < vg.getChildCount(); i++) {
                    View child = vg.getChildAt(i);
                    setupLayoutTypefaces(child);
                }
            } else if (v instanceof TextView) {
                if (v.getTag().toString().equals(AssetTypefaces.RobotoLight.toString())){
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoLight));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedRegular.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedRegular));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedBold.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedBold));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedLight.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedLight));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoThin.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoThin));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            // ignore
        }
    }
}

Dalam Aktivitas atau Fragmen Anda baru saja menelepon

Fonts fonts = new Fonts(getActivity());
fonts.setupLayoutTypefaces(mainLayout);
majinboo
sumber
4

Saya menemukan solusi yang bagus di blog Lisa Wray . Dengan data binding yang baru, dimungkinkan untuk menyetel font di file XML Anda.

@BindingAdapter({"bind:font"})
public static void setFont(TextView textView, String fontName){
    textView.setTypeface(Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + fontName));
}

Dalam XML:

<TextView
app:font="@{`Source-Sans-Pro-Regular.ttf`}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
userM1433372
sumber
Dapatkah Anda menyarankan contoh menggunakan Data Binding? Itu akan sangat dihargai.
Sri Krishna
3

Saya pikir ada cara yang lebih praktis untuk melakukannya. Kelas berikut akan menyetel wajah tipe khusus untuk semua komponen aplikasi Anda (dengan setelan per kelas).

/**
 * Base Activity of our app hierarchy.
 * @author SNI
 */
public class BaseActivity extends Activity {

    private static final String FONT_LOG_CAT_TAG = "FONT";
    private static final boolean ENABLE_FONT_LOGGING = false;

    private Typeface helloTypeface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        helloTypeface = Typeface.createFromAsset(getAssets(), "fonts/<your type face in assets/fonts folder>.ttf");
    }

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        View view = super.onCreateView(name, context, attrs);
        return setCustomTypeFaceIfNeeded(name, attrs, view);
    }

    @Override
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
        View view = super.onCreateView(parent, name, context, attrs);
        return setCustomTypeFaceIfNeeded(name, attrs, view);
    }

    protected View setCustomTypeFaceIfNeeded(String name, AttributeSet attrs, View view) {
        View result = null;
        if ("TextView".equals(name)) {
            result = new TextView(this, attrs);
            ((TextView) result).setTypeface(helloTypeface);
        }

        if ("EditText".equals(name)) {
            result = new EditText(this, attrs);
            ((EditText) result).setTypeface(helloTypeface);
        }

        if ("Button".equals(name)) {
            result = new Button(this, attrs);
            ((Button) result).setTypeface(helloTypeface);
        }

        if (result == null) {
            return view;
        } else {
            if (ENABLE_FONT_LOGGING) {
                Log.v(FONT_LOG_CAT_TAG, "A type face was set on " + result.getId());
            }
            return result;
        }
    }

}
Snicolas
sumber
2

Implementasi default LayoutInflater tidak mendukung penentuan jenis huruf font dari xml. Namun saya telah melihatnya dilakukan di xml dengan menyediakan pabrik kustom untuk LayoutInflater yang akan mengurai atribut tersebut dari tag xml.

Struktur dasarnya akan seperti ini.

public class TypefaceInflaterFactory implements LayoutInflater.Factory {

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        // CUSTOM CODE TO CREATE VIEW WITH TYPEFACE HERE
        // RETURNING NULL HERE WILL TELL THE INFLATER TO USE THE
        // DEFAULT MECHANISMS FOR INFLATING THE VIEW FROM THE XML
    }

}

public class BaseActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater.from(this).setFactory(new TypefaceInflaterFactory());
    }
}

Artikel ini memberikan penjelasan yang lebih mendalam tentang mekanisme ini dan bagaimana penulis mencoba memberikan dukungan tata letak xml untuk tipografi dengan cara ini. Kode untuk implementasi penulis dapat ditemukan di sini .

Ryan Thomas
sumber
1

Mengatur font khusus menjadi ProgressDialog / AlertDialog biasa:

font=Typeface.createFromAsset(getAssets(),"DroidSans.ttf");

ProgressDialog dialog = ProgressDialog.show(this, "titleText", "messageText", true);
((TextView)dialog.findViewById(Resources.getSystem().getIdentifier("message", "id", "android"))).setTypeface(font);
((TextView)dialog.findViewById(Resources.getSystem().getIdentifier("alertTitle", "id", "android"))).setTypeface(font);
artProc
sumber
1

Ya, itu dimungkinkan dengan mengganti jenis huruf default. Saya mengikuti solusi ini dan itu bekerja seperti pesona untuk semua TextView dan teks ActionBar juga dengan satu perubahan.

public class MyApp extends Application {

  @Override
  public void onCreate() {
    TypefaceUtil.overrideFont(getApplicationContext(), "SERIF", "fonts/Roboto-Regular.ttf"); // font from assets: "assets/fonts/Roboto-Regular.ttf
  }
}

styles.xml

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/pantone</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowTranslucentStatus" tools:targetApi="kitkat">true</item>
    <item name="android:windowDisablePreview">true</item>
    <item name="android:typeface">serif</item>
</style>

Alih-alih themes.xml seperti yang disebutkan dalam tautan di atas, saya menyebutkan font default untuk diganti di styles.xml saya di tag tema aplikasi default saya. Jenis huruf default yang dapat ditimpa adalah serif, sans, monospace, dan normal.

TypefaceUtil.java

public class TypefaceUtil {

    /**
     * Using reflection to override default typeface
     * NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
     * @param context to work with assets
     * @param defaultFontNameToOverride for example "monospace"
     * @param customFontFileNameInAssets file name of the font from assets
     */
    public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
        try {
            final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);

            final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
            defaultFontTypefaceField.setAccessible(true);
            defaultFontTypefaceField.set(null, customFontTypeface);
        } catch (Exception e) {
            Log.e("Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
        }
    }
}

Awalnya, saya tidak tahu tipografi yang akan ditimpa adalah tetap dan kumpulan nilai yang ditentukan tetapi akhirnya membantu saya memahami bagaimana Android menangani font dan tipografi dan nilai defaultnya, yang merupakan sudut pandang yang berbeda.

Amruta-Pani
sumber
0

Saya tidak tahu apakah itu mengubah seluruh aplikasi, tetapi saya telah berhasil mengubah beberapa komponen yang tidak dapat diubah dengan melakukan ini:

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Lucida Sans Unicode.ttf");
Typeface.class.getField("DEFAULT").setAccessible(true);
Typeface.class.getField("DEFAULT_BOLD").setAccessible(true);
Typeface.class.getField("DEFAULT").set(null, tf);
Typeface.class.getField("DEFAULT_BOLD").set(null, tf);
Richard
sumber
2
Sayangnya ini tidak berfungsi lagi: java.lang.IllegalAccessException: field ditandai 'final' di java.lang.reflect.Field.setField (Metode Asli) di java.lang.reflect.Field.set (Field.java: 556)
BoD
0

Saya suka saran pospi. Mengapa tidak pergi semua menggunakan properti 'tag' dari sebuah tampilan (yang bisa Anda tentukan di XML - 'android: tag') untuk menentukan gaya tambahan yang tidak bisa Anda lakukan di XML. Saya suka JSON jadi saya akan menggunakan string JSON untuk menentukan kumpulan kunci / nilai. Kelas ini melakukan tugasnya - panggil saja Style.setContentView(this, [resource id])aktivitas Anda.

public class Style {

  /**
   * Style a single view.
   */
  public static void apply(View v) {
    if (v.getTag() != null) {
      try {
        JSONObject json = new JSONObject((String)v.getTag());
        if (json.has("typeface") && v instanceof TextView) {
          ((TextView)v).setTypeface(Typeface.createFromAsset(v.getContext().getAssets(),
                                                             json.getString("typeface")));
        }
      }
      catch (JSONException e) {
        // Some views have a tag without it being explicitly set!
      }
    }
  }

  /**
   * Style the passed view hierarchy.
   */
  public static View applyTree(View v) {
    apply(v);
    if (v instanceof ViewGroup) {
      ViewGroup g = (ViewGroup)v;
      for (int i = 0; i < g.getChildCount(); i++) {
        applyTree(g.getChildAt(i));
      }
    }
    return v;
  }

  /**
   * Inflate, style, and set the content view for the passed activity.
   */
  public static void setContentView(Activity activity, int resource) {
    activity.setContentView(applyTree(activity.getLayoutInflater().inflate(resource, null)));
  }
}

Jelas Anda ingin menangani lebih dari sekedar jenis huruf agar menggunakan JSON bermanfaat.

Manfaat dari properti 'tag' adalah Anda dapat mengaturnya pada gaya dasar yang Anda gunakan sebagai tema dan dengan demikian menerapkannya ke semua tampilan Anda secara otomatis. EDIT: Melakukan ini menyebabkan crash selama inflasi di Android 4.0.3. Anda masih dapat menggunakan gaya dan menerapkannya ke tampilan teks satu per satu.

Satu hal yang akan Anda lihat di kode - beberapa tampilan memiliki tag tanpa satu pun yang disetel secara eksplisit - anehnya itu adalah string 'Αποκοπή' - yang 'dipotong' dalam bahasa Yunani, menurut google translate! Apa apaan...?

Richard
sumber
0

Jawaban @ majinboo direvisi untuk kinerja dan manajemen memori. Lebih dari satu font membutuhkan Aktivitas terkait dapat menggunakan kelas Font ini dengan memberikan konstruktor itu sendiri sebagai parameter.

@Override
public void onCreate(Bundle savedInstanceState)
{
    Font font = new Font(this);
}

Kelas Font yang direvisi adalah sebagai berikut:

public class Fonts
{
    private HashMap<AssetTypefaces, Typeface> hashMapFonts;

    private enum AssetTypefaces
    {
        RobotoLight,
        RobotoThin,
        RobotoCondensedBold,
        RobotoCondensedLight,
        RobotoCondensedRegular
    }

    public Fonts(Context context)
    {
        AssetManager mngr = context.getAssets();

        hashMapFonts = new HashMap<AssetTypefaces, Typeface>();
        hashMapFonts.put(AssetTypefaces.RobotoLight, Typeface.createFromAsset(mngr, "fonts/Roboto-Light.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoThin, Typeface.createFromAsset(mngr, "fonts/Roboto-Thin.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedBold, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Bold.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedLight, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Light.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedRegular, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Regular.ttf"));
    }

    private Typeface getTypeface(String fontName)
    {
        try
        {
            AssetTypefaces typeface = AssetTypefaces.valueOf(fontName);
            return hashMapFonts.get(typeface);
        }
        catch (IllegalArgumentException e)
        {
            // e.printStackTrace();
            return Typeface.DEFAULT;
        }
    }

    public void setupLayoutTypefaces(View v)
    {
        try
        {
            if (v instanceof ViewGroup)
            {
                ViewGroup vg = (ViewGroup) v;
                for (int i = 0; i < vg.getChildCount(); i++)
                {
                    View child = vg.getChildAt(i);
                    setupLayoutTypefaces(child);
                }
            }
            else if (v instanceof TextView)
            {
                ((TextView) v).setTypeface(getTypeface(v.getTag().toString()));
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            // ignore
        }
    }
}
Suphi ÇEVİKER
sumber
0

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
0

Sepertinya penggunaan font khusus telah dipermudah dengan Android O, pada dasarnya Anda dapat menggunakan xml untuk melakukannya. Saya telah melampirkan tautan ke dokumentasi resmi Android untuk referensi, dan semoga ini akan membantu orang-orang yang masih membutuhkan solusi ini. Bekerja dengan font khusus di Android

Mohale
sumber
0

Mungkin berguna untuk mengetahui bahwa mulai dari Android 8.0 (API level 26) Anda bisa menggunakan font khusus dalam XML .

Sederhananya, Anda bisa melakukannya dengan cara berikut.

  1. Letakkan font di folder tersebut res/font.

  2. Baik menggunakannya dalam atribut widget

<Button android:fontFamily="@font/myfont"/>

atau masukkan res/values/styles.xml

<style name="MyButton" parent="android:Widget.Button">
    <item name="android:fontFamily">@font/myfont</item>
</style>

dan menggunakannya sebagai gaya

<Button style="@style/MyButton"/>
Vic
sumber
0

Gunakan atribut "fontPath" secara langsung di file xml.

untuk digunakan dalam style.xml

<item name = "fontPath"> font / ProximaNovaSemibold.ttf </item>

untuk digunakan dalam file tata letak langsung

fontPath = "font / ProximaNovaBold.ttf"

(Catatan: Tidak perlu menggunakan atribut app / android di awalan)

Dharmendra
sumber
-6

Sangat mungkin. Banyak cara untuk melakukannya. Cara tercepat, buat kondisi dengan metode coba-tangkap .. coba kondisi gaya font tertentu Anda, tangkap kesalahannya, dan tentukan gaya font lainnya.

haloyudi
sumber
7
dapatkah Anda memberikan demo untuk membuktikan jawaban Anda?
Tandai