如何防止系统字体大小更改效果到Android应用程序?

时间:2014-02-04 07:52:43

标签: android android-fonts

我最近完成了我的Android应用程序的开发。我对所有textSize使用了sp(Scaled pixels)。问题是当我调整系统字体大小时,我的应用程序的字体大小正在改变。我可以使用dp(设备无关像素),但维护我的应用程序需要很长时间。

我引用了this的文字大小。

有没有办法阻止系统字体大小更改效果到我的应用程序?

8 个答案:

答案 0 :(得分:39)

如果您要求文字保持相同的尺寸,则必须使用dp

引用documentation

  

sp是相同的基本单位,但是按用户的首选文字大小(它是与比例无关的像素)进行缩放,因此在定义文字时应使用此测量单位大小(但绝不是布局大小)。

强调我的。

因此,您会看到使用sp作为文字大小单位的预期行为。

我不明白你使用dp花费太长时间来维护你的应用程序是什么意思 - 据我所知,这将是完全相同的努力量? (也许更少,但它可能会使眼睛不好的用户不太可用)

答案 1 :(得分:39)

我最近遇到了这个问题。我们的用户界面在屏幕尺寸有限的手机上无法很好地扩展,并且在用户将其可访问性选项设置为“巨大”的情况下更改整个用户界面似乎很愚蠢。

我发现StackOverflow上的这个question最有帮助。

我所做的是将下面的代码放在我的BaseActivity(我的所有活动扩展自的Activity类)中

public void adjustFontScale(Configuration configuration) {
    if (configuration.fontScale > 1.30) {
        LogUtil.log(LogUtil.WARN, TAG, "fontScale=" + configuration.fontScale); //Custom Log class, you can use Log.w
        LogUtil.log(LogUtil.WARN, TAG, "font too big. scale down..."); //Custom Log class, you can use Log.w
        configuration.fontScale = (float) 1.30;
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.getDefaultDisplay().getMetrics(metrics);
        metrics.scaledDensity = configuration.fontScale * metrics.density;
        getBaseContext().getResources().updateConfiguration(configuration, metrics);
    }
}

super.onCreate()之后立即调用它

adjustFontScale(getResources().getConfiguration());

此代码的作用是识别用户是否将“辅助功能设置”中的字体比例设置为大于1.30f(注释5上的1.30f为“大”,但可能会因设备而异。)。如果用户将其字体设置得太大(“超大”,“巨大”......),我们只将应用程序缩放为“大”。

这允许您的应用扩展到用户的偏好(在一定程度上),而不会扭曲您的UI。希望这会有助于其他人。祝你好运!

其他提示

如果您希望某些布局可以使用您的字体进行缩放(比如... RelativeLayout,您将其用作字体的背景),则可以使用sp而不是经典dp设置其宽度/高度。当用户更改其字体大小时,布局将根据应用程序中的字体进行相应更改。不错的小技巧。

答案 2 :(得分:3)

我们就是这样做的。 在应用类中,覆盖 onConfigurationChanged() ,就像这样。 如果您想要针对不同活动采取不同的行为 - 在活动中覆盖 onConfigurationChanged()

不要忘记添加清单标记 android:configChanges =“fontScale”,因为您自己进行了此配置更改。

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // In some cases modifying newConfig leads to unexpected behavior,
    // so it's better to edit new instance.
    Configuration configuration = new Configuration(newConfig);
    SystemUtils.adjustFontScale(getApplicationContext(), configuration);
}

在某个帮助类中,我们有 adjustFontScale() 方法。

public static void adjustFontScale(Context context, Configuration configuration) {
    if (configuration.fontScale != 1) {
        configuration.fontScale = 1;
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        wm.getDefaultDisplay().getMetrics(metrics);
        metrics.scaledDensity = configuration.fontScale * metrics.density;
        context.getResources().updateConfiguration(configuration, metrics);
    }
}

警告!这将完全忽略辅助功能字体比例用户设置,并会阻止您的App字体缩放!

答案 3 :(得分:1)

这就是您在2018年的操作方式(Xamarin.Android/C#-其他语言中的相同方法):

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    protected override void OnCreate(Bundle bundle)
    {
...
    }

    protected override void AttachBaseContext(Context @base)
    {
        var configuration = new Configuration(@base.Resources.Configuration);

        configuration.FontScale = 1f;
        var config =  Application.Context.CreateConfigurationContext(configuration);

        base.AttachBaseContext(config);
    }
}

您需要做的就是覆盖 attachBaseContext 活动方法并在那里更新配置。

尽管有许多使用此方法的示例,但不推荐使用

getBaseContext()。getResources()。updateConfiguration()。如果您在IDE警告之外使用此方法,则可能会发现应用程序的某些部分无法缩放。

答案 4 :(得分:0)

还有另一种方法可以防止设置字体大小更改时出现应用布局问题/字体问题。 你可以尝试

// ignore the font scale here
final Configuration newConfiguration = new Configuration(
    newBase.getResources().getConfiguration()
);

newConfiguration.fontScale = 1.0f;
applyOverrideConfiguration(newConfiguration);

其中newBase来自attachBaseContext函数。 您需要在Activity中覆盖此回调。

但是,副作用是,如果你想使用动画(objectanimator / valueanimator),那么它将导致奇怪的行为。

答案 5 :(得分:0)

在Android 8.1(API 27)上,以上答案均不适合我。有效的方法如下:将以下代码添加到您的活动中:

科特琳代码:

override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(newBase)
    val newOverride = Configuration(newBase?.resources?.configuration)
    newOverride.fontScale = 1.0f
    applyOverrideConfiguration(newOverride)
}

Java代码:

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(newBase);
    final Configuration override = new Configuration(newBase.getResources().getConfiguration());
    override.fontScale = 1.0f;
    applyOverrideConfiguration(override);
}

您不需要更改自己的AndroidManifest.xml

答案 6 :(得分:0)

您可以使用基本活动配置强制应用程序的文本大小,使所有活动固有于基本活动。 1.0f将强制将应用字体大小设置为正常大小,而忽略系统设置。

public  void adjustFontScale( Configuration configuration,float scale) {

configuration.fontScale = scale;
DisplayMetrics metrics = getResources().getDisplayMetrics();
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(metrics);
metrics.scaledDensity = configuration.fontScale * metrics.density;
getBaseContext().getResources().updateConfiguration(configuration, metrics);

}

@Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     adjustFontScale( getResources().getConfiguration(),1.0f);
}

答案 7 :(得分:0)

我认为使用dp是最好的方法,但是在某些情况下,您可能希望使用字体样式,但是该样式使用的是sp,则可以将sp转换为{ {1}}的作者:

dp

因此您可以使用样式中的fun TextView.getSizeInSp() = textSize / context.resources.displayMetrics.scaleDensity fun TextView.convertToDpSize() = setTextSize(TypedValue.COMPLEX_UNIT_DIP, getSizeInSp()) 值,而无需使用动态字体大小,也无需对字体大小进行硬编码