Sử dụng kiểu chữ tùy chỉnh trong Android


111

Tôi muốn sử dụng phông chữ tùy chỉnh cho ứng dụng Android mà tôi đang tạo.
Tôi có thể thay đổi riêng từng kiểu chữ của từng đối tượng từ Code, nhưng tôi có hàng trăm cái.

Vì thế,

  • Có cách nào để làm điều này từ XML không? [Đặt kiểu chữ tùy chỉnh]
  • Có cách nào để làm điều đó từ mã ở một nơi, để nói rằng toàn bộ ứng dụng và tất cả các thành phần nên sử dụng kiểu chữ tùy chỉnh thay vì kiểu mặc định không?

stackoverflow.com/questions/5541058/... Nhìn vào bài này, tôi gửi mã hoàn chỉnh ở đây liên quan đến vấn đề này
Manish Singla

Bạn có thể sử dụng các biến tĩnh trên hoạt động chính của mình để giữ các tham chiếu đến các phông chữ được nhúng. Điều đó sẽ gây ra một bộ phông chữ liên tục sẽ không được GC chọn.
Jacksonkr

Phương pháp nhà máy. Hoặc một phương pháp lấy chế độ xem của bạn và đặt tất cả cài đặt phông chữ và kiểu chữ.
mtmurdock

Thư viện hỗ trợ mới 26 hiện cho phép bạn sử dụng phông chữ trong XML. Dưới đây là làm thế nào để nó Fonts trong XML
Vinicius Silva

Câu trả lời:


80

Có cách nào để làm điều này từ XML không?

Không xin lỗi. Bạn chỉ có thể chỉ định các kiểu chữ dựng sẵn thông qua XML.

Có cách nào để thực hiện điều đó từ mã ở một nơi, để nói rằng toàn bộ ứng dụng và tất cả các thành phần nên sử dụng kiểu chữ tùy chỉnh thay vì kiểu mặc định không?

Không phải là tôi biết.

Ngày nay có nhiều lựa chọn cho những thứ này:

  • Tài nguyên phông chữ và cổng nền trong Android SDK, nếu bạn đang sử dụng appcompat

  • Thư viện bên thứ ba cho những người không sử dụng appcompat, mặc dù không phải tất cả đều sẽ hỗ trợ xác định phông chữ trong tài nguyên bố cục


4
@Codevalley: Chà, theo nhiều cách, câu trả lời tốt hơn là không cần phiền phức với các phông chữ tùy chỉnh. Chúng có xu hướng lớn, khiến lượt tải xuống của bạn lớn hơn và giảm số lượng người sẽ tải xuống và tiếp tục sử dụng ứng dụng của bạn.
CommonsWare

22
@CommonsWare: Tôi không nhất thiết phải đồng ý. Kiểu chữ là một phần không thể thiếu của Tạo kiểu giao diện người dùng giống như bạn làm với hình ảnh nền, v.v. Và kích thước không nhất thiết phải luôn lớn. Ví dụ, các phông chữ trong trường hợp của tôi chỉ là 19.6KB :)
Codevalley

2
@Amit: Không có thay đổi nào về vấn đề này. Có rất nhiều đoạn mã xung quanh để giúp đơn giản hóa việc áp dụng một kiểu chữ cho giao diện người dùng của bạn trong Java, nhưng không có cách nào để làm điều đó từ XML.
CommonsWare

1
@Amit: "Nhưng điều đó có nghĩa là tôi sẽ phải tạo tệp .ttf hoặc .otf của riêng mình cho phông chữ tùy chỉnh?" -- À, không. Bạn có thể sử dụng các phông chữ TTF / OTF hiện có, mặc dù chúng có thể không hoạt động. Vấn đề đối với câu hỏi này là làm thế nào để áp dụng các phông chữ đó trên toàn bộ ứng dụng, điều này vẫn không thể thực hiện được và đó là những gì tôi đã đề cập đến trong nhận xét của mình.
CommonsWare

1
Câu trả lời được chấp nhận này đã lỗi thời, và sẽ thật tuyệt nếu cập nhật hoặc xóa nó.
Sky Kelsey

109

Có Nó có thể.

Bạn phải tạo một dạng xem tùy chỉnh để mở rộng dạng xem văn bản.

Trong attrs.xmltrong valuesthư mục:

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

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

Trong 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
Điều này sẽ hoạt động, nhưng chỉ cho TextView. Nó sẽ yêu cầu các lớp con tùy chỉnh cho mọi lớp tiện ích con kế thừa từ TextViewnơi có cùng khả năng được mong muốn.
CommonsWare

Xin chào Manish, Cảm ơn vì giải pháp. Mặc dù tôi phải đối mặt với một vấn đề trong việc sử dụng này. Tôi tiếp tục nhận được 'không Resource Identifier tìm thấy cho thuộc tính ttf_name trong gói com.lht.android'
Kshitij Aggarwal

17
Điều này sẽ hoạt động, nhưng trước ICS, nó sẽ phân bổ bộ nhớ cho các phông chữ cho mỗi chế độ xem mà bạn khởi tạo: code.google.com/p/android/issues/detail?id=9904 Một cách để khắc phục điều này là tạo một bản đồ băm tĩnh của tất cả các phông chữ được khởi tạo: code.google.com/p/android/issues/detail?id=9904#c7
Ken Van Hoeylandt

Tại sao chúng ta cần một vòng lặp ?, Nó không hoạt động với một cuộc gọi?
Guillermo Tobar

1
@AlaksiejN. trong trường hợp bạn cần đặt các kiểu chữ khác nhau thành các TextView khác nhau ...
Nick

49

Tôi đã làm điều này theo cách "bạo lực" hơn mà không yêu cầu thay đổi bố cục xml hoặc Hoạt động.

Đã thử nghiệm trên Android phiên bản 2.1 đến 4.4. Chạy điều này khi khởi động ứng dụng, trong lớp Ứng dụng của bạ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);
    }
}

Để có ví dụ đầy đủ hơn, hãy xem http://github.com/perchrh/FontOverrideExample


Đây là giải pháp tốt nhất cho tôi.
Igor K

2
mặc định không hoạt động cho tôi. nếu tôi sử dụng monospace và sau đó đặt code<style name = "AppTheme" parent = "AppBaseTheme"> <item name = "android: typeface"> monospace </item> </style> codethì nó hoạt động nhưng không hoạt động cho chữ in đậm. tôi đã thêm mã này trong một lớp mở rộng Ứng dụng. đó có phải là nơi chính xác? @ P-chan
Christopher Rivera

2
@ChristopherRivera Có, hãy thêm nó vào lớp Ứng dụng của ứng dụng của bạn, đảm bảo nó chạy trên onCreate. Xem qua grepcode.com/file/repository.grepcode.com/java/ext/… Tôi khuyên bạn nên ghi đè trường bổ sung cho monospace cũng như trường trong mã mẫu của tôi ở trên!
Per Christian Henden

2
Được rồi, tôi thay đổi cho serif lĩnh vực và nó làm việc :)
Abdullah Umer

3
Câu trả lời này tham chiếu câu trả lời này và cung cấp một cách tiếp cận rõ ràng hơn.
adamdport

36

Mặc dù tôi tán thành câu trả lời của Manish là phương pháp nhanh nhất và được nhắm mục tiêu nhiều nhất, tôi cũng đã thấy các giải pháp ngây thơ chỉ lặp lại đệ quy qua hệ thống phân cấp chế độ xem và cập nhật lần lượt các kiểu chữ của tất cả các phần tử. Một cái gì đó như thế này:

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

Bạn sẽ cần gọi hàm này trên các khung nhìn của mình cả sau khi thổi phồng bố cục và trong các onContentChanged()phương thức Hoạt động của bạn .


Khá nhiều. Vào thời điểm đó, đó là cách duy nhất để thực hiện trong khung thời gian của dự án. Một phím tắt tiện dụng nếu cần thiết (:
pospi

23

Tôi đã có thể làm điều này một cách tập trung, đây là kết quả:

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

Tôi có theo dõi Activityvà tôi mở rộng từ nó nếu tôi cần phông chữ tùy chỉnh:

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

Nhưng nếu tôi đang sử dụng một hoạt động từ gói hỗ trợ, ví dụ: FragmentActivitythì tôi sử dụng cái này 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"));
}
}

Tôi chưa thử nghiệm mã này với Fragments, nhưng hy vọng nó sẽ hoạt động.

My FontUtilsis simple cũng giải quyết vấn đề trước ICS được đề cập tại đây 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;
}
}

2
Điều này sẽ nhận được nhiều phiếu bầu hơn. Nó hoạt động và nó có ảnh chụp màn hình để trình diễn
ericn

10

Này, tôi cũng cần 2 phông chữ khác nhau trong ứng dụng của mình cho các widgeds khác nhau! Tôi sử dụng cách này:

Trong lớp Ứng dụng của tôi, tôi tạo một phương thức tĩnh:

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

Kiểu chữ Chuỗi đại diện cho xyz.ttf trong thư mục nội dung. (tôi đã tạo Lớp Hằng số) Bây giờ bạn có thể sử dụng tính năng này ở mọi nơi trong ứng dụng của mình:

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

Vấn đề duy nhất là, bạn cần cái này cho mọi tiện ích mà bạn muốn sử dụng Phông chữ! Nhưng tôi nghĩ đây là cách tốt nhất.


4

Sử dụng gợi ý của pospi và làm việc với thuộc tính 'tag' như Richard đã làm, tôi đã tạo một lớp tùy chỉnh tải các phông chữ tùy chỉnh của tôi và áp dụng chúng cho các chế độ xem theo thẻ của chúng.

Vì vậy, về cơ bản, thay vì đặt TypeFace trong thuộc tính android: fontFamily, bạn đang sử dụng android: tag attritube và đặt nó thành một trong các enum đã xác định.

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

Trong Hoạt động hoặc Phân đoạn của bạn, bạn chỉ cần gọi

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

4

Tôi đã tìm thấy một giải pháp hay trên blog của Lisa Wray . Với liên kết dữ liệu mới, bạn có thể đặt phông chữ trong các tệp XML của mình.

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

Trong XML:

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

Bạn có thể đề xuất một ví dụ bằng cách sử dụng Data Binding không? Điều đó sẽ được nhiều đánh giá cao.
Sri Krishna,

3

Tôi nghĩ có thể có một cách dễ dàng hơn để làm điều đó. Lớp sau sẽ đặt một khuôn mặt kiểu tùy chỉnh cho tất cả các thành phần của ứng dụng của bạn (với một cài đặt cho mỗi lớp).

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

Các triển khai mặc định của LayoutInflater không hỗ trợ chỉ định kiểu chữ phông chữ từ xml. Tuy nhiên, tôi đã thấy nó được thực hiện trong xml bằng cách cung cấp một nhà máy tùy chỉnh cho LayoutInflater sẽ phân tích cú pháp các thuộc tính như vậy từ thẻ xml.

Cấu trúc cơ bản sẽ như thế này.

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

Bài viết này cung cấp giải thích sâu hơn về các cơ chế này và cách tác giả cố gắng cung cấp hỗ trợ bố cục xml cho các kiểu chữ theo cách này. Có thể tìm thấy mã thực hiện của tác giả tại đây .


1

Đặt phông chữ tùy chỉnh thành ProgressDialog / AlertDialog thông thường:

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

Có, có thể bằng cách ghi đè kiểu chữ mặc định. Tôi đã làm theo giải pháp này và nó hoạt động giống như một sự quyến rũ cho tất cả văn bản TextView và ActionBar với một thay đổi duy nhấ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>

Thay vì themes.xml như đã đề cập trong liên kết trên, tôi đã đề cập đến phông chữ mặc định để ghi đè trong styles.xml trong thẻ chủ đề ứng dụng mặc định của tôi. Các kiểu chữ mặc định có thể được ghi đè là serif, sans, monospace và 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);
        }
    }
}

Ban đầu, tôi không biết các kiểu chữ bị ghi đè là cố định và tập hợp các giá trị xác định nhưng cuối cùng nó đã giúp tôi hiểu cách Android xử lý các phông chữ và kiểu chữ cũng như các giá trị mặc định của chúng, đó là một điểm khác biệt.


0

Tôi không biết liệu nó có thay đổi toàn bộ ứng dụng hay không, nhưng tôi đã quản lý để thay đổi một số thành phần không thể thay đổi được bằng cách thực hiện điều này:

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
Rất tiếc, điều này không hoạt động nữa: java.lang.IllegalAccessException: trường được đánh dấu là 'cuối cùng' tại java.lang.reflect.Field.setField (Phương pháp bản địa) tại java.lang.reflect.Field.set (Field.java: 556)
BoD

0

Tôi thích gợi ý của pospi. Tại sao không sử dụng hết thuộc tính 'thẻ' của một chế độ xem (bạn có thể chỉ định trong XML - 'android: tag') để chỉ định bất kỳ kiểu bổ sung nào mà bạn không thể thực hiện trong XML. Tôi thích JSON nên tôi sẽ sử dụng một chuỗi JSON để chỉ định một bộ khóa / giá trị. Lớp này thực hiện công việc - chỉ cần gọi Style.setContentView(this, [resource id])trong hoạt động của bạ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)));
  }
}

Rõ ràng là bạn muốn xử lý nhiều hơn chỉ là kiểu chữ để làm cho việc sử dụng JSON trở nên đáng giá.

Một lợi ích của thuộc tính 'tag' là bạn có thể đặt nó trên một kiểu cơ sở mà bạn sử dụng làm chủ đề và do đó nó tự động áp dụng cho tất cả các chế độ xem của bạn. CHỈNH SỬA: Làm điều này dẫn đến sự cố khi lạm phát trên Android 4.0.3. Bạn vẫn có thể sử dụng một kiểu và áp dụng nó cho từng dạng xem văn bản.

Một điều bạn sẽ thấy trong mã - một số chế độ xem có thẻ mà không có thẻ nào được đặt rõ ràng - kỳ lạ đó là chuỗi 'Αποκοπή' - được 'cắt' trong tiếng Hy Lạp, theo google dịch! Cái quái gì thế...?


0

Câu trả lời của @ majinboo được sửa đổi để quản lý hiệu suất và bộ nhớ. Bất kỳ hoạt động liên quan nào cần nhiều hơn một phông chữ đều có thể sử dụng lớp Phông chữ này bằng cách cung cấp cho chính hàm tạo như một tham số.

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

Lớp Phông chữ được sửa đổi như sau:

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

Làm việc cho Xamarin.Android:

Lớp học:

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

Thực hiện ứng dụng:

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

Phong cách:

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

0

Có vẻ như việc sử dụng phông chữ tùy chỉnh đã được thực hiện dễ dàng với Android O, về cơ bản bạn có thể sử dụng xml để đạt được điều này. Tôi đã đính kèm một liên kết đến tài liệu chính thức của Android để tham khảo và hy vọng điều này sẽ giúp ích cho những người vẫn cần giải pháp này. Làm việc với phông chữ tùy chỉnh trong Android


0

Có thể hữu ích khi biết rằng bắt đầu từ Android 8.0 (API cấp 26), bạn có thể sử dụng phông chữ tùy chỉnh trong XML .

Thật đơn giản, bạn có thể thực hiện theo cách sau.

  1. Đặt phông chữ vào thư mục res/font.

  2. Sử dụng nó trong thuộc tính của tiện ích con

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

hoặc đặt nó vào res/values/styles.xml

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

và sử dụng nó như một phong cách

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

0

Sử dụng thuộc tính "fontPath" trực tiếp trong tệp xml.

để sử dụng trong style.xml

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

để sử dụng trong tệp bố cục trực tiếp

fontPath = "fonts / ProximaNovaBold.ttf"

(Lưu ý: Không cần sử dụng thuộc tính app / android trong tiền tố)


-6

Hoàn toàn có thể. Nhiều cách để làm điều đó. Cách nhanh nhất, tạo điều kiện với phương pháp try - catch .. hãy thử điều kiện kiểu phông chữ nhất định của bạn, bắt lỗi và xác định kiểu phông chữ khác.


7
bạn có thể cung cấp một bản demo để chứng minh bạn trả lời?
Đánh dấu
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.