How do I prevent Android device Display size scaling in my app?

北慕城南 提交于 2020-05-09 05:18:47

问题


I'm developing an app with React Native for both iOS and Android, and I am trying to prevent device-specific scaling of the display in the app.

For text/font size scaling, putting the following code in the root-level App.js file solves the issue for both iOS and Android:

if (Text.defaultProps == null) {
    Text.defaultProps = {};
}
Text.defaultProps.allowFontScaling = false;

However, Android devices have the following Display size setting that is still being applied:

I've tried (unsuccessfully) to piece together a variety of "solutions" to this issue that I've found in answers to the following questions:

Change the system display size programatically Android N

Disabling an app or activity zoom if Setting -> Display -> Display size changed to Large or small

how to prevent system font-size changing effects to android application?

I've often found references to a BaseActivity class that extends the Activity class. My understanding is that it is inside of that class where I would be writing a method (let's call it adjustDisplayScale) to make changes to the Configuration of the Context that I get from Resources, and that then I would be calling adjustDisplayScale within the onCreate() method after super.onCreate() in the MainApplication.java file.

As of now, in this directory I just have two files - MainApplication.java and MainActivity.java.

I've attempted creating a new Module and associated Package file to implement adjustDisplayScale following these instructions and it did not work: https://facebook.github.io/react-native/docs/text.html

I've attempted placing implementing the functionality of adjustDisplayScale within the onCreate() like this and it did not work:

@Override
public void onCreate() {
    super.onCreate();

    Context context = getApplicationContext();
    Resources res = context.getResources();
    Configuration configuration = res.getConfiguration();

    configuration.fontScale = 1f;
    DisplayMetrics metrics = res.getDisplayMetrics();

    WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    wm.getDefaultDisplay().getMetrics(metrics);
    metrics.scaledDensity = 1f;
    configuration.densityDpi = (int) res.getDisplayMetrics().xdpi;
    context = context.createConfigurationContext(configuration);

    SoLoader.init(this, /* native exopackage */ false);
}

A potentially promising answer included the following:

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

But when I tried to utilize this, I got errors about not recognizing the symbol @base.

Some background... I've done 99% of my work on this project in JavaScript / React Native and I have almost no understanding about things like Resources, Context, Configuration, and DisplayMetrics associated with Android development AND the last time I wrote code in Java was 10 years ago. I've spent a number of agonizing hours trying to figure this out and any help would be greatly appreciated.

ps. I am well-aware that accessibility settings exist for a good reason so please spare me the diatribe I've seen in so many "answers" on why I need to fix my UI to work with accessibility settings rather than disable them.


回答1:


You can try following code (overriding attachBaseContext). This will "disable" the screen zoom in your app. This is the way to re-scale whole screen at once.

@Override
protected void attachBaseContext(final Context baseContext) {

    Context newContext;

    if(Build.VERSION.SDK_INT >= VERSION_CODES.N) {

        DisplayMetrics displayMetrics = baseContext.getResources().getDisplayMetrics();
        Configuration configuration = baseContext.getResources().getConfiguration();

        if (displayMetrics.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE) {
            // Current density is different from Default Density. Override it
            displayMetrics.densityDpi = DisplayMetrics.DENSITY_DEVICE_STABLE;
            configuration.densityDpi = DisplayMetrics.DENSITY_DEVICE_STABLE;
            newContext = baseContext;//baseContext.createConfigurationContext(configuration);
        } else {
            // Same density. Just use same context
            newContext = baseContext;
        }
    } else {
        // Old API. Screen zoom not supported
        newContext = baseContext;
    }
    super.attachBaseContext(newContext);
}

On that code, I check if the current density is different from Device's default density. If they are different, I create a new context using default density (and not the current one). Then, I attach this modified context.

You must do that on every Activity. So, you can create a BaseActivity and add that code there. Then, you just need to update your activities in order to extend BaseActivity

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void attachBaseContext(final Context baseContext) {
        ....
    }
}

Then, in your activities:

public class MainActivity extends BaseActivity {
    // Since I'm extending BaseActivity, I don't need to add the code
    // on attachBaseContext again
    // If you don't want to create a base activity, you must copy/paste that
    // attachBaseContext code into all activities
}

I tested this code with:

Log.v("Test", "Dimension: " + getResources().getDimension(R.dimen.test_dimension));

Different Screen Zoom (using that code):

2019-06-26 16:38:17.193 16312-16312/com.test.testapplication V/Test: Dimension: 105.0
2019-06-26 16:38:35.545 16312-16312/com.test.testapplication V/Test: Dimension: 105.0
2019-06-26 16:38:43.021 16579-16579/com.test.testapplication V/Test: Dimension: 105.0

Different Screen Zoom (without that code):

2019-06-26 16:42:53.807 17090-17090/com.test.testapplication V/Test: Dimension: 135.0
2019-06-26 16:43:19.381 17090-17090/com.test.testapplication V/Test: Dimension: 120.0
2019-06-26 16:44:00.125 17090-17090/com.test.testapplication V/Test: Dimension: 105.0

So, using that code, I can get the same dimension in pixels regardless the zoom level.

Edit



来源:https://stackoverflow.com/questions/56779224/how-do-i-prevent-android-device-display-size-scaling-in-my-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!