Android: ต้องการตั้งค่าแบบอักษรที่กำหนดเองสำหรับแอปพลิเคชันทั้งหมดไม่ใช่รันไทม์


100

เป็นไปได้ไหมที่จะตั้งค่าแบบอักษรที่กำหนดเองในทุกการควบคุมของแอปพลิเคชัน และไม่จำเป็นต้องรันไทม์? (เช่นจาก xml ถ้าเป็นไปได้หรือเพียงครั้งเดียวสำหรับแอปพลิเคชันทั้งหมดในไฟล์ JAVA)

ฉันสามารถตั้งค่าแบบอักษรสำหรับการควบคุมเดียวจากรหัสนี้

public static void setFont(TextView textView) {
    Typeface tf = Typeface.createFromAsset(textView.getContext()
            .getAssets(), "fonts/BPreplay.otf");

    textView.setTypeface(tf);

}

และปัญหาเกี่ยวกับรหัสนี้คือควรเรียกทุกคอนโทรล และฉันต้องการเรียกสิ่งนี้หรือวิธีการใด ๆ ที่คล้ายกันหนึ่งครั้งหรือถ้าเป็นไปได้ให้ตั้งค่าคุณสมบัติเป็น xml เป็นไปได้ไหม?


6
คุณสามารถเขียนการควบคุมแบบกำหนดเองได้โดยการขยาย TextView และการตั้งค่าแบบอักษรในตัวสร้างอาจเป็นตัวเลือกจากนั้นคุณสามารถใช้การควบคุมนี้ได้ตลอดทั้งแอปแทนที่ textview ของคุณ นอกจากนี้เพื่อประหยัดหน่วยความจำคุณสามารถป้องกันการโหลดทรัพยากรโดยใช้แบบอักษรแบบคงที่
Varun

@Varun: แนวคิดนี้ช่วยประหยัดเวลาของฉันได้ แต่ฉันต้องตั้งค่าการควบคุมทั้งหมดและการเขียนการควบคุมแบบกำหนดเองสำหรับแต่ละรายการจะเป็นวิธีที่ยาวนานกว่าการตั้งค่ารันไทม์แบบอักษรคุณคิดว่าอย่างไร? (อย่างไรก็ตาม +1 สำหรับการเขียนคอนโทรลแบบกำหนดเอง)
Prasham

คุณอาจต้องการเขียนคอนโทรลแบบกำหนดเองเพียงตัวเดียวที่ขยาย textView และการปรับเปลี่ยนเพียงอย่างเดียวจะเป็นการตั้งค่าแบบอักษร ด้วยการใช้การควบคุม cusotm ในไฟล์เลย์เอาต์ของคุณคุณไม่จำเป็นต้องทำ eveytime สำหรับแต่ละ textview ด้วยตนเองและคุณยังสามารถมั่นใจได้ว่าคุณกำลังใช้แบบอักษรที่คุณต้องการ
Varun

แล้วการเขียนแบบกำหนดเองVIEWแทนที่จะเขียน a custom text viewและ a custom button viewแยกกันล่ะ? ความต้องการของฉันมีไว้สำหรับทุกการควบคุมและมุมมองข้อความเป็นเพียงตัวอย่าง ขออภัยฉันลืมพูดถึง .. :-(
Prasham

1
ดูคำถาม satckoverflow stackoverflow.com/questions/2711858/…มันช่วยคุณได้
Ashwini

คำตอบ:


123

แก้ไข : เป็นเวลานานแล้วและฉันต้องการเพิ่มสิ่งที่ฉันคิดว่าเป็นวิธีที่ดีที่สุดในการทำเช่นนี้และผ่าน XML ไม่น้อย!

ก่อนอื่นคุณจะต้องสร้างคลาสใหม่ที่แทนที่มุมมองที่คุณต้องการปรับแต่ง (เช่นต้องการปุ่มที่มีแบบอักษรที่กำหนดเองหรือไม่ขยายButton) ลองทำตัวอย่าง:

public class CustomButton extends Button {
    private final static int ROBOTO = 0;
    private final static int ROBOTO_CONDENSED = 1;

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

    public CustomButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        parseAttributes(context, attrs); //I'll explain this method later
    }

    public CustomButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        parseAttributes(context, attrs);
    }
}

ตอนนี้ถ้าคุณไม่มีให้เพิ่มเอกสาร XML ด้านล่างres/values/attrs.xmlและเพิ่ม:

<resources>
    <!-- Define the values for the attribute -->
    <attr name="typeface" format="enum">
        <enum name="roboto" value="0"/>
        <enum name="robotoCondensed" value="1"/>
    </attr>

    <!-- Tell Android that the class "CustomButton" can be styled, 
         and which attributes it supports -->
    <declare-styleable name="CustomButton">
        <attr name="typeface"/>
    </declare-styleable>
</resources>

เอาล่ะด้วยวิธีนี้เราจะกลับไปที่parseAttributes()วิธีการก่อนหน้านี้:

private void parseAttributes(Context context, AttributeSet attrs) {
    TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.CustomButton);

    //The value 0 is a default, but shouldn't ever be used since the attr is an enum
    int typeface = values.getInt(R.styleable.CustomButton_typeface, 0);

    switch(typeface) {
        case ROBOTO: default:
            //You can instantiate your typeface anywhere, I would suggest as a 
            //singleton somewhere to avoid unnecessary copies
            setTypeface(roboto); 
            break;
        case ROBOTO_CONDENSED:
            setTypeface(robotoCondensed);
            break;
    }

    values.recycle();
}

ตอนนี้คุณพร้อมแล้ว คุณสามารถเพิ่มแอตทริบิวต์อื่น ๆ สำหรับอะไรก็ได้ (คุณสามารถเพิ่มอีกอันหนึ่งสำหรับ typefaceStyle - ตัวหนาตัวเอียง ฯลฯ ) แต่ตอนนี้เรามาดูวิธีใช้กัน:

<?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/com.yourpackage.name"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.yourpackage.name.CustomButton
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me!"
        custom:typeface="roboto" />

</LinearLayout>

xmlns:customบรรทัดจริงๆสามารถเป็นอะไรก็ได้ แต่การประชุมเป็นสิ่งที่แสดงไว้ข้างต้น สิ่งที่สำคัญคือมันไม่เหมือนใครและนั่นคือเหตุผลที่ใช้ชื่อแพ็กเกจ ตอนนี้คุณใช้custom:คำนำหน้าสำหรับแอตทริบิวต์ของคุณและandroid:คำนำหน้าสำหรับแอตทริบิวต์ android

สิ่งสุดท้าย: หากคุณต้องการใช้สิ่งนี้ในลักษณะ ( res/values/styles.xml) คุณไม่ควรเพิ่มxmlns:customบรรทัด เพียงอ้างอิงชื่อของแอตทริบิวต์โดยไม่มีคำนำหน้า:

<style name="MyStyle>
    <item name="typeface">roboto</item>
</style>

                               (PREVIOUS ANSWER)

ใช้แบบอักษรที่กำหนดเองใน Android

สิ่งนี้น่าจะช่วยได้ โดยทั่วไปไม่มีวิธีทำใน XML และเท่าที่ฉันบอกได้ไม่มีวิธีที่ง่ายกว่าในการทำในโค้ด คุณสามารถมีเมธอด setLayoutFont () ที่สร้างแบบอักษรหนึ่งครั้งจากนั้นเรียกใช้ setTypeface () สำหรับแต่ละ คุณต้องอัปเดตทุกครั้งที่คุณเพิ่มรายการใหม่ลงในเค้าโครง สิ่งที่ต้องการด้านล่าง:

public void setLayoutFont() {
    Typeface tf = Typeface.createFromAsset(
        getBaseContext().getAssets(), "fonts/BPreplay.otf");
    TextView tv1 = (TextView)findViewById(R.id.tv1);
    tv1.setTypeface(tf);

    TextView tv2 = (TextView)findViewById(R.id.tv2);
    tv2.setTypeface(tf);

    TextView tv3 = (TextView)findViewById(R.id.tv3);
    tv3.setTypeface(tf);
}

แก้ไข : ดังนั้นฉันจึงได้ใช้สิ่งนี้ด้วยตัวเองและวิธีที่ฉันทำมันคือการสร้างฟังก์ชันเช่นนี้:

public static void setLayoutFont(Typeface tf, TextView...params) {
    for (TextView tv : params) {
        tv.setTypeface(tf);
    }
}

จากนั้นใช้วิธีนี้จาก onCreate () และส่ง TextView ทั้งหมดที่คุณต้องการอัปเดต:

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/BPreplay.otf");
//find views by id...
setLayoutFont(tf, tv1, tv2, tv3, tv4, tv5);

แก้ไข 9/5/12:

ดังนั้นเนื่องจากสิ่งนี้ยังคงได้รับการดูและโหวตฉันจึงต้องการเพิ่มวิธีที่ดีกว่าและสมบูรณ์กว่านี้:

Typeface mFont = Typeface.createFromAsset(getAssets(), "fonts/BPreplay.otf");
ViewGroup root = (ViewGroup)findViewById(R.id.myrootlayout);
setFont(root, mFont);

/*
 * Sets the font on all TextViews in the ViewGroup. Searches
 * recursively for all inner ViewGroups as well. Just add a
 * check for any other views you want to set as well (EditText,
 * etc.)
 */
public void setFont(ViewGroup group, Typeface font) {
    int count = group.getChildCount();
    View v;
    for(int i = 0; i < count; i++) {
        v = group.getChildAt(i);
        if(v instanceof TextView || v instanceof Button /*etc.*/)
            ((TextView)v).setTypeface(font);
        else if(v instanceof ViewGroup)
            setFont((ViewGroup)v, font);
    }
}

หากคุณส่งผ่านรูทของเค้าโครงของคุณมันจะตรวจสอบซ้ำTextViewหรือButtonมุมมอง (หรืออื่น ๆ ที่คุณเพิ่มเข้าไปในคำสั่ง if นั้น) ภายในเค้าโครงนั้นและตั้งค่าแบบอักษรโดยที่คุณไม่ต้องระบุด้วย ID แน่นอนว่าคุณต้องการตั้งค่าแบบอักษรเป็นทุกมุมมอง


1
ฉันไม่เห็นความแตกต่างใด ๆ ในรหัสของคุณและรหัสของฉันยกเว้นฉันใช้วิธีนี้เป็นวิธีการจากโรงงานสำหรับแอปพลิเคชันทั้งหมดและดูเหมือนว่าโค้ดของคุณจะเขียนขึ้นสำหรับกิจกรรมเดียว ปล. เป็นเรื่องแปลกมากที่จะเพิ่มวัตถุอีกหนึ่งรายการสำหรับ textView แบบอ่านอย่างเดียวเพื่อเปลี่ยนแบบอักษร ปิดหัวข้อ: Android ควรแนะนำกลไกในการดึงแบบอักษรจากโฟลเดอร์ assests และรวมอยู่ใน R เพื่อให้สามารถเปลี่ยนเวลาออกแบบได้)
Prasham

1
ฉันเดาตามความเป็นจริงแล้วไม่มีความแตกต่างใด ๆ นอกจากคุณจะไม่สร้าง Typeface ซ้ำแล้วซ้ำเล่า ความคิดของ Varun ที่จะใช้แบบอักษรคงที่ก็สามารถทำได้เช่นเดียวกัน
Kevin Coppock

1
บรรทัดสุดท้ายของโค้ดตัวอย่างของคุณควร setLayoutFont (tf, tv1, tv2, tv3, tv4, tv5); มากกว่า setTypeface (tf, tv1, tv2, tv3, tv4, tv5);?
Kyle Clegg

1
คุณไม่ควร? recycleTypedArray values
CorayThan

1
หากใช้ Gradle เนมสเปซที่กำหนดเองควรเป็นxmlns:custom="http://schemas.android.com/apk/res-auto"
Jabari

93

มีวิธีที่ค่อนข้างง่ายในการดำเนินการผ่าน XML คุณเพียงแค่ต้องสร้างวิดเจ็ตของคุณเองที่ขยาย TextView

ขั้นแรกให้สร้างไฟล์ใน res / values ​​/ attrs.xml โดยมีเนื้อหาต่อไปนี้:

<resources>
    <declare-styleable name="TypefacedTextView">
        <attr name="typeface" format="string" />
    </declare-styleable>
</resources>

หลังจากนั้นสร้างวิดเจ็ตที่กำหนดเองของคุณ:

package your.package.widget;

public class TypefacedTextView extends TextView {

    public TypefacedTextView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //Typeface.createFromAsset doesn't work in the layout editor. Skipping...
        if (isInEditMode()) {
            return;
        }

        TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.TypefacedTextView);
        String fontName = styledAttrs.getString(R.styleable.TypefacedTextView_typeface);
        styledAttrs.recycle();

        if (fontName != null) {
            Typeface typeface = Typeface.createFromAsset(context.getAssets(), fontName);
            setTypeface(typeface);
        }
    }

}

ดังที่คุณเห็นรหัสด้านบนจะอ่านแบบอักษรภายในสินทรัพย์ / โฟลเดอร์ สำหรับตัวอย่างนี้ฉันสมมติว่ามีไฟล์ชื่อ "custom.ttf" อยู่ในโฟลเดอร์ assets ในที่สุดใช้วิดเจ็ตใน XMLs:

<your.package.widget.TypefacedTextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:your_namespace="http://schemas.android.com/apk/res/your.package"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Custom fonts in XML are easy"
    android:textColor="#FFF"
    android:textSize="14dip"
    your_namespace:typeface="custom.ttf" />

หมายเหตุ: คุณจะไม่เห็นแบบอักษรที่กำหนดเองของคุณในโปรแกรมแก้ไขโครงร่างของ Eclipse นี่คือเหตุผลที่ฉันใส่isInEditMode()เช็ค แต่ถ้าคุณเรียกใช้แอปแบบอักษรที่กำหนดเองจะทำงานได้อย่างมีเสน่ห์

หวังว่าจะช่วยได้!


ฉันไม่ได้ลองสิ่งนี้ แต่ฉันสร้างการควบคุมแบบกำหนดเองโดยการขยายTextViewคลาส ตั้งค่าtypefaceในนั้นและใช้การควบคุมแบบกำหนดเองในเค้าโครงตามที่เราทำตามปกติ & มันใช้ได้ผลสำหรับฉัน ... มันง่ายมากที่ข้างบน ...
Mahendra Liya

1
ฉันทำตามที่คุณพูด ข้อแตกต่างเพียงอย่างเดียวคือฉันทำให้ส่วนประกอบนี้ใช้ซ้ำได้เนื่องจากคำถามถามว่าจะทำอย่างไรผ่าน XML มีวิธีดำเนินการผ่าน XML และนั่นคือวิธีที่จะทำ :)
leocadiotine

โค้ดที่ง่ายมากในการรวม มันใช้ได้กับฉัน ขอบคุณ.
Durai

1
อันนี้น่าจะเป็นคำตอบที่ได้รับการยอมรับ เขียนได้ดี ขอบคุณ!
Reaz Murshed

1
สุดยอด! คุณช่วยแชร์รหัสเพื่อให้ฉันอัปเดตคำตอบได้ไหม
leocadiotine

15

ตัวอย่าง TextView พร้อมแบบอักษร roboto:

attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="RobotoTextView">
    <attr name="typeface"/>
</declare-styleable>

<attr name="typeface" format="enum">
    <enum name="roboto_thin" value="0"/>
    <enum name="roboto_thin_italic" value="1"/>
    <enum name="roboto_light" value="2"/>
    <enum name="roboto_light_italic" value="3"/>
    <enum name="roboto_regular" value="4"/>
    <enum name="roboto_italic" value="5"/>
    <enum name="roboto_medium" value="6"/>
    <enum name="roboto_medium_italic" value="7"/>
    <enum name="roboto_bold" value="8"/>
    <enum name="roboto_bold_italic" value="9"/>
    <enum name="roboto_black" value="10"/>
    <enum name="roboto_black_italic" value="11"/>
    <enum name="roboto_condensed" value="12"/>
    <enum name="roboto_condensed_italic" value="13"/>
    <enum name="roboto_condensed_bold" value="14"/>
    <enum name="roboto_condensed_bold_italic" value="15"/>
</attr>

</resources>

RobotoTextView.java:

public class RobotoTextView extends TextView {

/*
 * Permissible values ​​for the "typeface" attribute.
 */
private final static int ROBOTO_THIN = 0;
private final static int ROBOTO_THIN_ITALIC = 1;
private final static int ROBOTO_LIGHT = 2;
private final static int ROBOTO_LIGHT_ITALIC = 3;
private final static int ROBOTO_REGULAR = 4;
private final static int ROBOTO_ITALIC = 5;
private final static int ROBOTO_MEDIUM = 6;
private final static int ROBOTO_MEDIUM_ITALIC = 7;
private final static int ROBOTO_BOLD = 8;
private final static int ROBOTO_BOLD_ITALIC = 9;
private final static int ROBOTO_BLACK = 10;
private final static int ROBOTO_BLACK_ITALIC = 11;
private final static int ROBOTO_CONDENSED = 12;
private final static int ROBOTO_CONDENSED_ITALIC = 13;
private final static int ROBOTO_CONDENSED_BOLD = 14;
private final static int ROBOTO_CONDENSED_BOLD_ITALIC = 15;
/**
 * List of created typefaces for later reused.
 */
private final static SparseArray<Typeface> mTypefaces = new SparseArray<Typeface>(16);

/**
 * Simple constructor to use when creating a view from code.
 *
 * @param context The Context the view is running in, through which it can
 *                access the current theme, resources, etc.
 */
public RobotoTextView(Context context) {
    super(context);
}

/**
 * Constructor that is called when inflating a view from XML. This is called
 * when a view is being constructed from an XML file, supplying attributes
 * that were specified in the XML file. This version uses a default style of
 * 0, so the only attribute values applied are those in the Context's Theme
 * and the given AttributeSet.
 * <p/>
 * <p/>
 * The method onFinishInflate() will be called after all children have been
 * added.
 *
 * @param context The Context the view is running in, through which it can
 *                access the current theme, resources, etc.
 * @param attrs   The attributes of the XML tag that is inflating the view.
 * @see #RobotoTextView(Context, AttributeSet, int)
 */
public RobotoTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    parseAttributes(context, attrs);
}

/**
 * Perform inflation from XML and apply a class-specific base style. This
 * constructor of View allows subclasses to use their own base style when
 * they are inflating.
 *
 * @param context  The Context the view is running in, through which it can
 *                 access the current theme, resources, etc.
 * @param attrs    The attributes of the XML tag that is inflating the view.
 * @param defStyle The default style to apply to this view. If 0, no style
 *                 will be applied (beyond what is included in the theme). This may
 *                 either be an attribute resource, whose value will be retrieved
 *                 from the current theme, or an explicit style resource.
 * @see #RobotoTextView(Context, AttributeSet)
 */
public RobotoTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    parseAttributes(context, attrs);
}

/**
 * Parse the attributes.
 *
 * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
 * @param attrs   The attributes of the XML tag that is inflating the view.
 */
private void parseAttributes(Context context, AttributeSet attrs) {
    TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.RobotoTextView);

    int typefaceValue = values.getInt(R.styleable.RobotoTextView_typeface, 0);
    values.recycle();

    setTypeface(obtaintTypeface(context, typefaceValue));
}

/**
 * Obtain typeface.
 *
 * @param context       The Context the view is running in, through which it can
 *                      access the current theme, resources, etc.
 * @param typefaceValue values ​​for the "typeface" attribute
 * @return Roboto {@link Typeface}
 * @throws IllegalArgumentException if unknown `typeface` attribute value.
 */
private Typeface obtaintTypeface(Context context, int typefaceValue) throws IllegalArgumentException {
    Typeface typeface = mTypefaces.get(typefaceValue);
    if (typeface == null) {
        typeface = createTypeface(context, typefaceValue);
        mTypefaces.put(typefaceValue, typeface);
    }
    return typeface;
}

/**
 * Create typeface from assets.
 *
 * @param context       The Context the view is running in, through which it can
 *                      access the current theme, resources, etc.
 * @param typefaceValue values ​​for the "typeface" attribute
 * @return Roboto {@link Typeface}
 * @throws IllegalArgumentException if unknown `typeface` attribute value.
 */
private Typeface createTypeface(Context context, int typefaceValue) throws IllegalArgumentException {
    Typeface typeface;
    switch (typefaceValue) {
        case ROBOTO_THIN:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Thin.ttf");
            break;
        case ROBOTO_THIN_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-ThinItalic.ttf");
            break;
        case ROBOTO_LIGHT:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Light.ttf");
            break;
        case ROBOTO_LIGHT_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-LightItalic.ttf");
            break;
        case ROBOTO_REGULAR:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Regular.ttf");
            break;
        case ROBOTO_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Italic.ttf");
            break;
        case ROBOTO_MEDIUM:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Medium.ttf");
            break;
        case ROBOTO_MEDIUM_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-MediumItalic.ttf");
            break;
        case ROBOTO_BOLD:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Bold.ttf");
            break;
        case ROBOTO_BOLD_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldItalic.ttf");
            break;
        case ROBOTO_BLACK:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Black.ttf");
            break;
        case ROBOTO_BLACK_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BlackItalic.ttf");
            break;
        case ROBOTO_CONDENSED:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Condensed.ttf");
            break;
        case ROBOTO_CONDENSED_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-CondensedItalic.ttf");
            break;
        case ROBOTO_CONDENSED_BOLD:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldCondensed.ttf");
            break;
        case ROBOTO_CONDENSED_BOLD_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldCondensedItalic.ttf");
            break;
        default:
            throw new IllegalArgumentException("Unknown `typeface` attribute value " + typefaceValue);
    }
    return typeface;
}

}

ตัวอย่างการใช้งาน:

<your.package.widget.RobotoTextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:typeface="roboto_thin"
                android:textSize="22sp"
                android:text="Roboto Thin"/>

แหล่งข้อมูล: แบบอักษร Roboto & Noto


มีวิธีใช้โซลูชันนี้โดยไม่ต้องแก้ไขรหัสของฟอนต์ในคลาส java หรือไม่? อาจอ่านฟิลด์สุดท้ายเหล่านี้จาก enum attrs .. private final static int ROBOTO_THIN = 0; int คงที่สุดท้ายส่วนตัว ROBOTO_THIN_ITALIC = 1; int คงที่สุดท้ายส่วนตัว ROBOTO_LIGHT = 2; ...
Arthur Melo

3

มันสายเกินไป แต่ของฉันมันช่วยคนอื่น
ฉันได้สร้าง CustomTextView ซึ่งมีแอตทริบิวต์ที่เรียกว่า typeFace และการดูแลปัญหาหน่วยความจำรั่วด้วยการโหลดแบบอักษรโดยไม่ต้องแคช

Fontsชั้นแรกที่โหลดแบบอักษรจากเนื้อหาเพียงครั้งเดียวเท่านั้น

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

import java.util.Hashtable;

/**
 * Created by tonyhaddad on 7/19/15.
 */
public class Fonts {
    private Context context;

    public Fonts(Context context) {
        this.context = context;
    }
    private static Hashtable<String, Typeface> sTypeFaces = new Hashtable<String, Typeface>(
            4);
    public static Typeface getTypeFace(Context context, String fileName) {
        Typeface tempTypeface = sTypeFaces.get(fileName);

        if (tempTypeface == null) {
            String fontPath=null;
            if(fileName=="metabold")
                fontPath ="fonts/Meta-Bold.ttf";

            else if(fileName=="metanormal")
                fontPath="fonts/Meta-Normal.ttf";
            else if(fileName=="gsligh")
                fontPath="fonts/gesslight.ttf";
            else if(fileName=="bold")
                fontPath="fonts/Lato-Bold.ttf";
            else if(fileName=="rcr")
                fontPath="fonts/RobotoCondensed-Regular.ttf";

            else if(fileName=="mpr")
                fontPath="fonts/MyriadPro-Regular.otf";
            else if(fileName=="rr")
                fontPath="fonts/Roboto-Regular.ttf";

            tempTypeface = Typeface.createFromAsset(context.getAssets(), fontPath);
            sTypeFaces.put(fileName, tempTypeface);
        }

        return tempTypeface;
    }
}

จากนั้นคุณต้องเพิ่มแอตทริบิวต์ที่กำหนดเองใน attrs.xml เพิ่มสิ่งนี้

<declare-styleable name="CustomFontTextView">
        <attr name="typeFace" format="string" />

    </declare-styleable>

จากนั้นคลาสที่กำหนดเอง

 package package_name;

/**
 * Created by tonyhaddad on 8/26/15.
 */

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

import package_name.R;

public class CustomFontTextView extends TextView {

    String typeFace;


    public CustomFontTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        if (isInEditMode()) {
            return;
        }
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.CustomFontTextView,
                0, 0);
        try {
            typeFace = a.getString(0);
        } finally {
            a.recycle();
        }

        if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
        {
            Typeface tf = Fonts.getTypeFace(context, typeFace);
            setTypeface(tf);
        }
        init();
    }

    public CustomFontTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        if (isInEditMode()) {
            return;
        }
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.CustomFontTextView,
                0, 0);
        try {
            typeFace = a.getString(0);
        } finally {
            a.recycle();
        }

        if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
        {
            Typeface tf = Fonts.getTypeFace(context, typeFace);
            setTypeface(tf);
        }

        init();
    }

    public CustomFontTextView(Context context) {
        super(context);



        if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
        {
            Typeface tf = Fonts.getTypeFace(context, typeFace);
            setTypeface(tf);
        }
        init();
    }


    private void init() {

    }

    public String getTypeFace() {
        return typeFace;
    }

    public void setTypeFace(String typeFace) {
        this.typeFace = typeFace;
        invalidate();
        requestLayout();
    }
}

และสุดท้ายเพิ่มมุมมองข้อความ

  <package_name.CustomFontTextView
            xmlns:custom="http://schemas.android.com/apk/res-auto/package_name"
            android:id="@+id/txt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="41dp"
            android:gravity="center_vertical"
            android:text="text"
            android:textColor="#000"
            android:textSize="23sp"
            custom:typeFace="metanormal"/>

และคุณสามารถเปลี่ยนฟอนต์ progrmaticlly ด้วยเมธอด setTypeFace
นอกจากนี้คุณยังสามารถย้ายเนมสเปซที่กำหนดเองไปยังเลย์เอาต์หลักของคุณได้หากคุณต้องการใช้มากกว่าหนึ่งจากมุมมองนี้

Happy Coding :)


คำตอบแบบแบ่งชั้นง่ายๆ
eyadMhanna

2

วิธีการด้านล่างนี้เรียกว่า onCreate () และส่งผ่าน ViewGroup ด้านนอกสุดของคุณจะใช้ได้กับทุกสิ่งยกเว้นข้อความที่สร้างขึ้นแบบไดนามิก (เช่นรายการแบบไดนามิกการแจ้งเตือน ฯลฯ ) วิธีง่ายๆในการรับ ViewGroup ที่อยู่นอกสุดคือการใช้ getRootView กับมุมมองใดมุมมองหนึ่งของคุณ

public void onCreate(Bundle savedInstanceState){
    //onCreate code...
    EditText text = (EditText) findViewById(R.id.editText1);
    setTypeFaceForViewGroup((ViewGroup) text.getRootView());
}

private void setTypeFaceForViewGroup(ViewGroup vg){

    for (int i = 0; i < vg.getChildCount(); i++) {

            if (vg.getChildAt(i) instanceof ViewGroup)
                setTypeFaceForViewGroup((ViewGroup) vg.getChildAt(i));

            else if (vg.getChildAt(i) instanceof TextView)
                ((TextView) vg.getChildAt(i)).setTypeface(Typeface.createFromAsset(getAssets(), "fonts/Your_Font.ttf"));

    }

}

สิ่งนี้ควรใช้ได้กับเนื้อหาไดนามิกเช่นกันคุณต้องเรียกมันว่าส่งผ่านสิ่งที่คุณสร้างหลังจากที่คุณสร้างมัน (ฉันยังไม่ได้ทดสอบสิ่งนี้)

เพื่อประหยัดหน่วยความจำคุณอาจต้องการทำให้แบบอักษรเป็นตัวแปรคงที่แทนที่จะสร้างใหม่ทุกครั้งที่ลูปทำงานเหมือนที่ฉันมีที่นี่


ฉันไม่แนะนำวิธีแก้ปัญหานี้เนื่องจากคุณกำลังสร้างอินสแตนซ์ใหม่ของแบบอักษรเดียวกันสำหรับแต่ละองค์ประกอบที่คุณต้องการนำไปใช้ ซึ่งอาจทำให้เกิดปัญหาเกี่ยวกับหน่วยความจำ
ข้อบกพร่อง

ที่กล่าวถึงในบันทึกของฉันในตอนท้าย
คริส

2

หากคุณกำลังมองหาวิธีแก้ปัญหาแบบเป็นโปรแกรมทั่วไปฉันได้สร้างคลาสแบบคงที่ที่สามารถใช้เพื่อตั้งค่า Typeface ของมุมมองทั้งหมด (UI กิจกรรม) โปรดทราบว่าฉันกำลังทำงานกับ Mono (C #) แต่คุณสามารถใช้งานได้อย่างง่ายดายโดยใช้ Java

คุณสามารถส่งเลย์เอาต์คลาสนี้หรือมุมมองเฉพาะที่คุณต้องการกำหนดเองได้ หากคุณต้องการประสิทธิภาพสูงสุดคุณสามารถใช้งานได้โดยใช้รูปแบบ Singleton

public static class AndroidTypefaceUtility 
{
    static AndroidTypefaceUtility()
    {
    }
    //Refer to the code block beneath this one, to see how to create a typeface.
    public static void SetTypefaceOfView(View view, Typeface customTypeface)
    {
    if (customTypeface != null && view != null)
    {
            try
            {
                if (view is TextView)
                    (view as TextView).Typeface = customTypeface;
                else if (view is Button)
                    (view as Button).Typeface = customTypeface;
                else if (view is EditText)
                    (view as EditText).Typeface = customTypeface;
                else if (view is ViewGroup)
                    SetTypefaceOfViewGroup((view as ViewGroup), customTypeface);
                else
                    Console.Error.WriteLine("AndroidTypefaceUtility: {0} is type of {1} and does not have a typeface property", view.Id, typeof(View));
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine("AndroidTypefaceUtility threw:\n{0}\n{1}", ex.GetType(), ex.StackTrace);
                    throw ex;
                }
            }
            else
            {
                Console.Error.WriteLine("AndroidTypefaceUtility: customTypeface / view parameter should not be null");
            }
        }

        public static void SetTypefaceOfViewGroup(ViewGroup layout, Typeface customTypeface)
        {
            if (customTypeface != null && layout != null)
            {
                for (int i = 0; i < layout.ChildCount; i++)
                {
                    SetTypefaceOfView(layout.GetChildAt(i), customTypeface);
                }
            }
            else
            {
                Console.Error.WriteLine("AndroidTypefaceUtility: customTypeface / layout parameter should not be null");
            }
        }

    }

ในกิจกรรมของคุณคุณจะต้องสร้างวัตถุ Typeface ฉันสร้างของฉันใน OnCreate () โดยใช้ไฟล์. ttf ที่วางไว้ในไดเร็กทอรี Resources / Assets / ของฉัน ตรวจสอบว่าไฟล์ถูกทำเครื่องหมายเป็น Android Asset ในคุณสมบัติ '

protected override void OnCreate(Bundle bundle)
{               
    ...
    LinearLayout rootLayout = (LinearLayout)FindViewById<LinearLayout>(Resource.Id.signInView_LinearLayout);
    Typeface allerTypeface = Typeface.CreateFromAsset(base.Assets,"Aller_Rg.ttf");
    AndroidTypefaceUtility.SetTypefaceOfViewGroup(rootLayout, allerTypeface);
}

2

น่าเสียดายที่ Android ไม่มีวิธีที่รวดเร็วง่ายและสะอาดที่คุณต้องการเพื่อเปลี่ยนแบบอักษรสำหรับทั้งแอป แต่เมื่อไม่นานมานี้ฉันได้ตรวจสอบเรื่องนี้และได้สร้างเครื่องมือบางอย่างที่ช่วยให้คุณสามารถเปลี่ยนฟอนต์โดยไม่ต้องเข้ารหัสใด ๆ (คุณสามารถทำได้ทั้งหมดผ่าน xml สไตล์และแม้แต่ข้อความที่ปรากฏ) โดยอ้างอิงจากโซลูชันที่คล้ายกันเช่นที่คุณเห็นในคำตอบอื่น ๆ ที่นี่ แต่ให้ความยืดหยุ่นมากขึ้น คุณสามารถอ่านทั้งหมดเกี่ยวกับเรื่องในบล็อกนี้และเห็นโครงการ GitHub ที่นี่

นี่คือตัวอย่างวิธีการใช้เครื่องมือเหล่านี้ ใส่ไฟล์ font assets/fonts/ของคุณทั้งหมดใน จากนั้นประกาศฟอนต์เหล่านั้นในไฟล์ xml (เช่นres/xml/fonts.xml) และโหลดไฟล์นี้ก่อนใครในแอพของคุณด้วยTypefaceManager.initialize(this, R.xml.fonts);(เช่นใน onCreate ของคลาส Application ของคุณ) ไฟล์ xml มีลักษณะดังนี้:

<?xml version="1.0" encoding="utf-8"?>
<familyset>

    <!-- Some Font. Can be referenced with 'someFont' or 'aspergit' -->
    <family>
        <nameset>
            <name>aspergit</name>
            <name>someFont</name>
        </nameset>
        <fileset>
            <file>Aspergit.ttf</file>
            <file>Aspergit Bold.ttf</file>
            <file>Aspergit Italic.ttf</file>
            <file>Aspergit Bold Italic.ttf</file>
        </fileset>
    </family>

    <!-- Another Font. Can be referenced with 'anotherFont' or 'bodoni' -->
    <family>
        <nameset>
            <name>bodoni</name>
            <name>anotherFont</name>
        </nameset>
        <fileset>
            <file>BodoniFLF-Roman.ttf</file>
            <file>BodoniFLF-Bold.ttf</file>
        </fileset>
    </family>

</familyset>

ตอนนี้คุณสามารถใช้ฟอนต์เหล่านี้ในสไตล์หรือ xml ของคุณได้แล้ว (หากคุณใช้เครื่องมือที่ฉันกล่าวถึงข้างต้น) โดยใช้องค์ประกอบ UI ที่กำหนดเองcom.innovattic.font.FontTextViewในเลย์เอาต์ xml ของคุณ ด้านล่างนี้คุณสามารถดูวิธีใช้แบบอักษรกับข้อความทั้งหมดในแอปทั้งหมดของคุณได้เพียงแค่แก้ไขres/values/styles.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">

    <!-- Application theme -->
    <!-- Use a different parent if you don't want Holo Light -->
    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <item name="android:textViewStyle">@style/MyTextViewStyle</item>
    </style>

    <!-- Style to use for ALL text views (including FontTextView) -->
    <!-- Use a different parent if you don't want Holo Light -->
    <style name="MyTextViewStyle" parent="@android:style/Widget.Holo.Light.TextView">
        <item name="android:textAppearance">@style/MyTextAppearance</item>
    </style>

    <!-- Text appearance to use for ALL text views (including FontTextView) -->
    <!-- Use a different parent if you don't want Holo Light -->
    <style name="MyTextAppearance" parent="@android:style/TextAppearance.Holo">
        <!-- Alternatively, reference this font with the name "aspergit" -->
        <!-- Note that only our own TextView's will use the font attribute -->
        <item name="flFont">someFont</item>
        <item name="android:textStyle">bold|italic</item>
    </style>

    <!-- Alternative style, maybe for some other widget -->
    <style name="StylishFont">
        <item name="flFont">anotherFont</item>
        <item name="android:textStyle">normal</item>
    </style>

</resources>

พร้อมด้วยres/layout/layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <!-- This text view is styled with the app theme -->
    <com.innovattic.font.FontTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This uses my font in bold italic style" />

    <!-- This text view is styled here and overrides the app theme -->
    <com.innovattic.font.FontTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:flFont="anotherFont"
        android:textStyle="normal"
        android:text="This uses another font in normal style" />

    <!-- This text view is styled with a style and overrides the app theme -->
    <com.innovattic.font.FontTextView
        style="@style/StylishFont"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This also uses another font in normal style" />

</LinearLayout>

อย่าลืมใช้ธีมในรายการ Android ของคุณ


2

ฉันต้องการเพิ่มหมายเหตุในการแก้ปัญหาที่ยอดเยี่ยมของleocadiotine. มันสมบูรณ์แบบ แต่เมื่อใช้ Custom TextView หลายครั้งทำให้แอปพลิเคชันช้าลงเนื่องจากต้องเข้าถึงเนื้อหาทุกครั้งที่มีการสร้าง textview ฉันแนะนำให้ใช้บางอย่างเช่นView Holder patternในAdaptersฉันเขียนตัวอย่าง:

public class Fonts {

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

    public static Typeface getTypeface(Context ctx, String fontName) {
        Typeface typeface = typefaces.get(fontName);
        if (typeface == null) {
            typeface = Typeface.createFromAsset(ctx.getAssets(), fontName);
            typefaces.put(fontName, typeface);
        }
        return typeface;
    } 
}

ด้วยวิธีนี้แอปพลิเคชันจะเข้าถึงเนื้อหาเพียงครั้งเดียวต่อหนึ่งเนื้อหาและจะเก็บไว้ในหน่วยความจำสำหรับความต้องการเพิ่มเติม


0

ฉันไม่รู้ว่ามันเปลี่ยนทั้งแอพหรือเปล่า แต่ฉันได้จัดการเปลี่ยนส่วนประกอบบางอย่างที่ไม่สามารถเปลี่ยนแปลงได้โดยทำสิ่งนี้:

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Lucida Sans Unicode.ttf");
Typeface.class.getField("DEFAULT").setAccessible(true);
Typeface.class.getField("DEFAULT_BOLD").setAccessible(true);
Typeface.class.getField("DEFAULT").set(null, tf);
Typeface.class.getField("DEFAULT_BOLD").set(null, tf);

@richard ฉันต้องการตั้งค่าแบบอักษรที่กำหนดเองตามสถานที่ตัวอย่างเช่นฉันต้องการตั้งค่า Arial TTF เมื่อเราใช้ภาษาอังกฤษและตั้งค่า TTF แบบโกธิกเมื่อฉันใช้รองเท้าเกาหลี
Dwivedi Ji

0

ฉันพบข้อมูลทีละขั้นตอนที่ลิงค์นี้ลิงค์: https://github.com/jaydipumaretiya/CustomTypeface/

มีหลายวิธีในการใช้แบบอักษรอย่างถูกต้องใน Android คุณต้องใส่ไฟล์แบบอักษรของคุณในโฟลเดอร์สินทรัพย์ภายใต้หลักของคุณโดยตรงและสามารถใช้งานได้

วิธีที่ง่ายที่สุดคือใช้ไลบรารีเริ่มต้นเพื่อตั้งค่าแบบอักษรในไฟล์ xml ของคุณ ฉันชอบไลบรารีแบบอักษรที่กำหนดเองนี้เพื่อตั้งค่าแบบอักษรเป็น TextView, EditText, Button, CheckBox, RadioButton และ AutoCompleteTextView และ Wedget อื่น ๆ ใน Android


0

Android 8.0 (API ระดับ 26) เปิดตัวฟีเจอร์ใหม่ Fonts ใน XML คุณสามารถสร้างไฟล์ fontfamily และตั้งค่าใน styles.xml

ในการเพิ่มฟอนต์เป็นทรัพยากรให้ทำตามขั้นตอนต่อไปนี้ใน Android Studio:

1. คลิกขวาที่โฟลเดอร์ res แล้วไปที่ New> Android resource directory หน้าต่าง New Resource Directory จะปรากฏขึ้น

2. ในรายการชนิดทรัพยากรเลือกแบบอักษรจากนั้นคลิกตกลง หมายเหตุ: ชื่อของไดเรกทอรีทรัพยากรต้องเป็นแบบอักษร

3. เพิ่มไฟล์ฟอนต์ของคุณในโฟลเดอร์ฟอนต์

ในการสร้างตระกูลฟอนต์ให้ทำตามขั้นตอนต่อไปนี้:

1. คลิกขวาที่โฟลเดอร์ฟอนต์แล้วไปที่ New> Font resource file หน้าต่างไฟล์ทรัพยากรใหม่จะปรากฏขึ้น

2. ป้อนชื่อไฟล์จากนั้นคลิกตกลง XML ทรัพยากรแบบอักษรใหม่จะเปิดขึ้นในตัวแก้ไข

3. ปิดไฟล์ฟอนต์สไตล์และน้ำหนักแต่ละรายการในองค์ประกอบ XML ต่อไปนี้แสดงการเพิ่มแอตทริบิวต์ที่เกี่ยวข้องกับฟอนต์ใน XML ของทรัพยากรฟอนต์:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
    <font
        android:fontStyle="normal"
        android:fontWeight="400"
        android:font="@font/lobster_regular" />
    <font
        android:fontStyle="italic"
        android:fontWeight="400"
        android:font="@font/lobster_italic" />
</font-family>

การเพิ่มแบบอักษรให้กับสไตล์

เปิด styles.xml และตั้งค่าแอตทริบิวต์ fontFamily เป็นไฟล์ฟอนต์ที่คุณต้องการเข้าถึง

 <style name="customfontstyle" parent="@android:style/TextAppearance.Small">
    <item name="android:fontFamily">@font/lobster</item>
</style>

ที่มา: ฟอนต์ใน XML

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.