Android'de özel bir yazı tipi kullanma


111

Oluşturmakta olduğum android uygulamam için özel bir yazı tipi kullanmak istiyorum.
Koddan her nesnenin yazı tipini ayrı ayrı değiştirebilirim, ancak yüzlerim var.

Yani,

  • Bunu XML'den yapmanın bir yolu var mı? [Özel bir yazı tipi belirleme]
  • Bunu tek bir yerde koddan yapmanın, tüm uygulamanın ve tüm bileşenlerin varsayılan yazı tipi yerine özel yazı tipini kullanması gerektiğini söylemenin bir yolu var mı?


Gömülü fontlara referansları tutmak için ana etkinliğinizde statik değişkenler kullanabilirsiniz. Bu, GC tarafından alınmayacak kalıcı bir yazı tipi kümesi olmasına neden olur.
Jacksonkr

Fabrika yöntemi. Veya görünümünüzü alan ve tüm yazı tipi ve yazı tipi ayarlarını belirleyen bir yöntem.
mtmurdock

Yeni destek kitaplığı 26 artık yazı tiplerini XML'de kullanmanıza izin veriyor. İşte XML'de Yazı Tipleri
Vinicius Silva

Yanıtlar:


80

Bunu XML'den yapmanın bir yolu var mı?

Hayır, üzgünüm. Yerleşik yazı tiplerini yalnızca XML aracılığıyla belirtebilirsiniz.

Bunu tek bir yerde koddan yapmanın, tüm uygulamanın ve tüm bileşenlerin varsayılan yazı tipi yerine özel yazı tipini kullanması gerektiğini söylemenin bir yolu var mı?

Bildiğim kadarıyla ... değil.

Günümüzde bunlar için çeşitli seçenekler var:

  • Android SDK'da yazı tipi kaynakları ve arka portlar kullanıyorsanız appcompat

  • Kullanmayanlar için üçüncü taraf kitaplıklarıappcompat , hepsi olmasa da, düzen kaynaklarında yazı tipini tanımlamayı desteklemez


4
@Codevalley: Pek çok yönden daha iyi cevap, özel yazı tipleriyle uğraşmamaktır. Büyük olma eğilimindedirler, indirmelerinizi büyütür ve uygulamanızı indirip kullanmaya devam edecek kişi sayısını azaltırlar.
CommonsWare

22
@CommonsWare: Mutlaka aynı fikirde değilim. Yazı biçimi, arka plan resimleri vb. İle yaptığınız gibi UI Styling'in ayrılmaz bir parçasıdır. Ve boyut her zaman büyük olmayabilir. Örneğin, benim durumumdaki yazı tipi sadece 19.6KB :)
Codevalley

2
@ Kabul: Bu konuda bir değişiklik yok. Java'da kullanıcı arabiriminize bir yazı tipi uygulamayı basitleştirmeye yardımcı olacak birçok kod parçacığı vardır, ancak bunu XML'den yapmanın bir yolu yoktur.
CommonsWare

1
@Amit: "Ama bu, özel yazı tipleri için kendi .ttf veya .otf dosyalarımı oluşturmam gerektiği anlamına mı geliyor?" - hayır. Hepsi çalışmasa da mevcut TTF / OTF yazı tiplerini kullanabilirsiniz. Bu sorudaki sorun, bu yazı tiplerinin bir uygulamanın tamamına nasıl uygulanacağıdır, ki bu hala mümkün değildir ve yorumumda bahsettiğim şey buydu.
CommonsWare

1
Kabul edilen bu cevap eski ve onu güncellemek veya silmek harika olur.
Sky Kelsey

109

Evet mümkün.

Metin görünümünü genişleten özel bir görünüm oluşturmalısınız.

In attrs.xmliçinde valuesklasörünün:

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

İçinde 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>

İçinde 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);
    }

}

4
Bu işe yarayacak, ancak yalnızca için TextView. TextViewAynı kabiliyetin istendiği yerden miras alan her widget sınıfı için özel alt sınıflar gerektirecektir .
CommonsWare

Merhaba Manish, Çözüm için teşekkürler. Bununla birlikte, bunu kullanırken bir sorunla karşı karşıyayım. 'Com.lht.android paketindeki ttf_name özniteliği için hiçbir kaynak tanımlayıcısı bulunamadı'
Kshitij Aggarwal

17
Bu işe yarayacak, ancak ICS öncesi, başlattığınız her görünüm için yazı tipleri için bellek ayıracaktır: code.google.com/p/android/issues/detail?id=9904 Bunu düzeltmenin bir yolu, küresel olarak erişilebilir bir tüm örneklenmiş yazı tiplerinin statik
karma haritası

Neden bir döngüye ihtiyacımız var? Tek bir aramayla çalışmamalı mı?
Guillermo Tobar

1
@AlaksiejN. farklı Yazı Görünümleri için farklı yazı tipleri ayarlamanız gerekirse ...
Nick

49

Bunu, xml veya Etkinlikler düzeninde değişiklik gerektirmeyen daha "kaba kuvvet" yöntemiyle yaptım.

Android sürüm 2.1 ile 4.4 arasında test edilmiştir. Bunu, Uygulama sınıfınızda uygulama başlangıcında çalıştırın:

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

Daha eksiksiz bir örnek için bkz. Http://github.com/perchrh/FontOverrideExample


Bu benim için en iyi çözüm.
Igor K

2
varsayılan benim için çalışmıyor. monospace kullanırsam ve sonra code<style name = "AppTheme" parent = "AppBaseTheme"> <item name = "android: typeface"> monospace </item> </style> ayarlarsam codeçalışır, ancak kalın için değil. Bu kodu Application'ı genişleten bir sınıfa ekledim. burası doğru yer mi? @ P-chan
Christopher Rivera

2
@ChristopherRivera Evet, uygulamanızın Application sınıfına ekleyin, onCreate üzerinde çalıştığından emin olun. Grepcode.com/file/repository.grepcode.com/java/ext/… adresine bir göz atarak , monospace için ek alanı ve yukarıdaki örnek kodumdaki alanı geçersiz kılmanızı öneririm!
Per Christian Henden

2
Tamam, SERIF alanını değiştirdim ve işe yaradı :)
Abdullah Umer

3
Bu cevap , bu yanıta atıfta bulunur ve daha temiz bir yaklaşım sağlar.
adamdport

36

Manish'in cevabını en hızlı ve en çok hedeflenen yöntem olarak değerlendirmeme rağmen, aynı zamanda bir görünüm hiyerarşisi boyunca yinelemeli olarak yineleyen ve sırayla tüm öğelerin yazı tiplerini güncelleyen saf çözümler de gördüm. Bunun gibi bir şey:

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

Bu işlevi görünümlerinizde hem düzeni şişirdikten sonra hem de Aktivitenizin onContentChanged()yöntemlerinde çağırmanız gerekir .


Hemen hemen. O zamanlar bunu proje zaman dilimleri içinde yapmanın tek yolu buydu. Gerekirse kullanışlı bir kısayol (:
pospi

23

Bunu merkezi bir şekilde yapabildim, işte sonuç:

görüntü açıklamasını buraya girin

Aşağıdakilere Activitysahibim ve özel yazı tiplerine ihtiyacım olursa bundan genişletiyorum:

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

Ancak, örneğin destek paketinden bir etkinlik kullanıyorsam, FragmentActivitybunu kullanıyorum 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"));
}
}

Bu kodu Fragmenthenüz s ile test etmedim, ama umarım çalışacaktır.

Benim FontUtilsbasit, bu da https://code.google.com/p/android/issues/detail?id=9904 burada bahsedilen ICS öncesi sorununu çözüyor :

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

2
Bu daha fazla oy almalı. Çalışıyor ve gösteri için bir ekran görüntüsü var
ericn

10

Hey ayrıca uygulamamda farklı yazılımlar için 2 farklı yazı tipine ihtiyacım var! Bu şekilde kullanıyorum:

Uygulama sınıfımda statik bir yöntem oluşturuyorum:

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

Dize yazı tipi, varlık klasöründeki xyz.ttf'yi temsil eder. (Bir Sabitler Sınıfı oluşturdum) Artık bunu uygulamanızın her yerinde kullanabilirsiniz:

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

Tek sorun, Yazı Tipini kullanmak istediğiniz her widget için buna ihtiyacınız olmasıdır! Ama bence bu en iyi yol.


4

Pospi'nin önerisini kullanmak ve Richard gibi 'tag' özelliği ile çalışmak yaptığı özel yazı yükleyen ve bunları etiketlerine göre görünümlere uygulayan özel bir sınıf oluşturdum.

Temel olarak, android: fontFamily özniteliğinde TypeFace'i ayarlamak yerine android: tag attritube'u kullanıyorsunuz ve bunu tanımlanan numaralandırmalardan birine ayarlayın.

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

Aktivitenizde veya Parçanızda sadece arayın

Fonts fonts = new Fonts(getActivity());
fonts.setupLayoutTypefaces(mainLayout);

4

Lisa Wray'in blogunda güzel bir çözüm buldum . Yeni veri bağlama ile XML dosyalarınızdaki yazı tipini ayarlamak mümkündür.

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

XML'de:

<TextView
app:font="@{`Source-Sans-Pro-Regular.ttf`}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

Veri Bağlamayı kullanarak bir örnek önerebilir misiniz? Bu çok takdir edilecektir.
Sri Krishna

3

Sanırım bunu yapmanın daha pratik bir yolu olabilir. Aşağıdaki sınıf, uygulamanızın tüm bileşenleri için özel bir tip yüz ayarlayacaktır (sınıf başına bir ayarla).

/**
 * 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;
        }
    }

}

2

LayoutInflater'ın varsayılan uygulamaları, xml'den yazı tipi yazı tipinin belirtilmesini desteklemez. Bununla birlikte, bu tür öznitelikleri xml etiketinden ayrıştıracak LayoutInflater için özel bir fabrika sağlayarak xml'de yapıldığını gördüm.

Temel yapı bundan hoşlanır.

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

Bu makale , bu mekanizmaların daha ayrıntılı bir açıklamasını ve yazarın bu şekilde yazı tipleri için xml mizanpajı desteği sağlamaya nasıl çalıştığını sağlar. Yazarın uygulaması için kod burada bulunabilir .


1

Normal bir ProgressDialog / AlertDialog'a özel bir font ayarlama:

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

1

Evet, varsayılan yazı tipini geçersiz kılarak mümkündür. Bu çözümü takip ettim ve tek bir değişiklikle tüm TextViews ve ActionBar metinleri için de bir cazibe gibi çalıştı.

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>

Yukarıdaki bağlantıda belirtildiği gibi temalar.xml yerine, varsayılan uygulama tema etiketimde styles.xml dosyamda geçersiz kılınacak varsayılan yazı tipinden bahsetmiştim. Üzerine yazılabilen varsayılan yazı biçimleri serif, sans, monospace ve normaldir.

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

Başlangıçta, üzerine yazılacak yazı tiplerinin sabit ve tanımlanmış değerler seti olduğunu bilmiyordum, ancak sonunda Android'in yazı tipleri ve yazı karakterleri ve bunların varsayılan değerleri ile nasıl ilgilendiğini anlamama yardımcı oldu, ki bu da farklı bir nokta.


0

Tüm uygulamayı değiştirip değiştirmediğini bilmiyorum, ancak bunu yaparak başka türlü değiştirilemeyen bazı bileşenleri değiştirmeyi başardım:

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

2
Ne yazık ki bu artık çalışmıyor: java.lang.IllegalAccessException: alan java.lang.reflect.Field.set (Field.java: 556)
BoD

0

Pospi'nin önerisini beğendim. XML'de yapamayacağınız herhangi bir ek stili belirtmek için neden bir görünümün 'tag' özelliğini (XML'de belirtebilirsiniz - 'android: tag') kullanmıyorsunuz? JSON'u seviyorum, bu yüzden bir anahtar / değer kümesi belirtmek için bir JSON dizesi kullanıyorum. Bu sınıf işi yapar - sadece Style.setContentView(this, [resource id])aktivitenizi arayın .

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

Açıkçası, JSON kullanmaya değer kılmak için yazı tipinden daha fazlasını işlemek isteyeceksiniz.

'Etiket' özelliğinin bir yararı, onu tema olarak kullandığınız bir temel stile göre ayarlayabilmeniz ve böylece tüm görünümlerinize otomatik olarak uygulanmasını sağlayabilmenizdir. DÜZENLE: Bunu yapmak, Android 4.0.3'te enflasyon sırasında bir çökmeye neden olur. Yine de bir stili kullanabilir ve bunu metin görünümlerine ayrı ayrı uygulayabilirsiniz.

Kodda göreceğiniz bir şey - bazı görünümlerde açıkça belirtilmemiş bir etiket var - tuhaf bir şekilde bu, google translate'e göre Yunanca 'kesilmiş' olan 'Αποκοπή' dizesidir! Ne oluyor be...?


0

@ majinboo'nun cevabı performans ve hafıza yönetimi için revize edildi. Aktivite ile ilgili birden fazla font ihtiyacı varsa, kurucunun kendisini parametre olarak vererek bu Font sınıfını kullanabilir.

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

Revised Fonts sınıfı aşağıdaki gibidir:

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

0

Xamarin.Android için Çalışma:

Sınıf:

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

Uygulama Uygulaması:

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

Stil:

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

0

Görünüşe göre özel yazı tiplerini kullanmak Android O ile kolaylaştırılmıştır, bunu başarmak için temelde xml kullanabilirsiniz. Referans için Android resmi belgelerine bir bağlantı ekledim ve umarım bu hala bu çözüme ihtiyaç duyan insanlara yardımcı olur. Android'de özel yazı tipleriyle çalışma


0

Android 8.0'dan (API seviyesi 26) başlayarak XML'de özel bir yazı tipi kullanabileceğinizi bilmek faydalı olabilir .

Basitçe söylemek gerekirse, bunu şu şekilde yapabilirsiniz.

  1. Yazı tipini klasöre koyun res/font.

  2. Ya bir widget'ın özniteliğinde kullanın

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

veya içine koy res/values/styles.xml

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

ve bir stil olarak kullan

<Button style="@style/MyButton"/>

0

"FontPath" özelliğini doğrudan xml dosyasında kullanın.

style.xml'de kullanım için

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

doğrudan yerleşim dosyasında kullanım için

FontPath = "yazı / ProximaNovaBold.ttf"

(Not: Önekte app / android özelliğini kullanmaya gerek yoktur)


-6

Kesinlikle mümkün. Bunu yapmanın birçok yolu. En hızlı yol, dene-yakala yöntemiyle koşul oluştur. Belirli yazı tipi stili koşulunuzu deneyin, hatayı yakalayın ve diğer yazı tipi stilini tanımlayın.


7
Cevap verdiğinizi kanıtlamak için bir demo sağlayabilir misiniz?
Mark
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.