Android: chcesz ustawić niestandardowe czcionki dla całej aplikacji, a nie środowiska wykonawczego

100

Czy w każdej kontrolce aplikacji można ustawić dowolną niestandardową czcionkę? A niekoniecznie runtime? (tj. z xml jeśli to możliwe lub tylko raz dla całej aplikacji w pliku JAVA)

Mogę ustawić czcionkę dla jednej kontrolki z tego kodu.

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

    textView.setTypeface(tf);

}

Problem z tym kodem polega na tym, że powinien być wywoływany dla każdej kontroli. I chcę raz wywołać tę lub inną podobną metodę lub, jeśli to możliwe, ustawić właściwość w xml. Czy to możliwe?

Prasham
źródło
6
Być może możesz napisać niestandardową kontrolkę, rozszerzając TextView i ustawiając czcionkę w konstruktorze, co może być opcją, a następnie możesz użyć tej kontrolki w całej aplikacji zamiast widoku tekstu. również w celu zaoszczędzenia pamięci u można zapobiec ładowaniu zasobów przy użyciu statycznego kroju pisma.
Varun,
@Varun: cóż, ten pomysł może zaoszczędzić mój czas, ale muszę ustawić każdą kontrolkę, a napisanie niestandardowej kontrolki dla każdego będzie dłuższą drogą niż ustawienie środowiska wykonawczego czcionki, co o tym sądzisz? (Jednak +1 za pisanie kontroli niestandardowej)
Prasham,
Możesz chcieć napisać tylko jedną kontrolkę niestandardową rozszerzającą textView, a jedyną modyfikacją będzie ustawienie kroju pisma. Używając kontroli cusotm w plikach układu, nie musisz robić tego ręcznie za każdym razem dla każdego widoku tekstu i nadal możesz mieć pewność, że używasz czcionki, której chcesz.
Varun
A co z napisaniem zwyczaju VIEWzamiast pisać osobno a custom text viewi a custom button view? Moje wymagania dotyczą każdej kontrolki, a widok tekstu był tylko przykładem. Przepraszam, zapomniałem o tym wspomnieć ... :-(
Prasham,
1
Spójrz na pytanie satckoverflow stackoverflow.com/questions/2711858/ ... to ci pomaga.
Ashwini,

Odpowiedzi:

123

EDYCJA : Więc minęło trochę czasu i chciałbym dodać to, co uważam za najlepszy sposób, aby to zrobić, a nie mniej za pomocą XML!

Najpierw będziesz chciał utworzyć nową klasę, która zastąpi dowolny widok, który chcesz dostosować. (np. chcesz mieć przycisk z niestandardowym krojem czcionki? Rozszerz Button). Zróbmy przykład:

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

Teraz, jeśli go nie masz, dodaj dokument XML pod res/values/attrs.xmli dodaj:

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

Okej, więc pomijając to, wróćmy do parseAttributes()metody z wcześniejszej:

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

Teraz wszystko gotowe. Możesz dodać więcej atrybutów do wszystkiego (możesz dodać kolejny dla stylu kroju - pogrubienie, kursywa, itp.), Ale teraz zobaczmy, jak go użyć:

<?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:customLinia może być naprawdę coś, ale konwencja jest co pokazano powyżej. Liczy się to, że jest unikalny i dlatego używana jest nazwa pakietu. Teraz wystarczy użyć custom:przedrostka dla swoich atrybutów i android:przedrostka dla atrybutów Androida.

Ostatnia sprawa: jeśli chcesz to wykorzystać w stylu ( res/values/styles.xml), należy nie dodać xmlns:customlinię. Po prostu odwołaj się do nazwy atrybutu bez przedrostka:

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

                               (PREVIOUS ANSWER)

Używanie niestandardowego kroju pisma w systemie Android

To powinno pomóc. Zasadniczo nie ma sposobu, aby to zrobić w XML i, o ile wiem, nie ma prostszego sposobu na zrobienie tego w kodzie. Zawsze możesz mieć metodę setLayoutFont (), która tworzy krój pisma raz, a następnie uruchamia setTypeface () dla każdego. Wystarczy, że zaktualizujesz go za każdym razem, gdy dodasz nowy element do układu. Coś jak poniżej:

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

EDYCJA : Więc po prostu zabrałem się za zaimplementowanie czegoś takiego samodzielnie, a jak skończyłem, zrobiłem taką funkcję:

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

Następnie użyj tej metody z onCreate () i przekaż wszystkie TextViews, które chcesz zaktualizować:

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

EDYCJA 9/5/12:

Ponieważ nadal uzyskuje się wyświetlenia i głosy, chciałbym dodać znacznie lepszą i bardziej kompletną metodę:

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

Jeśli przekażesz mu katalog główny twojego układu, będzie on rekurencyjnie sprawdzał widoki TextViewlub Button(lub inne, które dodasz do tej instrukcji if) w tym układzie i ustawi czcionkę bez konieczności określania ich przez identyfikator. To oczywiście zakłada, że ​​chcesz ustawić czcionkę dla każdego widoku.

Kevin Coppock
źródło
1
Nie widzę żadnej różnicy w twoim kodzie i moim kodzie, z wyjątkiem tego, że używam metody jako metody fabrycznej dla całej aplikacji, a twój kod wydaje się być napisany dla jednej czynności. PS To naprawdę dziwne, aby dodać jeszcze jeden obiekt dla tekstu tylko do odczytu, aby zmienić czcionkę. Off Topic: Android powinien naprawdę wprowadzić mechanizm pobierania czcionki z folderu assests i dołączenia go do R, aby można było zmienić czas projektowania)
Prasham,
1
Myślę, że realistycznie nie ma większej różnicy poza tym, że nie tworzysz kroju pisma w kółko. Pomysł Varuna, by po prostu użyć statycznego kroju pisma, zrobiłby to samo.
Kevin Coppock,
1
Czy w ostatnim wierszu przykładowego kodu należy ustawićLayoutFont (tf, tv1, tv2, tv3, tv4, tv5); zamiast setTypeface (tf, tv1, tv2, tv3, tv4, tv5) ;?
Kyle Clegg
1
Nie powinieneś ? recycleTypedArray values
CorayThan,
1
Jeśli używasz Gradle, niestandardowa przestrzeń nazw powinna mieć xmlns:custom="http://schemas.android.com/apk/res-auto"
postać
93

Jest na to dość łatwy sposób poprzez XML. Wystarczy, że stworzysz własny widget, który rozszerzy TextView.

Najpierw utwórz plik w res / values ​​/ attrs.xml z następującą zawartością:

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

Następnie utwórz swój niestandardowy widżet:

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

}

Jak widać, powyższy kod odczyta czcionkę w folderze asset /. W tym przykładzie zakładam, że w folderze zasobów znajduje się plik o nazwie „custom.ttf”. Na koniec użyj widżetu w XML:

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

Uwaga: nie będziesz w stanie zobaczyć swojej niestandardowej czcionki w edytorze układu Eclipse. Dlatego wystawiłem isInEditMode()czek. Ale jeśli uruchomisz aplikację, niestandardowa czcionka będzie działać jak urok.

Mam nadzieję, że to pomoże!

leokadiotyna
źródło
Nie próbowałem tego, ale utworzyłem niestandardową kontrolkę, rozszerzając TextViewklasę; ustawiłem typefacew nim i użyłem niestandardowej kontroli w układzie tak jak zwykle i to zadziałało dla mnie ... Jednak było proste, że powyższe ...
Mahendra Liya
1
Zrobiłem dokładnie to, co powiedziałeś. Jedyną różnicą jest to, że uczyniłem ten komponent wielokrotnego użytku, ponieważ pytanie dotyczy tego, jak to zrobić za pomocą XML. Rzeczywiście jest sposób, aby to zrobić za pomocą XML i tak to zrobić :)
leocadiotine
Bardzo łatwy kod do integracji. Mi to pasuje. Dzięki.
Durai
1
Ta powinna być akceptowaną odpowiedzią. Ładnie napisane. Dzięki!
Reaz Murshed
1
Super, @DominikSuszczewicz! Czy możesz udostępnić kod, abym zaktualizował odpowiedź?
leokadiotyna
15

Przykład TextView z krojem 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;
}

}

Przykład użycia:

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

Zasoby: czcionki Roboto i Noto

e.shishkin
źródło
jest sposób na użycie tego rozwiązania bez ustalania identyfikatorów czcionek w klasie java? może odczytać te ostatnie pola z atrybutów wyliczeniowych .. private final static int ROBOTO_THIN = 0; prywatne końcowe statyczne int ROBOTO_THIN_ITALIC = 1; prywatne końcowe statyczne int ROBOTO_LIGHT = 2; ...
Arthur Melo
3

Jest już za późno, ale moje pomaga innym
utworzyłem CustomTextView, który ma atrybut o nazwie typeFace i dba o problem z wyciekiem pamięci przy ładowaniu kroju pisma bez buforowania

Pierwsza Fontsklasa, która ładuje czcionki z zasobów tylko raz

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

następnie musisz dodać atrybut niestandardowy w attrs.xml dodaj to

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

    </declare-styleable>

następnie klasa niestandardowa

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

i na koniec dodaj widok tekstu

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

i możesz zmieniać czcionkę progrmaticlly za pomocą metody setTypeFace
również możesz przenieść niestandardową przestrzeń nazw do swojego układu nadrzędnego, jeśli chcesz użyć więcej niż jednej z tego widoku

Miłego kodowania :)

Antwan
źródło
prosta odpowiedź stratight.
eyadMhanna
2

Poniższa metoda, wywołana w onCreate () i przekazana Twojej najbardziej zewnętrznej ViewGroup, będzie działać dla wszystkiego oprócz tekstu, który jest tworzony dynamicznie (tj. Listy dynamiczne, alerty, itp.). Łatwym sposobem na uzyskanie najbardziej zewnętrznej ViewGroup jest użycie getRootView w dowolnym z widoków.

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

    }

}

Powinno to działać również w przypadku zawartości dynamicznej, po prostu musisz to nazwać, przekazując wszystko, co stworzyłeś, zaraz po utworzeniu (chociaż tego nie testowałem).

Aby zaoszczędzić pamięć, prawdopodobnie będziesz chciał ustawić krój jako zmienną statyczną, zamiast tworzyć nową za każdym razem, gdy pętla działa, tak jak tutaj.

Chris
źródło
Nie polecam tego rozwiązania, ponieważ tworzysz nową instancję tej samej czcionki dla każdego elementu, do którego chcesz ją zastosować. Może to powodować problemy z pamięcią.
flawyte
Omówię to na końcu w mojej notatce.
Chris,
2

Jeśli szukasz bardziej ogólnego rozwiązania programistycznego, stworzyłem statyczną klasę, której można użyć do ustawienia Kroju całego widoku (interfejs użytkownika). Zauważ, że pracuję z Mono (C #), ale możesz to łatwo zaimplementować za pomocą Java.

Możesz przekazać tej klasie układ lub określony widok, który chcesz dostosować. Jeśli chcesz być super wydajny, możesz zaimplementować to za pomocą wzorca 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");
            }
        }

    }

W swoim ćwiczeniu będziesz musiał utworzyć obiekt Typeface. Tworzę swoje w OnCreate () używając pliku .ttf umieszczonego w moim katalogu Resources / Assets /. Upewnij się, że plik jest oznaczony jako zasób systemu Android we właściwościach.

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);
}
JCKortlang
źródło
2

Niestety system Android nie zapewnia szybkiego, łatwego i przejrzystego sposobu, w jaki chcesz zmienić czcionkę w całej aplikacji. Ale ostatnio przyjrzałem się tej sprawie i stworzyłem kilka narzędzi, które pozwalają zmienić czcionkę bez żadnego kodowania (możesz to wszystko zrobić poprzez xml, style, a nawet wygląd tekstu). Opierają się na podobnych rozwiązaniach, jakie widzisz w innych odpowiedziach tutaj, ale pozwalają na znacznie większą elastyczność. Możesz przeczytać o tym wszystko na tym blogu , a projekt github tutaj .

Oto przykład zastosowania tych narzędzi. Umieść wszystkie pliki czcionek w assets/fonts/. Następnie zadeklaruj te czcionki w pliku xml (np. res/xml/fonts.xml) I załaduj ten plik na wczesnym etapie aplikacji TypefaceManager.initialize(this, R.xml.fonts);(np. W onCreate klasy Application). Plik xml wygląda następująco:

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

Teraz możesz używać tych czcionek w swoim stylu lub XML (pod warunkiem, że używasz narzędzi, o których wspomniałem powyżej), używając niestandardowego elementu interfejsu użytkownika com.innovattic.font.FontTextVieww swoim układzie XML. Poniżej możesz zobaczyć, jak możesz zastosować czcionkę do wszystkich tekstów w całej aplikacji, po prostu edytując 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>

Z towarzyszącymi 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>

Nie zapomnij zastosować motywu w swoim manifeście Androida.

Jelle Fresen
źródło
2

Chciałbym dodać uwagę do świetnego rozwiązania leocadiotine. Jest doskonały, ale podczas korzystania z tego niestandardowego TextView wiele razy spowalnia aplikację, ponieważ musi ona uzyskiwać dostęp do zasobów za każdym razem, gdy tworzony jest widok tekstu. Proponuję użyć czegoś takiego jak View Holder patternw Adapters, napisałem przykład:

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

W ten sposób aplikacja uzyskuje dostęp do zasobów tylko raz dla każdego zasobu i zachowuje je w pamięci na dalsze potrzeby.

Emaborsa
źródło
0

Nie wiem, czy zmienia to całą aplikację, ale udało mi się zmienić niektóre komponenty, których nie można by zmienić w inny sposób:

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
źródło
@richard, chcę ustawić niestandardową czcionkę zgodnie z lokalizacją. Na przykład chcę ustawić Arial TTF, gdy używamy angielskich ustawień regionalnych, i ustawić gotycki TTF, gdy używam koreańskiego loacale
Dwivedi Ji
0

Informacje krok po kroku znalazłem pod tym linkiem, link: https://github.com/jaydipumaretiya/CustomTypeface/

Istnieje wiele sposobów prawidłowego używania kroju pisma w systemie Android, musisz umieścić plik kroju pisma w folderze zasobów bezpośrednio w głównym folderze i możesz go używać w czasie wykonywania.

Innym najprostszym sposobem jest użycie domyślnej biblioteki do ustawienia kroju pisma w pliku xml. Wolę tę niestandardową bibliotekę krojów pisma, aby ustawić krój czcionki na TextView, EditText, Button, CheckBox, RadioButton i AutoCompleteTextView i inne narzędzia w systemie Android.

Mehul Rakholiya
źródło
0

Android 8.0 (poziom API 26) wprowadza nową funkcję Czcionki w XML Możesz utworzyć plik fontfamily i ustawić go w styles.xml.

Aby dodać czcionki jako zasoby, wykonaj następujące kroki w Android Studio:

1. Kliknij prawym przyciskiem myszy folder res i przejdź do Nowy> katalog zasobów Androida. Zostanie wyświetlone okno New Resource Directory.

2. Na liście Typ zasobu wybierz czcionkę, a następnie kliknij przycisk OK. Uwaga: nazwa katalogu zasobów musi być czcionką.

3. Dodaj pliki czcionek do folderu czcionek.

Aby utworzyć rodzinę czcionek, wykonaj następujące czynności:

1. Kliknij prawym przyciskiem myszy folder czcionek i przejdź do Nowy> Plik zasobów czcionek. Zostanie wyświetlone okno New Resource File.

2. Wprowadź nazwę pliku, a następnie kliknij przycisk OK. W edytorze zostanie otwarty nowy kod XML zasobu czcionek.

3. Zamknij każdy plik czcionki, styl i atrybut wagi w elemencie. Poniższy kod XML ilustruje dodawanie atrybutów związanych z czcionkami w kodzie XML zasobu czcionek:

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

Dodawanie czcionek do stylu

Otwórz style.xml i ustaw atrybut fontFamily na plik czcionki, do którego chcesz uzyskać dostęp.

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

Źródło: czcionki w XML

Programista Android
źródło