[java] 전체 응용 프로그램에 대해 사용자 정의 글꼴을 설정할 수 있습니까?

전체 응용 프로그램에 특정 글꼴을 사용해야합니다. 동일한 .ttf 파일이 있습니다. 응용 프로그램 시작시이 글꼴을 기본 글꼴로 설정 한 다음 응용 프로그램의 다른 곳에서 사용할 수 있습니까? 설정하면 레이아웃 XML에서 어떻게 사용합니까?



답변

그렇습니다. 이것은 작동합니다 ( 이 답변을 기반으로 ).

(참고 : 이것은 사용자 정의 글꼴에 대한 지원이 없기 때문에 해결 방법 이므로이 상황을 변경하려면 여기 에서 Android 문제를 투표 하십시오 .) 참고 : 해당 문제에 대해 “나도”의견을 남기지 마십시오 . 별표를 표시 한 모든 사람은 이메일을받을 때 이메일을받습니다. 그러니 그냥 “별”입니다.

import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.Typeface;

public final class FontsOverride {

    public static void setDefaultFont(Context context,
            String staticTypefaceFieldName, String fontAssetName) {
        final Typeface regular = Typeface.createFromAsset(context.getAssets(),
                fontAssetName);
        replaceFont(staticTypefaceFieldName, regular);
    }

    protected static void replaceFont(String staticTypefaceFieldName,
            final Typeface newTypeface) {
        try {
            final Field staticField = Typeface.class
                    .getDeclaredField(staticTypefaceFieldName);
            staticField.setAccessible(true);
            staticField.set(null, newTypeface);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

그런 다음 몇 가지 기본 글꼴 (예 : 응용 프로그램 클래스) 을 오버로드해야합니다 .

public final class Application extends android.app.Application {
    @Override
    public void onCreate() {
        super.onCreate();
        FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");
        FontsOverride.setDefaultFont(this, "MONOSPACE", "MyFontAsset2.ttf");
        FontsOverride.setDefaultFont(this, "SERIF", "MyFontAsset3.ttf");
        FontsOverride.setDefaultFont(this, "SANS_SERIF", "MyFontAsset4.ttf");
    }
}

또는 동일한 글꼴 파일을 사용하는 경우이를 개선하여 한 번만로드 할 수 있습니다.

그러나 나는 하나를 무시 "MONOSPACE"하고 글꼴 서체 응용 프로그램을 강제로 적용하는 스타일을 설정하는 경향이 있습니다.

<resources>
    <style name="AppBaseTheme" parent="android:Theme.Light">
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <item name="android:typeface">monospace</item>
    </style>
</resources>

API 21 안드로이드 5.0

작동하지 않는다는 의견의 보고서를 조사했으며 테마와 호환되지 않는 것으로 보입니다. android:Theme.Material.Light .

해당 테마가 중요하지 않은 경우 다음과 같은 이전 테마를 사용하십시오.

<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
    <item name="android:typeface">monospace</item>
</style>


답변

안드로이드에는 커스텀 폰트를위한 훌륭한 라이브러리가 있습니다 : Calligraphy

다음은 사용 방법에 대한 샘플입니다.

Gradle 에서이 줄을 앱의 build.gradle 파일에 넣어야합니다.

dependencies {
    compile 'uk.co.chrisjenx:calligraphy:2.2.0'
}

그런 다음 Application이 코드 를 확장 하고 작성 하는 클래스를 만듭니다 .

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
                        .setDefaultFontPath("your font path")
                        .setFontAttrId(R.attr.fontPath)
                        .build()
        );
    }
} 

그리고 활동 클래스 에서이 메소드를 onCreate 전에 두십시오.

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}

매니페스트 파일의 마지막 모습은 다음과 같습니다.

<application
   .
   .
   .
   android:name=".App">

전체 활동을 글꼴로 변경합니다! 간단하고 깨끗합니다!


답변

전체 응용 프로그램에서는 작동하지 않지만 활동에서는 작동하고 다른 활동에서는 재사용 할 수 있습니다. 다른 뷰를 지원하기 위해 @ FR073N 덕분에 코드를 업데이트했습니다. 의 문제에 대해 잘 모르겠습니다 Buttons.RadioGroups 등 해당 클래스의 모든 확장 때문에TextView 그들이 잘 작동해야하므로. 리플렉션 사용에 대한 부울 조건을 추가했습니다. 왜냐하면 매우 해킹처럼 보이고 성능을 현저하게 저하시킬 수 있기 때문입니다.

참고 : 지적한 것처럼 동적 콘텐츠에는 작동하지 않습니다! 이를 위해 onCreateViewor getView메소드를 사용하여이 메소드를 호출 할 수 있지만 추가 노력이 필요합니다.

/**
 * Recursively sets a {@link Typeface} to all
 * {@link TextView}s in a {@link ViewGroup}.
 */
public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect)
{
    if (mContainer == null || mFont == null) return;

    final int mCount = mContainer.getChildCount();

    // Loop through all of the children.
    for (int i = 0; i < mCount; ++i)
    {
        final View mChild = mContainer.getChildAt(i);
        if (mChild instanceof TextView)
        {
            // Set the font if it is a TextView.
            ((TextView) mChild).setTypeface(mFont);
        }
        else if (mChild instanceof ViewGroup)
        {
            // Recursively attempt another ViewGroup.
            setAppFont((ViewGroup) mChild, mFont);
        }
        else if (reflect)
        {
            try {
                Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);
                mSetTypeface.invoke(mChild, mFont);
            } catch (Exception e) { /* Do something... */ }
        }
    }
}

그런 다음 사용하려면 다음과 같이하십시오.

final Typeface mFont = Typeface.createFromAsset(getAssets(),
"fonts/MyFont.ttf");
final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
HomeActivity.setAppFont(mContainer, mFont);

희망이 도움이됩니다.


답변

요약해서 말하자면:

옵션 # 1 : 리플렉션을 사용하여 글꼴 적용 ( Weston & Roger Huang 의 답변 결합) :

import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.Typeface;

public final class FontsOverride {

    public static void setDefaultFont(Context context,
            String staticTypefaceFieldName, String fontAssetName) {
        final Typeface regular = Typeface.createFromAsset(context.getAssets(),
                fontAssetName);
        replaceFont(staticTypefaceFieldName, regular);
    }

    protected static void replaceFont(String staticTypefaceFieldName,final Typeface newTypeface) {
        if (isVersionGreaterOrEqualToLollipop()) {
            Map<String, Typeface> newMap = new HashMap<String, Typeface>();
            newMap.put("sans-serif", newTypeface);
            try {
                final Field staticField = Typeface.class.getDeclaredField("sSystemFontMap");
                staticField.setAccessible(true);
                staticField.set(null, newMap);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else {
            try {
                final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName);
                staticField.setAccessible(true);
                staticField.set(null, newTypeface);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

} 

응용 프로그램 클래스의 사용법 :

public final class Application extends android.app.Application {
    @Override
    public void onCreate() {
        super.onCreate();
        FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");
        FontsOverride.setDefaultFont(this, "MONOSPACE", "MyFontAsset2.ttf");
        FontsOverride.setDefaultFont(this, "SERIF", "MyFontAsset3.ttf");
        FontsOverride.setDefaultFont(this, "SANS_SERIF", "MyFontAsset4.ttf");
    }
} 

글꼴 서체 응용 프로그램을 광범위하게 적용하는 스타일을 설정하십시오 ( lovefish 기반 ).

롤리팝 전 :

<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:typeface">monospace</item>
   </style>
</resources>

롤리팝 (API 21) :

<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:textAppearance">@style/CustomTextAppearance</item>
   </style>

   <style name="CustomTextAppearance">
       <item name="android:typeface">monospace</item>
   </style>
</resources>

Option2 : 폰트를 커스터마이즈해야하는 각각의 모든 뷰를 서브 클래 합니다. ListView, EditTextView, Button 등 ( Palani 의 답변) :

public class CustomFontView extends TextView {

public CustomFontView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

public CustomFontView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public CustomFontView(Context context) {
    super(context);
    init();
}

private void init() {
    if (!isInEditMode()) {
        Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
        setTypeface(tf);
    }
} 

옵션 3 : 현재 화면의 뷰 계층을 통과하는 뷰 크롤러를 구현합니다.

변형 # 1 ( Tom 의 답변) :

public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect)
{
    if (mContainer == null || mFont == null) return;

    final int mCount = mContainer.getChildCount();

    // Loop through all of the children. 
    for (int i = 0; i < mCount; ++i)
    {
        final View mChild = mContainer.getChildAt(i);
        if (mChild instanceof TextView)
        {
            // Set the font if it is a TextView. 
            ((TextView) mChild).setTypeface(mFont);
        }
        else if (mChild instanceof ViewGroup)
        {
            // Recursively attempt another ViewGroup. 
            setAppFont((ViewGroup) mChild, mFont);
        }
        else if (reflect)
        {
            try {
                Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);
                mSetTypeface.invoke(mChild, mFont);
            } catch (Exception e) { /* Do something... */ }
        }
    }
} 

사용법 :

final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
HomeActivity.setAppFont(mContainer, Typeface.createFromAsset(getAssets(),
"fonts/MyFont.ttf"));

변형 # 2 : https://coderwall.com/p/qxxmaa/android-use-a-custom-font-everywhere .

옵션 # 4 : Calligraphy 라는 타사 라이브러리를 사용하십시오 .

개인적으로, 옵션 # 4는 많은 두통을 덜기 때문에 권장합니다.


답변

웨스턴 을 개선하고 싶습니다API 21 Android 5.0에 대한 의 답변 .

원인

API 21에서 대부분의 텍스트 스타일에는 다음과 같은 fontFamily 설정이 포함됩니다.

<style name="TextAppearance.Material">
     <item name="fontFamily">@string/font_family_body_1_material</item>
</style>

기본 Roboto Regular 글꼴을 적용합니다.

<string name="font_family_body_1_material">sans-serif</string>

android : fontFamily가 android : typeface 속성 ( reference 보다 우선 순위가 높기 때문에 원래의 대답은 고정 폭 글꼴을 적용하지 못합니다. ) . 내부에 android : fontFamily 설정이 없으므로 Theme.Holo. *를 사용하는 것이 올바른 해결 방법입니다.

해결책

Android 5.0은 시스템 서체를 정적 변수 Typeface.sSystemFontMap ( reference ) 에 넣었으므로 동일한 반사 기법을 사용하여 대체 할 수 있습니다.

protected static void replaceFont(String staticTypefaceFieldName,
        final Typeface newTypeface) {
    if (isVersionGreaterOrEqualToLollipop()) {
        Map<String, Typeface> newMap = new HashMap<String, Typeface>();
        newMap.put("sans-serif", newTypeface);
        try {
            final Field staticField = Typeface.class
                    .getDeclaredField("sSystemFontMap");
            staticField.setAccessible(true);
            staticField.set(null, newMap);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    } else {
        try {
            final Field staticField = Typeface.class
                    .getDeclaredField(staticTypefaceFieldName);
            staticField.setAccessible(true);
            staticField.set(null, newTypeface);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}


답변

그것의 아주 간단한 … 1. 다운로드 및 자산에 ur 사용자 정의 글꼴을 넣습니다. 다음 텍스트 뷰에 대해 별도의 클래스를 하나 작성하십시오 : 여기에 나는 futura 글꼴을 사용했습니다

public class CusFntTextView extends TextView {

public CusFntTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

public CusFntTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public CusFntTextView(Context context) {
    super(context);
    init();
}

private void init() {
    if (!isInEditMode()) {
        Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
        setTypeface(tf);
    }
}

}

xml에서 다음을 수행하십시오.

 <com.packagename.CusFntTextView
        android:id="@+id/tvtitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hi Android"
        android:textAppearance="?android:attr/textAppearanceLarge"
      />


답변

TextView 및 기타 컨트롤을 확장하는 것이 좋습니다. 그러나 구문에서 글꼴을 설정하는 것이 좋습니다.

public FontTextView(Context context) {
    super(context);
    init();
}

public FontTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public FontTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

protected void init() {
    setTypeface(Typeface.createFromAsset(getContext().getAssets(), AppConst.FONT));
}