【问题标题】:how to prevent system font-size changing effects to android application?如何防止系统字体大小变化对android应用程序的影响?
【发布时间】:2014-02-28 02:05:13
【问题描述】:

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

我从 this 引用了文本大小。

有没有办法防止系统字体大小更改对我的应用程序产生影响?

【问题讨论】:

    标签: android android-fonts


    【解决方案1】:

    如果您要求文本大小保持不变,则必须使用dp

    引用documentation

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

    强调我的。

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

    我不明白您所说的使用 dp 来维护您的应用程序的时间太长是什么意思 - 据我所知,这将是完全相同的工作量吗? (也许更少,尽管它可能会使其对视力不佳的用户不太有用)

    【讨论】:

    • 我同意你的解释。但在 IOS 中,它仅限于系统的特定应用程序,如日历、邮件等。对于Android,没有限制。那么我可以阻止我的应用程序更改系统 font-szie。
    • 您无法阻止用户更改系统字体大小;您只需要使用 dp 并忽略 lint 错误!有一个 blog post on how to disable lint errors 可能有用。
    • 虽然您的使用可能非常具体并且需要恒定的字体大小,但我建议您考虑如何在布局中适应不同的字体大小,而不是完全避免使用它。这将为您的用户带来更好的体验。
    • 如果您有一个正常工作的应用程序,将所有 sp 值切换为 dp 值很容易出错,并且需要更多时间来执行此操作。然后,如果选择切换回来再次支持它,您需要恢复所有这些更改。在父活动中覆盖fontScale 更有意义。与更改资源相比,这需要更少的努力。它的可维护性也更好。下面的答案覆盖Context 是要走的路。
    • 应该有一个简单的设置,开发者可以在android manifest中使用不遵循系统文本和显示大小设置。
    【解决方案2】:

    我最近也遇到了这个问题。我们的 UI 在屏幕尺寸有限的手机上无法很好地扩展,并且如果用户将其辅助功能选项设置为“巨大”似乎很愚蠢,就更改了整个 UI。

    我发现 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 = 1.30f;
            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(1.30f 在 Note 5 上是“大”,但可能因设备而异)。如果用户将他们的字体设置得太大(“Extra Large”、“Huge”...),我们只会将应用程序缩放为“Large”。

    这允许您的应用在不扭曲 UI 的情况下(在一定程度上)根据用户的偏好进行扩展。希望这对其他人有帮助。祝你好运!

    其他提示

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

    【讨论】:

    • 我能问一下为什么您的示例与您链接的问题略有不同,关于这一行:WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);。我是 android 新手,正在尝试选择“最佳”答案。谢谢!
    • @Tallboy 好问题。我已经看到代码以两种方式获取窗口管理器(像我一样使用 getSystemService 调用并像我链接到的示例一样使用 getWindowManager() )。我只是以两种方式测试了我的代码,它们都运行良好。我相信我在某处读到 getWindowManager 返回一个只读的窗口管理器对象,这可能是这两种方法之间的关键区别,但对于这个例子来说,这并不重要。
    • 这不适用于牛轧糖。到棉花糖它工作正常。
    • 我已经浏览了整个网络好几天了,这是唯一适用于电容器的解决方案!谢谢!
    • updateConfiguration 方法已弃用!
    【解决方案3】:

    我们就是这样做的。 在 Application 类中重写 onConfigurationChanged() 像这样。 如果您希望不同活动的不同行为 - 覆盖 Activity 中的 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);
        }
    }
    

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

    【讨论】:

    • 它不起作用。 onConfigurationChanged 永远不会被触发。
    • @zed 您需要在清单中的应用程序或活动上设置 android:configChanges="orientation|screenSize"
    • 此解决方案仅适用于平板电脑而非智能设备。
    • 它适用于nexus 5-Android 6,我会在其他设备上检查。
    • 查看updateConfiguration 的一些源代码实现(在5.1 和10 中),不需要手动更新scaledDensity。他们为你做。
    【解决方案4】:

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

    // 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】:

      这就是您在 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 警告之外使用此方法,您可能会发现应用的某些部分未缩放。

      【讨论】:

        【解决方案6】:

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

        Kotlin 代码:

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

        Java 代码:

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

        您无需更改您的AndroidManifest.xml

        【讨论】:

        • 这是Android API > N的解决方案,未在N以下的设备上测试。
        • java.lang.IllegalStateException: getResources() 或 getAssets() 已被调用
        • @Dr.DS 是 API > N 还是 API >= N ?对我来说,它不适用于 N。只是想确认一下
        • @Dr.DS 我已经在 N 台以下的设备上测试过,效果很好
        • 确认它适用于 Android 12。但super.attachBaseContext(newBase); 需要移动到 attachBaseContext() 的最后一行
        【解决方案7】:

        您可以使用基本活动配置强制应用的文本大小,使所有活动成为固有基本活动。 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);
        }
        

        【讨论】:

          【解决方案8】:

          我认为使用dp 是最好的方法,但在某些情况下您可能想要使用字体样式。但是,样式使用sp,您可以通过以下方式将sp转换为dp

          fun TextView.getSizeInSp() = textSize / context.resources.displayMetrics.scaleDensity
          
          fun TextView.convertToDpSize() = setTextSize(TypedValue.COMPLEX_UNIT_DIP, getSizeInSp())
          

          因此,您可以使用样式中的sp 值,无需动态字体大小,也无需对字体大小进行硬编码

          【讨论】:

            【解决方案9】:

            我遇到了同样的问题,并通过将 .XML 文件中的 sp 更改为 dp 来修复它。但是,我还需要修复 WebViews 的文本大小。

            通常,要调整WebView 的文本大小,使用setDefaultFontSize() 函数。但是,它的默认值单位是sp

            在我的项目中,我使用setTextZoom(100) 来修复 WebView 的文本和图标大小。*(stackoverflow 中还有其他方法,但几乎所有方法都不推荐使用)*

            WebSettings settings = mWebView.getSettings();
            settings.setTextZoom(100);
            

            For further details about setTextZoom()

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-09-28
              • 1970-01-01
              • 2013-08-02
              • 1970-01-01
              • 2019-03-09
              • 2020-07-19
              相关资源
              最近更新 更多