Xml का उपयोग करके Android TextView में कस्टम फ़ॉन्ट का उपयोग करना


92

मैंने अपनी संपत्ति / फोंट फ़ोल्डर में एक कस्टम फ़ॉन्ट फ़ाइल जोड़ी है। मैं इसे अपने XML से कैसे उपयोग करूं?

मैं इसे कोड से निम्नानुसार उपयोग कर सकता हूं:

TextView text = (TextView) findViewById(R.id.textview03);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Molot.otf");
text.setTypeface(tf);

क्या मैं XML से एक android:typeface="/fonts/Molot.otf"विशेषता का उपयोग नहीं कर सकता हूँ ?


मैंने इसे बहुत खोजा है और इसका कोई तरीका नहीं है कि आप इसे xml से कर सकें।
सीडी

2
इस पोस्ट के बाहर की जाँच की कोशिश stackoverflow.com/questions/2376250/...
dor506

इस जवाब पर एक नज़र डालें ! यह आपको कई फोंट और XML का उपयोग करने की अनुमति देता है।
राफा 0809

जैसा कि अन्य ने कहा, आप इसे प्राप्त करने के लिए सुलेख का उपयोग कर सकते हैं ।
मॉबिनिन

जवाबों:


45

संक्षिप्त उत्तर: नहीं। एंड्रॉइड में XML के माध्यम से टेक्स्ट विजेट पर कस्टम फोंट लगाने के लिए अंतर्निहित समर्थन नहीं है।

हालाँकि, वहाँ एक समाधान है जिसे लागू करना बहुत मुश्किल नहीं है।

प्रथम

आपको अपनी शैली को परिभाषित करने की आवश्यकता होगी। अपने / Res / मान फ़ोल्डर में, attrs.xml फ़ाइल खोलें / बनाएं और एक घोषित-शैली योग्य ऑब्जेक्ट जोड़ें जैसे:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="FontText">
        <attr name="typefaceAsset" format="string"/>
    </declare-styleable>
</resources>

दूसरा

मान लें कि आप अक्सर इस विजेट का उपयोग करना चाहते हैं, तो आपको लोड की गई Typefaceवस्तुओं के लिए एक सरल कैश सेट करना चाहिए , क्योंकि उन्हें उड़ने पर मेमोरी से लोड करने में समय लग सकता है। कुछ इस तरह:

public class FontManager {
    private static FontManager instance;

    private AssetManager mgr;

    private Map<String, Typeface> fonts;

    private FontManager(AssetManager _mgr) {
        mgr = _mgr;
        fonts = new HashMap<String, Typeface>();
    }

    public static void init(AssetManager mgr) {
        instance = new FontManager(mgr);
    }

    public static FontManager getInstance() {
        if (instance == null) {
            // App.getContext() is just one way to get a Context here
            // getContext() is just a method in an Application subclass
            // that returns the application context
            AssetManager assetManager = App.getContext().getAssets();
            init(assetManager);
        }
        return instance;
    }

    public Typeface getFont(String asset) {
        if (fonts.containsKey(asset))
            return fonts.get(asset);

        Typeface font = null;

        try {
            font = Typeface.createFromAsset(mgr, asset);
            fonts.put(asset, font);
        } catch (Exception e) {

        }

        if (font == null) {
            try {
                String fixedAsset = fixAssetFilename(asset);
                font = Typeface.createFromAsset(mgr, fixedAsset);
                fonts.put(asset, font);
                fonts.put(fixedAsset, font);
            } catch (Exception e) {

            }
        }

        return font;
    }

    private String fixAssetFilename(String asset) {
        // Empty font filename?
        // Just return it. We can't help.
        if (TextUtils.isEmpty(asset))
            return asset;

        // Make sure that the font ends in '.ttf' or '.ttc'
        if ((!asset.endsWith(".ttf")) && (!asset.endsWith(".ttc")))
            asset = String.format("%s.ttf", asset);

        return asset;
    }
}

यह आपको .ttc फ़ाइल एक्सटेंशन का उपयोग करने की अनुमति देगा, लेकिन यह अप्रयुक्त है।

तीसरा

एक नया वर्ग बनाएं जो उप-वर्ग का निर्माण करे TextView। यह विशेष उदाहरण परिभाषित XML टाइपफेस ( bold, italicआदि) को ध्यान में रखता है और इसे फ़ॉन्ट पर लागू करते हैं (यह मानते हुए कि आप एक .tt फ़ाइल का उपयोग कर रहे हैं)।

/**
 * TextView subclass which allows the user to define a truetype font file to use as the view's typeface.
 */
public class FontText extends TextView {
    public FontText(Context context) {
        this(context, null);
    }

    public FontText(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FontText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        if (isInEditMode())
            return;

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FontText);

        if (ta != null) {
            String fontAsset = ta.getString(R.styleable.FontText_typefaceAsset);

            if (!TextUtils.isEmpty(fontAsset)) {
                Typeface tf = FontManager.getInstance().getFont(fontAsset);
                int style = Typeface.NORMAL;
                float size = getTextSize();

                if (getTypeface() != null)
                    style = getTypeface().getStyle();

                if (tf != null)
                    setTypeface(tf, style);
                else
                    Log.d("FontText", String.format("Could not create a font from asset: %s", fontAsset));
            }
        }
    }
}

आखिरकार

TextViewअपने XML के उदाहरणों को पूरी तरह से योग्य वर्ग नाम से बदलें । अपने कस्टम नेमस्पेस को उसी तरह डिक्लेयर करें जैसे आप एंड्रॉइड नेमस्पेस करेंगे। ध्यान दें कि "टाइपफेसटसेट" को आपके / एसेट्स डायरेक्टरी में एक .ttf या .ttc फाइल की ओर इशारा करना चाहिए।

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.FontText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is a custom font text"
        custom:typefaceAsset="fonts/AvenirNext-Regular.ttf"/>
</RelativeLayout>

बहुत बढ़िया जवाब! एक सवाल हालांकि: आप क्यों वापस आ गए जब IsEditMode?
एवी शुक्रोन

04-11 18: 18: 32.685 3506-3506 / com.example.demo E / AndroidRuntime PT FATAL EXCEPTION: मुख्य प्रक्रिया: com.example.demo, PID: 3506 android.view.InflateException: बाइनरी एक्सएमएल फाइल लाइन # 2: त्रुटि Android.view.LayoutInflater.createView (LayoutInflater.java:620) पर android.view.LayoutInflater.create.cromfagFromTag (LayoutInflater.java:696) android.view.LayoutInflater.inflate.in पर कक्षा com.example.demo.lbooks.LatoTextView इनवॉइसिंग करें। LayoutInflater.java:469) android.view.LayoutInflater.inflate पर (LayoutInflater.java:397) ...
e-info128

@AvrahamShukron - ऐसा इसलिए है क्योंकि मैं पूर्वावलोकन मोड में रहते हुए एंड्रॉइड स्टूडियो में एक त्रुटि प्राप्त करता रहा (संभवतः क्योंकि यह नहीं जानता कि कस्टम टाइपफेस को लागू करने का तरीका कैसे संभालना है।
themarshal

जोड़ा गया xmlns: रिलेटिवलैटआउट में कस्टम = " स्कीमा.एंड्रॉयड.com / tools " और त्रुटि चली गई थी। धन्यवाद आदमी
नावेद अहमद

1
नमस्कार @themarshal: xmlns के बजाय: custom = " schemas.android.com/tools " आपको उपयोग करना चाहिए: xmlns: custom = " schemas.android.com/apk/res-auto " शैलीगत विशेषताओं का उपयोग करने के लिए।
अभिनव सक्सेना

28

यहाँ उदाहरण कोड है जो ऐसा करता है। मेरे पास एक स्थिर अंतिम चर में परिभाषित फ़ॉन्ट है और फ़ॉन्ट फ़ाइल संपत्ति निर्देशिका में है।

public class TextViewWithFont extends TextView {

    public TextViewWithFont(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setTypeface(MainActivity.typeface);
    }

    public TextViewWithFont(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setTypeface(MainActivity.typeface);
    }

    public TextViewWithFont(Context context) {
        super(context);
        this.setTypeface(MainActivity.typeface);
    }

}

5
ओपी विशेष रूप से बताता है कि वह जानता है कि फ़ॉन्ट को प्रोग्रामेटिक रूप से कैसे सेट किया जाए (वह एक उदाहरण भी प्रदान करता है)। सवाल यह है कि xml में फ़ॉन्ट कैसे सेट करें?
SMBiggs

13

अपना कस्टम बनाया गया टेक्स्टव्यू उस फ़ॉन्ट से संबंधित है जिसे आप उपयोग करना चाहते हैं। इस श्रेणी में, मैं टाइपफेस (बेहतर प्रदर्शन के लिए) को कैश करने के लिए एक स्थिर mTypeface फ़ील्ड का उपयोग करता हूं

public class HeliVnTextView extends TextView {

/*
 * Caches typefaces based on their file path and name, so that they don't have to be created every time when they are referenced.
 */
private static Typeface mTypeface;

public HeliVnTextView(final Context context) {
    this(context, null);
}

public HeliVnTextView(final Context context, final AttributeSet attrs) {
    this(context, attrs, 0);
}

public HeliVnTextView(final Context context, final AttributeSet attrs, final int defStyle) {
    super(context, attrs, defStyle);

     if (mTypeface == null) {
         mTypeface = Typeface.createFromAsset(context.getAssets(), "HelveticaiDesignVnLt.ttf");
     }
     setTypeface(mTypeface);
}

}

Xml फ़ाइल में:

<java.example.HeliVnTextView
        android:id="@+id/textView1"
        android:layout_width="0dp"
        ... />

जावा वर्ग में:

HeliVnTextView title = new HeliVnTextView(getActivity());
title.setText(issue.getName());

11

एक्टिविटी लेआउट लेआउटइन्फ्लेटर.फैक्टरी 2 जो प्रत्येक बनाए गए व्यू पर कॉलबैक प्रदान करता है। कस्टम फ़ॉन्ट परिवार विशेषता के साथ TextView को स्टाइल करना संभव है, मांग पर टाइपफेस लोड करें और इंस्टेंटिकेटेड संदेशों को स्वचालित रूप से कॉल सेट टाइप करें।

दुर्भाग्य से इन्फ्लेटर के वास्तुशिल्प संबंधों और गतिविधियों के सापेक्ष उदाहरणों के कारण और एंड्रॉइड में कस्टम फोंट का उपयोग करने के लिए सबसे सरल दृष्टिकोण एप्लिकेशन स्तर पर लोड किए गए फोंट को कैश करना है।

नमूना कोड आधार यहां है:

https://github.com/leok7v/android-textview-custom-fonts

  <style name="Baroque" parent="@android:style/TextAppearance.Medium">
    <item name="android:layout_width">fill_parent</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:textColor">#F2BAD0</item>
    <item name="android:textSize">14pt</item>
    <item name="fontFamily">baroque_script</item>
  </style>

  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:custom="http://schemas.android.com/apk/res/custom.fonts"
          android:orientation="vertical"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
  >
  <TextView
    style="@style/Baroque"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/sample_text"
  />

का परिणाम

यहां छवि विवरण दर्ज करें


2 साल तक उस कोड को नहीं छुआ। लेकिन यह होना चाहिए। मैं इसे रोकने वाले सिद्धांत में कुछ भी नहीं देखता हूं।
सिंह

7

इस तथ्य के कारण xml में कस्टम फोंट का उपयोग करने के लिए एक अच्छा विचार नहीं है, आपको मेमोरी लीक से बचने के लिए इसे प्रोग्रामेटिक रूप से करना होगा!


6
ऐसा प्रतीत होता है कि स्मृति रिसाव आइसक्रीम सैंडविच में तय किया गया था।
माइकल शेपर

2
मेमोरी लीक से बचने के लिए आपको TypedArray मेथड रीसायकल () का उपयोग करना चाहिए।
अभिनव सक्सेना

7

अद्यतन: https://github.com/chrisjenx/Calligraphy इसका एक बेहतर समाधान प्रतीत होता है।


हो सकता है कि जब आप अपना एप्लिकेशन बनाते हैं तो आप उपलब्ध फ़ॉन्ट की स्थिर सूची में अपने फ़ॉन्ट को इंजेक्ट / हैक करने के लिए प्रतिबिंब का उपयोग कर सकते हैं ? मुझे दूसरों से प्रतिक्रिया में दिलचस्पी है अगर यह वास्तव में है, वास्तव में बुरा विचार है या यदि यह एक महान समाधान है - ऐसा लगता है कि यह उन चरम सीमाओं में से एक होने जा रहा है ...

मैं अपने कस्टम टाइपफेस को अपने स्वयं के फ़ॉन्ट परिवार के नाम के साथ सिस्टम टाइपफेस की सूची में इंजेक्ट करने में सक्षम था, फिर उस कस्टम फ़ॉन्ट परिवार का नाम ("ब्रश-स्क्रिप्ट") को Android के मान के रूप में निर्दिष्ट करते हुए : FontFamily एक मानक TextView पर मेरे एलजी के साथ काम किया G4 Android 6.0 चल रहा है।

public class MyApplication extends android.app.Application
{
    @Override
    public void onCreate()
    {
        super.onCreate();

        Typeface font = Typeface.createFromAsset(this.getResources().getAssets(),"fonts/brush-script.ttf");
        injectTypeface("brush-script", font);
    }

    private boolean injectTypeface(String fontFamily, Typeface typeface)
    {
        try
        {
            Field field = Typeface.class.getDeclaredField("sSystemFontMap");
            field.setAccessible(true);
            Object fieldValue = field.get(null);
            Map<String, Typeface> map = (Map<String, Typeface>) fieldValue;
            map.put(fontFamily, typeface);
            return true;
        }
        catch (Exception e)
        {
            Log.e("Font-Injection", "Failed to inject typeface.", e);
        }
        return false;
    }
}

मेरे लेआउट में

<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Fancy Text"
    android:fontFamily="brush-script"/>

मेरे लिए काम नहीं करता है, क्या आप इसे उपयोग करने के बारे में अधिक विस्तार दे सकते हैं? क्या MyApplicationकक्षा को बुलाने की जरूरत है?
दादन

@ यव्ज़ को आपको अपने आवेदन में कम से कम एक बार इंजेक्टाइपफेस विधि को कॉल करना होगा। यदि यह एक अपवाद को जोड़ता है तो मुझे विवरण में दिलचस्पी होगी। मैंने केवल एंड्रॉइड 6.0 पर चलने वाले अपने एलजी जी 4 पर यह परीक्षण किया (मैं उस समय अपने स्वयं के कुछ शोध कर रहा था) और मुझे उम्मीद है कि यह एंड्रॉइड के सभी संस्करणों पर काम नहीं करता है।
रॉस ब्रैडबरी

@RossBradbury यह कुछ उपकरणों पर काम नहीं करता है .. अधिकांश उपकरण सही ढंग से काम कर रहे हैं, लेकिन कुछ डिवाइस इस फ़ॉन्ट को स्वीकार नहीं करते हैं .. मेरा परीक्षण किया गया उपकरण - lenova a7000 मॉडल
कुमार

अद्यतन: github.com/chrisjenx/Calligraphy एक बेहतर समाधान है।
रॉस ब्रैडबरी

4

संपत्ति में एक फोंट फ़ोल्डर बनाएं और अपने सभी आवश्यक फ़ॉन्ट को वहां जोड़ें।

public class CustomTextView extends TextView {
    private static final String TAG = "TextView";

    public CustomTextView(Context context) {
        super(context);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setCustomFont(context, attrs);
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setCustomFont(context, attrs);
    }

    private void setCustomFont(Context ctx, AttributeSet attrs) {
        TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
        String customFont = a.getString(R.styleable.CustomTextView_customFont);
        setCustomFont(ctx, customFont);
        a.recycle();
    }

    public boolean setCustomFont(Context ctx, String fontName) {
        Typeface typeface = null;
        try {
            if(fontName == null){
                fontName = Constants.DEFAULT_FONT_NAME;
            }
            typeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/" + fontName);
        } catch (Exception e) {
            Log.e(TAG, "Unable to load typeface: "+e.getMessage());
            return false;
        }
        setTypeface(typeface);
        return true;
    }
}

और में एक declarable जोड़ने attrs.xml

<declare-styleable name="CustomTextView">
      <attr name="customFont" format="string"/>
</declare-styleable>

और फिर अपने customFont की तरह जोड़ें

app:customFont="arial.ttf"

आप यहां स्टाइल के साथ काम करने के लिए क्लास के ऊपर भी कस्टमाइज कर सकते हैं। github.com/leok7v/android-textview-custom-fonts/blob/master/res/…
AndroidGeek

4

मुझे पता है कि यह एक पुराना सवाल है, लेकिन मुझे बहुत आसान समाधान मिल गया है।

सबसे पहले अपने TextView को हमेशा की तरह xml में घोषित करें। अपने फ़ॉन्ट (TTF या TTC) को एसेट फ़ोल्डर में रखें

एप्लिकेशन \ src \ मुख्य \ संपत्ति \

तो बस अपने onCreate विधि में अपने पाठ दृश्य के लिए टाइपफेस सेट करें।

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

    TextView textView = findViewById(R.id.my_textView);
    Typeface typeface = Typeface.createFromAsset(getAssets(), "fontName.ttf");
    textView.setTypeface(typeface);
}

किया हुआ।


1
यह प्रश्न स्पष्ट रूप से xml फ़ाइलों के अंदर उपयोग करने के लिए स्पष्ट रूप से नहीं बताता है
गुस्तावो बायोची कोस्टा

2

Google द्वारा मूल कस्टम फ़ॉन्ट सुविधा XML में प्रस्तुत (अंत में) उपयोग करने के लिए सबसे अच्छा समाधान है। लेकिन आपको एपीआई 26 को लक्षित करना होगा। यह एपीआई 16+ का समर्थन करता है

https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml


0

xmlns के बजाय: custom = "schemas.android.com/tools"; आपको उपयोग करना चाहिए: xmlns: custom = "schemas.android.com/apk/res-auto"; शैलीगत विशेषताओं का उपयोग करने के लिए। मैंने यह बदलाव किया है और यह अब काम कर रहा है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.