Basic Screen Concepts

Hardware concept

Physical properties
The name of the define unit
size The length of the diagonal Inch is about 2.54 centimeters
The resolution of the The number of pixels in the screen direction A pixel,
Pixel density Number of pixels per inch ppi,point per inch

In daily life, we usually hear or use the screen size (XX mobile phone 6.5-inch blabla), which refers to the diagonal length of the mobile phone screen

The second is resolution, common are 1080P (1920×1080), 2K (2560×1440), 4K (4096 x 2160), where the number refers to the number of pixels in two directions of the screen (why not say vertical and horizontal two directions? Because you can see it portrait, you can see it landscape 🙂

Software concept

Software concept
The name of the define
px pixel
dp Dip, pixel density
sp Font unit, same as DP, but can be changed according to system Settings
dpi The number of pixels per unit inch, also called screen density
density Density qualifier that represents the density level of the current screen

The relationship is as follows:

For example: the phone has a 1920×1080 resolution and a 5-inch screen

(1920^2 + 1080^2)^ 1/2) / 5 = 440

So dpi is 440

Other relationships are as follows:

Why does the screen not fit

Android screen coding, control width and height properties are usually used in dp units

Assuming that our UI design is designed with a screen width of 360DP, the screen width of dPI440 is actually 1080/(440/160)=392.7 DP, which means that the screen is wider than the design. In this case, even using DP will not display the same effect on different devices. At the same time, the screen width of some devices is less than 360DP, which will lead to the actual display of incomplete development based on 360DP width.

Moreover, the above relationship between screen size, resolution and pixel density is not realized by many devices according to this rule, so the VALUE of DPI is very disorderly and there is no rule to follow, resulting in unsatisfactory adaptation effect of DP.

However, screen adaptation is generally unified with the width or height of different models, because now mobile phones are uneven in the screen height, so the common screen adaptation scheme is for the width of adaptation.

Toutiao’s screen adaptation scheme

Toutiao technology team provides a relatively complete solution:

Because dp in Android turns DP to PX before rendering,

So start with the conversion formula dp and PX:

Density is derived from dPI

Px is the final display, dp is the unit we layout according to the design drawing, so we take Density and DPI to start

We can learn by reading the source code, and density were members of the DisplayMetrics variables, and DisplayMetrics instance through Resources. GetDisplayMetrics can get, Resouces are obtained from the Activity or Application Context.

Let’s get familiar with a few variables related to DisplayMetrics neutralization and adaptation:

  • DisplayMetrics.densityThis is density above
  • DisplayMetrics.densityDpiThat’s dPI
  • DisplayMetrics.scaledDensityThe size factor of a typeface is normally the same as density, but adjusting the system font size will change this value

hands-on

Get the current DisplayMetrics
DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
Copy the code
Compute the target Denisty
// Density = px/DP
final float targetDensity = (float) (appDisplayMetrics.widthPixels / 360.0);
// Calculate the font size of the corresponding scale size. Generally, scaledDensity is the same as density to prevent users from adjusting the font size in system Settings
final float targetScaledDensity = targetDensity * (appDisplayMetrics.scaledDensity / appDisplayMetrics.density);
//dpi = density * 160
final int targetDensityDpi = (int)(targetDensity * 160);
Copy the code
Add Settings to make all
    private static void setCustomDensity(Application application, Activity activity) {
        final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
    
        // If DP = 360, the Density can be calculated
        final float targetDensity = (float) (appDisplayMetrics.widthPixels / 360.0);
        final float targetScaledDensity = targetDensity * (appDisplayMetrics.scaledDensity / appDisplayMetrics.density);
        final int targetDensityDpi = (int)(targetDensity * 160);

        // Set the application Density
        appDisplayMetrics.density = targetDensity;
        appDisplayMetrics.scaledDensity = targetScaledDensity;
        appDisplayMetrics.densityDpi = targetDensityDpi;

        // Set the Density of the activity
        final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
        activityDisplayMetrics.density = targetDensity;
        activityDisplayMetrics.scaledDensity = targetScaledDensity;
        activityDisplayMetrics.densityDpi = targetDensityDpi;
    }
Copy the code

A common application scenario is to call setCustomDensity() in the onCreate method of BaseActivity to achieve global adaptation

At present, it seems that there is no problem, but there is another scenario: if the user modifies the font in the system setting example during the run and then returns the APP, the APP will not be aware of the font change, so the font does not change, so we should also monitor the font change and adjust ScaledDensity at the same time

Evolved into a polar body

    private static float aNoncompatDensity;
    private static float aNoncompatScaledDensity;

    private static void setCustomDensity(Application application, Activity activity) {

        final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
        if (aNoncompatDensity == 0) {
            aNoncompatDensity = appDisplayMetrics.density;
            aNoncompatScaledDensity = appDisplayMetrics.scaledDensity;
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(@NonNull Configuration newConfig) {
                    if (newConfig.fontScale > 0) { aNoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity; }}@Override
                public void onLowMemory(a) {}}); }final float targetDensity = (float) (appDisplayMetrics.widthPixels / 360.0);
        final float targetScaledDensity = targetDensity * (aNoncompatScaledDensity/ aNoncompatDensity);
        final int targetDensityDpi = (int)(targetDensity * 160);

        // Set the application Density
        appDisplayMetrics.density = targetDensity;
        appDisplayMetrics.scaledDensity = targetScaledDensity;
        appDisplayMetrics.densityDpi = targetDensityDpi;

        // Set the Density of the activity
        final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
        activityDisplayMetrics.density = targetDensity;
        activityDisplayMetrics.scaledDensity = targetScaledDensity;
        activityDisplayMetrics.densityDpi = targetDensityDpi;
    }

Copy the code

Poor me, I do not have many devices to test the adaptation effect, so I quote the test screenshots of today’s technical team:

This adaptation method is very low invasion, the effect is stable, just dozens of lines of code can complete the adaptation problem, it is not too simple

The above article briefly explains the principle of adaptation, there are many open source projects based on this principle to adopt a more brief implementation, I will not expand on the next, you can explore what more convenient implementation scheme

Dig a hole and talk about several other screen adaptations and how they compare

Reference: Toutiao: A Very low-cost Way to adapt Android screens