Preface:

Android Skill Tree series:

Android Basics

Android Skill Tree – Animation summary

Android Skill Tree – View summary

Android Skill Tree – Activity summary

Android Skill Tree – View event system summary

Android Skill Tree – Summary of Android storage paths and I/O operations

Android Skill Tree – Multi-process related summary

Android skill Tree – Drawable summary

Android Skill Tree – Screen Adaptation summary

Basic knowledge of data structures

Android Skill Tree – Array, linked list, hash table basic summary

Android Skill Tree — Basic Knowledge of The Tree

Basic knowledge of algorithms

Android Skill Tree – Sorting algorithm basics summary

Rx series related

Android Skill Tree – RxPermission analysis

Android Skill Tree — Rxjava Unsubscribe Summary (1): Native method

Android Skill Tree — Rxjava Unsubscribe Summary (2):RxLifeCycle

In terms of screen adaptation, almost every once in a while you see someone coming out with a XXX solution, a super simple adaptation and so on. So I put my current understanding of the commonly used adaptation scheme to make a summary, and a brief talk about the principle, so that we also preliminary understanding of the implementation of each scheme. (In fact, a lot of people are to see others write adaptation scheme, although may actually be in use, but never to understand the principle of the scheme, and encountered some simple pit, because I do not know the principle, also can not solve their own.)

Common adaptation schemes:

  1. Generate the resolution VALUES folder
  2. Generate the values-sw folder
  3. Google Percentage layout library
  4. AutoLayout
  5. Dynamic change density

1. Basic knowledge

In fact, I didn’t want to write this, because basically everyone knows dp, DPI, PX, Inch,density, etc., but some adaptions in the following will involve these principles. In addition, sometimes when interviewing people, they feel that they know this knowledge point, but they don’t really understand it, so I would like to mention it again. And I’m going to give you some examples that are easy to understand. (PS: Of course, if you don’t want to see it, you can skip it.)

So let’s just put a brain map here to show you the basics:

1.1 px.

We can see that the current mobile phone resolution in the market as of 2018-05 is as follows:

As an added bonus, endings like 1080 x 1812,720 x 1184, which look strange, are not at zero resolution, mostly because of the virtual keys, which take up some of the height.

Take 1080 X 1920, which stands for pixels on a phone,

So if we write a Button with a height of 10px and a width of 10px, that means there are 10 points on the screen that are both high and wide.

1.2 inch (screen size)

Physical screen size, we often hear people say I bought the iPhone 8 Plus, size 5.5 screen, iPhone 8 size 4.7 screen. In fact, they all carry the unit of inch, 1 is 2.54 cm.

So the screen size is the actual physical size measured diagonally on the screen. For simplicity, Android groups all actual screen sizes into four common sizes: small, normal, large, and extra large.

1.3 dpi

The number of pixels in the physical area of the screen; Usually called dPI (Dots Per Inch). So if you look at the title, it’s more like he’s trying to figure out a density. Now that we know the diagonal size of the phone’s screen, all we need to know is the number of pixels on the diagonal of the phone, divided by the number of pixels per inch.

So we just use the Pythagorean theorem to get the pixels on the diagonal and divide by the screen size.

For simplicity, Android groups all screen densities into six common densities: low, medium, high, ultra high, ultra high, and Ultra Ultra High.

There are six general densities:

  • Ldpi (low) to 120dpi
  • Mdpi (middle) to 160dpi
  • Hdpi (high) to 240dpi
  • Xhdpi (high) to 320dpi
  • Xxhdpi (super high) to 480dpi
  • Xxxhdpi (super super Super High) to 640Dpi

1.4 dp and density

In fact, DP is originally called DIP (Density Independent Pixels). Sometimes in an interview, an interviewer will mistake DIP for DPI, so if you ask him to say DP and DIP, he will say DIP as DPI.

For example: To draw a Button with the height and width of a normal screen, suppose we have two screens, one is 100 X 100, one is 200 X 200, then on the first screen we should write Button:

<Button 
     layout_height = "50px"
     layout_width = "50px"/>
Copy the code

The Button for the second screen should be:

<Button 
     layout_height = "100px"
     layout_width = "100px"/>
Copy the code

If I had a third screen, 300 X 300, I would write a Button’s width and height. So we could use one unit instead, but the units can be different in different screen environments. For example, we refer to this unit as “haha.”

For example, we now write:

<Button 
     layout_height = "50haha"
     layout_width = "50haha"/>
Copy the code

At 100 x 100, 50haha = 50px, at 200 x 200 screen, 50haha = 100px, at 300 x 300 screen, 50haha = 150px.

If you say I owe you 50 money, it means you owe someone 50 yuan. If you say you owe someone 50 dollars, it means you owe more than 300 yuan. (Don’t take this example seriously, I’m just saying it)

Therefore, DP is similar to the haha unit defined above.

For example, 50dp = 50px, 1dp = 1px, 50DP = 100px, 1dp = 2px, so we can see the multiples of 1 and 2, respectively. We use density to represent the multiples. Dp * 1 = 50px, 50dp * 2 = 100px

(It’s like I say I owe you 50 money. In China, the density is 1, which means I owe you 50 yuan. In the US, it means I owe you over 300 yuan.)

So how does density come from? Remember we talked about dPI, the density of the screen, and we use this density for comparison. For example, if we use 160dpi as the standard and the other phone is 320dpi, the density will be (320/160 = 2). Dp * density = px = dp * (dpi / 160) = px

The mdPI is based on the screen configuration (scale=1) of the first Android device, the T-Mobile G1.

1.5 Summary of basic knowledge

So if we now know the resolution of the phone, the screen size of the phone also know. Then dPI / 160 is the density of the current phone. Then we know how much PX I wrote 1DP on this phone.

Specific Android phone size four categories and six DPI categories:

How to obtain the DPI, density, resolution and so on of one of our mobile phones?

DisplayMetrics mDisplayMetrics = getResources().getDisplayMetrics(); . / / lateral resolution int width = mDisplayMetrics widthPixels; . / / vertical resolution int height = mDisplayMetrics heightPixels; / / density valuesfloatdensity = mDisplayMetrics.density; // Dpi = density * 160float dpi = density * 160;
Copy the code

Some people might say, well, don’t we have a perfect compatibility with dp? As we mentioned above, for 100 X 100, 200X200, 300 X 300 screens, we just write 50haha, which stands for 50,100,150, respectively. They take up half of each screen. That’s true in theory, but we just mentioned that our density is equal to (DPI / 160), and DPI is determined by both resolution and screen size. Android phones are too fragmented, so many phones have the same DPI despite different resolutions and screen sizes. Therefore, the final density is also the same, resulting in incomplete adaptation. If we add a 400X400 device and the density is the same as 300X300 because the screen size is also much larger, then we write 50haha, which stands for 150px, obviously 400X400 is not half. Even if the 400X400 setting has a very large screen size, the density may be the same as the 100X100 setting, and the 50haha May be only 50px, making the display gap even larger. (In fact, the main reason is that DPI is not determined by the resolution alone, but also by the screen size, so the two variables work simultaneously, resulting in the same density of phones with different resolutions. In this way, the DP will be converted to px in the same way, but the phone’s resolution itself is different, which will cause a mismatch.)

2 Adaptation schemes

2.1 Generate resolution VALUES folder

As we mentioned above, px = (dpi / 160) * dp, but DPI is determined by both the resolution and the screen size, resulting in different resolutions. Dpi may be the same, so you end up with the same PX. For example, if both take up half of the screen, 300X300 might be 150. But 400 x 400 is also 150, so it’s not right.

Then we have an idea. Can we not be influenced by resolution and screen size at the same time, but only by one factor, which is truly proportional. For example, 300X300 is 150,400 X400 is 200, and 500X500 is 250, which only depends on the resolution, so if you have a higher resolution, you’re going to get a higher result. So we can’t use dp. It’s a new unit, and it gets a different value depending on the resolution. So how do you calculate it? For example, in 300X300, we say 1 haha equals 1 px, and then in 600 X 600, 1 haha equals 2 px. In 1200X1200, 1 haha equals 3 px. So we put different values in the values folder at different resolutions:

300X300下
<dimens name = "1haha"> 1px </ DIMens > 600X600 <dimens name ="1haha"> 2px </ Dimens > 1200X1200 <dimens name ="1haha"> 3px </dimens>
Copy the code

So this is plan 1, with a link to the article.

Android screen adaptation scheme we can look at the following figure:

We can see values that list all possible screen resolutions and then manually assign them in multiples. Of course, these files can not be handwritten, through Java automatically generated corresponding files:

So the only thing that ultimately affects the result is the resolution, and the higher the resolution, the greater the value of x1.

A fatal flaw in this solution is that it requires a precise hit to fit. For example, a 1920×1080 phone must find the 1920×1080 qualifier, otherwise it will have to use the same default Dimens file. With the default size, the UI is likely to be distorted or, in short, poorly fault-tolerant.


2.2 Generating the values-sw folder

For reference:

Android is currently the most stable and efficient UI adaptation scheme

SAO year your screen adaptation way should upgrade! -smallestWidth qualifier adaptation scheme

In fact, this method can be said to be the same as the 2.1 method above. The only difference is the use of SW to ensure some fault tolerance.

We have changed the resolution values to values-sw.


2.3 Percentage layout library

The Android Enhanced Percent-support-lib library has been extended for adaptation

Actually, this is also very simple, literally, I wrote that the Button width is 50 percent of the parent layout, and on different phones, it’s 50 percent. Anyone who has ever used a percentage layout should know that we wrote it like this:

<android.support.percent. PercentRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_heightPercent="20%"
        app:layout_widthPercent="50%"
        android:gravity="center"
        />

</PercentRelativeLayout >
Copy the code

In fact, the principle is very simple, is to dynamically calculate the actual 50 percent of the total number of px in different machines, 2.1, 2.2 is equivalent to helping us to calculate the specific PX in advance, and then write in the file, and then we read the data.

So how does it work? There are two simple steps:

  1. Gets the percentage value that the user filled in
  2. Gets the space of the parent layout, then multiplys it by the percentage value entered by the user, or a new value, and assigns it to the control.

Let’s look at the source code step by step:

2.3.1 Get the percentage value of the user:

We know that the core property in our percentage layout is the child control to fill in:

app:layout_heightPercent="20%"
app:layout_widthPercent="30%"
Copy the code

So we need to traverse the child controls below it in PercentRelativeLayout and get the percentage value of each child control separately. It’s pretty simple, if you’ve ever written a custom View, because this is really just a custom property.

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PercentLayout_Layout);
float value = array.getFraction(R.styleable.PercentLayout_Layout_layout_widthPercent, 1, 1,-1f);
Copy the code

2.3.2 Get the calculated value and assign:

This behavior is performed in the onMeasure method because the parent control is dynamically retrieved and the new value is assigned to the child control.

LayoutParams public void fillLayoutParams(viewgroup. LayoutParams params, int widthHint, int heightHint) { // Preserve the original layout params, so we can restore them after the measure step. mPreservedParams.width = params.width; mPreservedParams.height = params.height;if (widthPercent >= 0) {
                params.width = (int) (widthHint * widthPercent);
            }
            if (heightPercent >= 0) {
                params.height = (int) (heightHint * heightPercent);
            }
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "after fillLayoutParams: (" + params.width + "," + params.height + ")"); }}Copy the code

Of course, the specific source will be more, I will not be a large length to complete the process, more is to explain ideas.


2.4 AutoLayout

Android AutoLayout’s new adaptation is the adaptation terminator

The way to use it is simple:

  1. Register design dimensions

Introducing autolayout

dependencies {
    compile project(':autolayout')}Copy the code

Specify the size of your design in the AndroidManifest of your project.

<meta-data android:name="design_width" android:value="768"></meta-data>
<meta-data android:name="design_height" android:value="1280"></meta-data>
Copy the code
  1. Start Settings in your Activity for your Activity to inheritAutoLayoutActivity

The idea, of course, is to read the values in androidmanifest.xml and use them as reference values. Then dynamically calculate the numbers on different phones. Does it feel similar to the percentage layout?

Let’s look at AutoLayoutActivity source:

public class AutoLayoutActivity extends AppCompatActivity
{
    private static final String LAYOUT_LINEARLAYOUT = "LinearLayout";
    private static final String LAYOUT_FRAMELAYOUT = "FrameLayout";
    private static final String LAYOUT_RELATIVELAYOUT = "RelativeLayout";


    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs)
    {
        View view = null;
        if (name.equals(LAYOUT_FRAMELAYOUT))
        {
            view = new AutoFrameLayout(context, attrs);
        }

        if (name.equals(LAYOUT_LINEARLAYOUT))
        {
            view = new AutoLinearLayout(context, attrs);
        }

        if (name.equals(LAYOUT_RELATIVELAYOUT))
        {
            view = new AutoRelativeLayout(context, attrs);
        }

        if(view ! = null)return view;

        returnsuper.onCreateView(name, context, attrs); }}Copy the code

We found that the Layout controls we wrote in layout.xml were replaced with custom controls such as AutoXXXX. Then we use AutoLinearLayout to analyze: actually read the source code of the percentage layout, you will find that the basic architecture is the same, so the percentage layout code can understand, and then go to see AutoLayout related code will soon.


2.5 Dynamically change density

A very low cost Android screen adaptation

Is Android screen adaptation a hassle? No! It’s too easy.

Android screen adaptation has never been easier

SAO year your screen adaptation way should upgrade! – Toutiao adaptation scheme

  1. If the design is 1920px by 1080px and density is 3, the screen is actually 640DP by 360DP. If we want our Button to occupy half of it, do we need to set the width to 180dp?
  2. If the screen is 1280X 720 and density is 2, the width is 360DP, which is exactly half of the width when set to 180DP.
  3. If the density of the 1280X 720 phone is 3 and the width is 240dp, set it to 180dp and the actual PX value is: 180 * 3 = 540px, but we want 360px, i.e. 180 * density = 360px, since we can’t change the value of 180DP (i.e., set a value for various phones), we can only change the density.
  4. Density = 360 Ha ha. Yes, density is 2. We dynamically change density from 3 to 2.
  5. For example, the density of the 960X540 mobile phone is 2, because our Button width is set to 180dp, and the width is 180X 2 = 360px, which is more than half, we just need to dynamically change the density to 180X = 270px. So our density is calculated to be 1.5.

Density, density, density, density, density, density, density, density, density, density, density, density, density, density The width of the design is 360DP, and the 960X540 phone can be obtained as long as 540/360 = 1.5, so density = the true width of the device (px) /360

if (orientation.equals("height")) {
        targetDensity = (appDisplayMetrics.heightPixels - barHeight) / 667f;
} else {
        targetDensity = appDisplayMetrics.widthPixels / 360f;
}
Copy the code

Therefore, the density is dynamically changed to meet the design plan.

Conclusion:

emm……. Just spray it…