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