Sử dụng phông chữ tùy chỉnh trong TextView android bằng xml


92

Tôi đã thêm tệp phông chữ tùy chỉnh vào thư mục tài sản / phông chữ của mình. Làm cách nào để sử dụng nó từ XML của tôi?

Tôi có thể sử dụng nó từ mã như sau:

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

Tôi không thể làm điều đó từ XML bằng cách sử dụng một android:typeface="/fonts/Molot.otf"thuộc tính?


Tôi đã tìm kiếm điều này rất nhiều và không có cách nào mà bạn có thể làm điều đó từ xml.
Cd

2
hãy thử kiểm tra kiểm tra bài viết này stackoverflow.com/questions/2376250/...
dor506

Hãy xem câu trả lời này ! Nó cho phép bạn sử dụng nhiều phông chữ và sử dụng XML.
Rafa0809

Như đã nói ở dưới, bạn có thể sử dụng Thư pháp để đạt được điều này.
mbonnin

Kiểm tra bài viết này gadgetsaint.com/tips/…
ASP

Câu trả lời:


45

Câu trả lời ngắn gọn: Không. Android không có hỗ trợ tích hợp để áp dụng phông chữ tùy chỉnh cho các widget văn bản thông qua XML.

Tuy nhiên, có một cách giải quyết không quá khó thực hiện.

Đầu tiên

Bạn sẽ cần xác định kiểu tạo kiểu của riêng mình. Trong thư mục / res / values ​​của bạn, mở / tạo tệp attrs.xml và thêm một đối tượng có thể khai báo kiểu như sau:

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

Thứ hai

Giả sử bạn muốn sử dụng tiện ích này thường xuyên, bạn nên thiết lập một bộ đệm ẩn đơn giản cho các Typefaceđối tượng được tải , vì việc tải chúng từ bộ nhớ khi đang di chuyển có thể mất nhiều thời gian. Cái gì đó như:

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

Cái này sẽ cho phép bạn sử dụng phần mở rộng tệp .ttc, nhưng nó chưa được kiểm tra.

Ngày thứ ba

Tạo một lớp mới phân lớp con TextView. Ví dụ cụ thể này có tính đến kiểu chữ XML đã xác định ( bold, italicv.v.) và áp dụng nó vào phông chữ (giả sử bạn đang sử dụng tệp .ttc).

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

Cuối cùng

Thay thế các trường hợp TextViewtrong XML của bạn bằng tên lớp đủ điều kiện. Khai báo không gian tên tùy chỉnh của bạn giống như bạn làm với không gian tên Android. Lưu ý rằng "typefaceAsset" phải trỏ đến tệp .ttf hoặc .ttc có trong thư mục / asset của bạn.

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

Câu trả lời chính xác! Tuy nhiên, một câu hỏi: Tại sao bạn quay lại khi isInEditMode?
Avi Shukron

04-11 18: 18: 32.685 3506-3506 / com.example.demo E / AndroidRuntime ﹕ FATAL EXCEPTION: main Process: com.example.demo, PID: 3506 android.view.InflateException: Binary XML file line # 2: Error thổi phồng lớp com.example.demo.libraries.LatoTextView tại android.view.LayoutInflater.createView (LayoutInflater.java:620) tại android.view.LayoutInflater.createViewFromTag (LayoutInflater.java:696) tại android.view.LayoutInflater.inflate ( LayoutInflater.java:469) tại android.view.LayoutInflater.inflate (LayoutInflater.java:397) tại ...
e-info128

@AvrahamShukron - Đó là vì tôi liên tục gặp lỗi trong Android Studio khi ở chế độ xem trước (có lẽ là do nó không biết cách xử lý việc áp dụng kiểu chữ tùy chỉnh.
themarshal

Đã thêm xmlns: custom = " schemas.android.com/tools " trong RelativeLayout và lỗi đã biến mất. Cảm ơn người đàn ông
Naveed Ahmad

1
Xin chào @themarshal: thay vì xmlns: custom = " schemas.android.com/tools ", bạn nên sử dụng: xmlns: custom = " schemas.android.com/apk/res-auto " để sử dụng các thuộc tính có thể định kiểu.
Abhinav Saxena

28

Đây là mã ví dụ thực hiện điều này. Tôi đã xác định phông chữ trong biến cuối cùng tĩnh và tệp phông chữ nằm trong thư mục nội dung.

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
OP đặc biệt nói rằng anh ta biết cách đặt phông chữ theo chương trình (thậm chí anh ta còn cung cấp một ví dụ). Câu hỏi đặt ra là làm thế nào để đặt phông chữ trong xml?
SMBiggs

13

Tạo TextView tùy chỉnh của bạn thuộc về phông chữ bạn muốn sử dụng. Trong lớp này, tôi sử dụng trường mTypeface tĩnh để lưu vào bộ đệm Kiểu chữ (để có hiệu suất tốt hơn)

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

}

Trong tệp xml:

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

Trong lớp java:

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

11

Activity triển khai LayoutInflater.Factory2 cung cấp các lệnh gọi lại trên mỗi Dạng xem được tạo. Có thể tạo kiểu cho TextView với thuộc tính Phông chữ tùy chỉnh Gia đình, tải các kiểu chữ theo yêu cầu và tự động gọi setTypeface trên các chế độ xem văn bản được khởi tạo.

Thật không may do mối quan hệ kiến ​​trúc của các phiên bản Inflater liên quan đến Hoạt động và Windows, cách tiếp cận đơn giản nhất để sử dụng phông chữ tùy chỉnh trong Android là lưu vào bộ nhớ cache các phông chữ đã tải ở cấp Ứng dụng.

Cơ sở mã mẫu ở đây:

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

kết quả trong

nhập mô tả hình ảnh ở đây


Không chạm vào mã đó trong 2 năm. Nhưng nó nên. Tôi không thấy điều gì trên lý thuyết ngăn cản nó.
Leo

7

Bạn không nên sử dụng phông chữ tùy chỉnh trong xml vì thực tế là bạn phải làm điều đó theo chương trình để tránh rò rỉ bộ nhớ!


6
Có vẻ như lỗi rò rỉ bộ nhớ đã được khắc phục trong Ice Cream Sandwich.
Michael Scheper

2
Bạn nên sử dụng phương thức TypedArray recycle () để tránh rò rỉ bộ nhớ.
Abhinav Saxena

7

CẬP NHẬT: https://github.com/chrisjenx/ Thư pháp dường như là một giải pháp ưu việt cho việc này.


Có thể bạn có thể sử dụng phản chiếu để đưa / hack phông chữ của mình vào danh sách tĩnh các phông chữ có sẵn khi ứng dụng của bạn được tạo? Tôi quan tâm đến phản hồi từ những người khác nếu đây là một ý tưởng thực sự, thực sự tồi tệ hoặc nếu đây là một giải pháp tuyệt vời - có vẻ như nó sẽ là một trong những thái cực ...

Tôi đã có thể đưa kiểu chữ tùy chỉnh của mình vào danh sách kiểu chữ hệ thống với tên họ phông chữ của riêng mình, sau đó chỉ định họ phông chữ tùy chỉnh đó ("brush-script") làm giá trị của android: FontFamily trên TextView tiêu chuẩn đã hoạt động trên LG của tôi G4 chạy 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;
    }
}

Trong bố cục của tôi

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

Không làm việc cho tôi, bạn có thể cho biết chi tiết hơn làm thế nào để sử dụng nó? Liệu MyApplicationnhu cầu lớp được gọi là?
Dadan

@Yawz, bạn sẽ cần gọi phương thức injectionTypeface ít nhất một lần trong ứng dụng của mình. Nếu nó ghi một ngoại lệ, tôi sẽ quan tâm đến các chi tiết. Tôi chỉ thử nghiệm điều này trên LG G4 chạy Android 6.0 (tôi đang thực hiện một số nghiên cứu của riêng mình vào thời điểm đó) và tôi hy vọng nó không hoạt động trên tất cả các phiên bản Android.
Ross Bradbury

@RossBradbury nó không làm việc trên một số thiết bị .. hầu hết các thiết bị hoạt động chính xác nhưng một số thiết bị không chấp nhận điều này fontFamily .. tôi thiết bị thử nghiệm - mô hình lenova A7000
Ranjith Kumar

CẬP NHẬT: github.com/chrisjenx/Cal Thư pháp là một giải pháp ưu việt.
Ross Bradbury

4

Tạo thư mục phông chữ trong nội dung và thêm tất cả phông chữ cần thiết của bạn vào đó.

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

và thêm một tệp có thể khai báo trong attrs.xml

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

và sau đó thêm tùy chỉnh của bạn

app:customFont="arial.ttf"

bạn cũng có thể tùy chỉnh lớp trên để làm việc với phong cách như được thực hiện tại đây. github.com/leok7v/android-textview-custom-fonts/blob/master/res/…
AndroidGeek

4

Tôi biết đây là một câu hỏi cũ, nhưng tôi đã tìm ra một giải pháp dễ dàng hơn nhiều.

Đầu tiên khai báo TextView của bạn trong xml như bình thường. Đặt phông chữ của bạn (TTF hoặc TTC) vào thư mục nội dung

app \ src \ main \ asset \

Sau đó, chỉ cần đặt kiểu chữ cho chế độ xem văn bản của bạn trong phương thức onCreate của bạn.

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

Làm xong.


1
Câu hỏi đặt ra nêu rõ để sử dụng nó bên trong file xml không programatically
Gustavo Baiocchi Costa


0

thay vì xmlns: custom = "schemas.android.com/tools"; bạn nên sử dụng: xmlns: custom = "schemas.android.com/apk/res-auto"; để sử dụng các thuộc tính có thể định kiểu. Tôi đã thực hiện thay đổi này và nó đang hoạt động ngay bây giờ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.