Android에서 사용자 지정 서체 사용


111

내가 만들고있는 내 Android 애플리케이션에 사용자 지정 글꼴을 사용하고 싶습니다.
코드에서 각 개체의 서체를 개별적으로 변경할 수 있지만 수백 개가 있습니다.

그래서,

  • XML에서이를 수행하는 방법이 있습니까? [사용자 정의 서체 설정]
  • 전체 응용 프로그램과 모든 구성 요소가 기본 서체 대신 사용자 정의 서체를 사용해야한다고 말하는 것처럼 한 곳에서 코드를 사용하는 방법이 있습니까?

stackoverflow.com/questions/5541058/… 이 게시물을보세요.이 문제에 관한 전체 코드를 여기에 게시했습니다
Manish Singla 2011

기본 활동에서 정적 변수를 사용하여 포함 된 글꼴에 대한 참조를 보유 할 수 있습니다. 그러면 GC에서 선택하지 않는 하나의 영구 글꼴 집합이있게됩니다.
Jacksonkr

공장 방법. 또는보기를 가져와 모든 글꼴 및 서체 설정을 설정하는 방법입니다.
mtmurdock

이제 새로운 지원 라이브러리 26을 사용하여 XML에서 글꼴을 사용할 수 있습니다. 가에 방법 다음은 XML 글꼴
비니 실바

답변:


80

XML에서이를 수행하는 방법이 있습니까?

아뇨, 죄송합니다. 기본 제공 서체는 XML을 통해서만 지정할 수 있습니다.

전체 응용 프로그램과 모든 구성 요소가 기본 서체 대신 사용자 정의 서체를 사용해야한다고 말하는 것처럼 한 곳에서 코드를 사용하는 방법이 있습니까?

내가 아는 것은 아닙니다.

요즘에는 다양한 옵션이 있습니다.

  • Android SDK의 글꼴 리소스 및 백 포트 (사용중인 경우) appcompat

  • appcompat모든 사용자가 레이아웃 리소스에서 글꼴 정의를 지원하지는 않지만을 사용하지 않는 사용자를위한 타사 라이브러리


4
@Codevalley : 글쎄요, 여러면에서 더 나은 대답은 사용자 정의 글꼴을 사용하지 않는 것입니다. 그들은 큰 경향이있어 다운로드를 더 많이 만들고 앱을 다운로드하고 계속 사용할 사람들의 수를 줄입니다.
CommonsWare 2010-06-05

22
@CommonsWare : 반드시 동의하지는 않습니다. 서체는 배경 이미지 등과 같이 UI 스타일링의 필수적인 부분입니다. 크기가 항상 클 필요는 없습니다. 예를 들어, 제 경우 글꼴은
19.6KB에

2
@Amit :이 문제에 대한 변경 사항은 없습니다. Java에서 UI에 서체를 간단하게 적용하는 데 도움이되는 코드 스 니펫이 많이 있지만 XML에서 수행 할 수있는 방법은 없습니다.
CommonsWare

1
@Amit : "하지만 사용자 지정 글꼴에 대해 고유 한 .ttf 또는 .otf 파일을 만들어야한다는 의미입니까?" -- 음 .. 아니야. 모두 작동하지 않을 수도 있지만 기존 TTF / OTF 글꼴을 사용할 수 있습니다. 이 질문에 대한 문제는 여전히 불가능한 전체 앱에 해당 글꼴을 적용하는 방법이며, 이것이 제가 의견에서 언급 한 것입니다.
CommonsWare

1
이 대답은 더 이상 사용되지 않으며 업데이트하거나 삭제하는 것이 좋습니다.
Sky Kelsey

109

네 가능합니다.

텍스트보기를 확장하는 사용자 지정보기를 만들어야합니다.

에서 attrs.xmlvalues폴더 :

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

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

에서 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
이것은 작동하지만 TextView. TextView동일한 기능이 필요한 곳에서 상속하는 모든 위젯 클래스에 대해 사용자 정의 하위 클래스가 필요 합니다.
CommonsWare 2011 년

안녕하세요 Manish, 솔루션에 감사드립니다. 나는 이것을 사용하는 데 문제가 있지만. 나는 '패키지 com.lht.android에서 속성 ttf_name 찾을 식별자에는 자원'지고 없습니다 계속
Kshitij 가르 왈

17
이것은 작동하지만 pre-ICS는 인스턴스화하는 각 뷰의 글꼴에 대한 메모리를 할당합니다. code.google.com/p/android/issues/detail?id=9904 이 문제를 해결하는 방법은 전역 적으로 액세스 할 수있는 파일을 만드는 것입니다. 모든 인스턴스화 된 글꼴의 정적 해시 맵 : code.google.com/p/android/issues/detail?id=9904#c7
Ken Van Hoeylandt

루프가 필요한 이유는 무엇입니까?, 단일 호출로 작동하지 않아야합니까?
Guillermo Tobar 2012

1
@AlaksiejN. 다른 TextView에 다른 서체를 설정해야하는 경우 ...
Nick

49

레이아웃 xml 또는 활동을 변경할 필요가없는보다 "무력한"방식으로이 작업을 수행했습니다.

Android 버전 2.1 ~ 4.4에서 테스트되었습니다. 앱 시작시 애플리케이션 클래스에서 실행합니다.

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

더 완전한 예는 http://github.com/perchrh/FontOverrideExample을 참조하십시오.


이것이 저에게 가장 적합한 솔루션입니다.
Igor K

2
기본값은 나를 위해 작동하지 않습니다. 고정 폭을 사용하고 code<style name = "AppTheme"parent = "AppBaseTheme"> <item name = "android : typeface"> monospace </ item> </ style>을 설정 code하면 작동하지만 굵게 표시되지 않습니다. 이 코드를 Application을 확장하는 클래스에 추가했습니다. 그것이 올바른 장소입니까? @ P-chan
Christopher Rivera

2
@ChristopherRivera 예, 앱의 Application 클래스에 추가하고 onCreate에서 실행되는지 확인합니다. grepcode.com/file/repository.grepcode.com/java/ext/…를 살펴보면 모노 스페이스에 대한 추가 필드와 위의 샘플 코드에있는 필드를 재정의하는 것이 좋습니다.
Christian Henden 당

2
좋아, 필드 SERIF에 대해 변경하며 :) 일
압둘라 Umer에게

3
이 답변은이 답변을 참조하고 더 깨끗한 접근 방식을 제공합니다.
adamdport

36

내가 가장 빠르고 가장 표적이 된 방법으로 Manish의 답변을 찬성하고 있지만 뷰 계층 구조를 반복적으로 반복하고 모든 요소의 서체를 차례로 업데이트하는 순진한 솔루션도 보았습니다. 이 같은:

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

레이아웃을 확장 한 후 활동의 onContentChanged()메서드 에서 뷰에서이 함수를 호출해야 합니다.


꽤 많이. 당시에는 프로젝트 기간 내에서이를 수행하는 유일한 방법이었습니다. 필요한 경우 편리한 단축키 (:
pospi

23

중앙 집중식으로이 작업을 수행 할 수있었습니다. 결과는 다음과 같습니다.

여기에 이미지 설명 입력

다음이 Activity있으며 사용자 지정 글꼴이 필요한 경우 확장합니다.

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

그러나 지원 패키지의 활동을 사용하는 경우 예 FragmentActivity를 들어 다음을 사용합니다 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"));
}
}

Fragment아직 s 로이 코드를 테스트 하지는 않았지만 잘 작동 할 것입니다.

My FontUtils는 여기에 언급 된 pre-ICS 문제도 해결하는 간단합니다 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
이것은 더 많은 표를 얻을 것입니다. 그것은 작동하며 시위에 대한 스크린 샷이
ericn

10

이봐, 나는 또한 다른 위젯을 위해 내 앱에 2 개의 다른 글꼴이 필요합니다! 이 방법으로 사용합니다.

내 Application 클래스에서 정적 메서드를 만듭니다.

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

문자열 서체는 자산 폴더의 xyz.ttf를 나타냅니다. (나는 상수 클래스를 만들었습니다) 이제 앱의 모든 곳에서 이것을 사용할 수 있습니다.

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

유일한 문제는 글꼴을 사용하려는 모든 위젯에 대해 이것이 필요하다는 것입니다! 하지만 이것이 최선의 방법이라고 생각합니다.


4

사용 pospi의 제안과 같은 '태그'속성 작업 리처드 했다, 그 부하 내 사용자 지정 글꼴을 사용자 정의 클래스를 생성하고 자신의 태그에 따라 뷰에 적용합니다.

따라서 기본적으로 android : fontFamily 속성에서 TypeFace를 설정하는 대신 android : tag attritube를 사용하고 정의 된 열거 형 중 하나로 설정합니다.

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

당신의 활동 또는 조각에서 당신은

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

4

나는 Lisa Wray의 블로그 에서 좋은 해결책을 찾았습니다 . 새로운 데이터 바인딩을 사용하면 XML 파일에 글꼴을 설정할 수 있습니다.

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

XML에서 :

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

데이터 바인딩을 사용하여 예제를 제안 할 수 있습니까? 그것은 많이 감사 할 것입니다.
Sri Krishna

3

더 편리한 방법이있을 수 있다고 생각합니다. 다음 클래스는 응용 프로그램의 모든 구성 요소에 대해 사용자 정의 유형면을 설정합니다 (클래스 별 설정 포함).

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

LayoutInflater의 기본 구현은 xml에서 글꼴 서체 지정을 지원하지 않습니다. 그러나 xml 태그에서 이러한 속성을 구문 분석하는 LayoutInflater에 대한 사용자 정의 팩토리를 제공하여 xml에서 수행되는 것을 보았습니다.

기본 구조는 이와 같습니다.

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

이 기사 에서는 이러한 메커니즘에 대한 자세한 설명과 작성자가 이러한 방식으로 서체에 대한 xml 레이아웃 지원을 제공하는 방법을 제공합니다. 작성자의 구현 코드는 여기 에서 찾을 수 있습니다 .


1

사용자 지정 글꼴을 일반 ProgressDialog / AlertDialog로 설정 :

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

예, 기본 서체를 재정 의하여 가능합니다. 솔루션을 따랐고 한 번의 변경으로 모든 TextView 및 ActionBar 텍스트에 대한 매력처럼 작동했습니다.

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>

위 링크에서 언급 한 themes.xml 대신 기본 앱 테마 태그의 styles.xml에서 재정의 할 기본 글꼴을 언급했습니다. 덮어 쓸 수있는 기본 서체는 serif, sans, monospace 및 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);
        }
    }
}

처음에는 덮어 쓸 서체가 고정되어 있고 정의 된 값 집합이라는 것을 몰랐지만 결국 Android가 글꼴과 서체 및 기본값을 처리하는 방식을 이해하는 데 도움이되었습니다.


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

2
불행히도 이것은 더 이상 작동하지 않습니다 : java.lang.IllegalAccessException : 필드는 java.lang.reflect.Field.set (Field.java : 556)
BoD 2012 년

0

나는 pospi의 제안을 좋아한다. XML에서 할 수없는 추가 스타일을 지정하기 위해 뷰의 'tag'속성 (XML- 'android : tag'에서 지정할 수 있음)을 사용하지 않는 이유는 무엇입니까? 저는 JSON을 좋아하므로 JSON 문자열을 사용하여 키 / 값 집합을 지정합니다. 이 클래스는 작업을 수행 Style.setContentView(this, [resource id])합니다. 활동을 호출 하기 만하면 됩니다.

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

분명히 당신은 JSON을 가치있게 사용하기 위해 서체 이상의 것을 처리하고 싶을 것입니다.

'tag'속성의 장점은 테마로 사용하는 기본 스타일에 설정하여 모든보기에 자동으로 적용 할 수 있다는 것입니다. 편집 : 이렇게하면 Android 4.0.3에서 인플레이션 중에 충돌이 발생합니다. 여전히 스타일을 사용하고 개별적으로 텍스트보기에 적용 할 수 있습니다.

코드에서 볼 수있는 한 가지는-일부 뷰에는 명시 적으로 설정되지 않은 태그가 있습니다. 이상하게도 그것은 'Αποκοπή'문자열입니다. 구글 번역에 따르면 그리스어로 '잘라 내기'입니다! 도대체 ...?


0

@majinboo의 대답은 성능 및 메모리 관리를 위해 수정되었습니다. 하나 이상의 글꼴이 필요한 관련 활동은 생성자 자체를 매개 변수로 제공하여이 Font 클래스를 사용할 수 있습니다.

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

수정 된 글꼴 클래스는 다음과 같습니다.

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

Xamarin.Android 작업 :

수업:

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

응용 프로그램 구현 :

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

스타일:

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

0

Android O에서 사용자 지정 글꼴 사용이 쉬워 진 것 같습니다. 기본적으로 xml을 사용하여이 작업을 수행 할 수 있습니다. 참조를 위해 Android 공식 문서에 대한 링크를 첨부했으며이 솔루션이 여전히 필요한 사람들에게 도움이되기를 바랍니다. Android에서 사용자 정의 글꼴 작업


0

Android 8.0 (API 레벨 26)부터는 XML에서 맞춤 글꼴을 사용할 수 있다는 사실을 아는 것이 유용 할 수 있습니다 .

간단히 말해서 다음과 같은 방법으로 수행 할 수 있습니다.

  1. 폴더에 글꼴을 넣으십시오 res/font.

  2. 위젯의 속성에서 사용하십시오.

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

또는 넣어 res/values/styles.xml

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

스타일로 사용하세요

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

0

xml 파일에서 직접 "fontPath"속성을 사용하십시오.

style.xml에서 사용

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

직접 레이아웃 파일에 사용

fontPath = "fonts / ProximaNovaBold.ttf"

(참고 : 접두사에 app / android 속성을 사용할 필요가 없습니다)


-6

물론 가능합니다. 그것을하는 많은 방법. 가장 빠른 방법은 try-catch 메소드로 조건을 생성하는 것입니다. 특정 글꼴 스타일 조건을 시도하고 오류를 포착하고 다른 글꼴 스타일을 정의합니다.


7
답을 증명하는 데모를 제공 할 수 있습니까?
Mark
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.