The original address: www.jianshu.com/p/2aded8bb6…
Here’s how to upgrade your screen adaptation this year! Welcome to repost and share:
- It’s time to upgrade your screen adaptation. (I) – Toutiao adaptation scheme
- It’s time to upgrade your screen adaptation. (2) -smallestWidth qualifier adaptation solution
- Toutiao screen adaptation ultimate version officially released!
- Why is the design of AndroidAutoLayout wrong?
Join technical exchange QQ group 455850365
preface
Ok, according to the last article, it’s time to upgrade your screen adaptation! – The promise of the Toutiao adaptation solution. This is the second article in this series, which explores the smallestWidth qualifier screen adaptation solution in detail
Those of you who know me well know that MVPArms always use AndroidAutoLayout screen adaptation solution. Thanks to the convenience of AndroidAutoLayout, I have not studied much in the field of screen adaptation. After AndroidAutoLayout stopped maintenance, I was looking for an alternative until Todaytoutiao screen adaptation scheme went on the screen, and then CAME across smallestWidth qualifier screen adaptation scheme, which slowly turned my research direction to screen adaptation field
In the last month, I started to learn more about Android screen adaptation, and I have done a deeper study of these two solutions. I can say that I grew up slowly from a small white, so I understand the pain of a small white, so in the last article, your screen adaptation should be upgraded! – In the adaptation scheme of Toutiao, the screen adaptation scheme of Toutiao is very detailed, and try to describe every knowledge point clearly, so as to avoid missing every detail. In this article, I will continue the good tradition of the last article, and describe every knowledge point of the smallestWidth qualifier screen adaptation scheme clearly
By the way, thank you for supporting AndroidAutoSize. I just mentioned the screen adaptation framework I just released, AndroidAutoSize, in my last article. I didn’t give a detailed introduction or analysis of the principles (originally planned for the third article in this series). AndroidAutoSize was promoted to Github Trending by everyone, and I got 2K + stars in more than a week. With the increase of attention, I was also tired during this period. Issues never stopped, and I submitted more than 200 commit times in less than half a month. But tired and happy, thanks again for your recognition of AndroidAutoSize
Talk about the percentage pool
Well, in the last article, some brothers raised some opinions, which I quite agree with, but I look at this issue from the perspective of an executive, and there are some different opinions. The following is my reply in the last article
Attention, everyone! These points are really for all libraries with a percentage scale layout, not just toutiao’s screen fit, so they also apply to smallestWidth qualifier screen fit, which is a misconception, so be aware!
Each of the boxes in the picture represents the screen of an Android device. The fragmentation of Android system, the fragmentation of model and screen size, and the fragmentation of screen resolution can be seen by the Alliance Index. Sometimes, when it comes to the criteria for deciding something, it is not as if it is right or wrong. In most cases, we need to analyze various factors such as costs and benefits, and make a decision based on the advantages and disadvantages. Everyone has different standards of advantages and disadvantages, so everyone’s opinion will be different, but they should be respected. So I just talk about my own opinion, and I don’t deny anyone’s opinion
Scheme is dead people is alive, in some domestic mobile phone or tablet, you can also use other adaptation scheme and percentage library used in combination, such as for a range of screen equipment separate out a set of drawings to show more than the small screen mobile phone more detailed content, to achieve the result that complements percentage library, without a plan is perfect, However, we can clearly recognize the advantages and disadvantages of different solutions, and combine their advantages to cope with more complex development needs and produce the best product
Friendly tip: The following smallestWidth qualifier screen adaptation solution is also based on the principle of percentage zoom layout, theoretically there will be the above mentioned large-screen phone and small-screen phone display the same problem, please choose carefully
This section describes the smallestWidth qualifier adaptation scheme
This scheme is used in the same way that we would normally reference Dimens in the layout. The core point is to generate the dimens. XML file, but someone has done this for us
├ ─ ─ SRC/main │ ├ ─ ─ res │ ├ ─ ─ ├ ─ ─ values │ ├ ─ ─ ├ ─ ─ values - 800 x480 │ ├ ─ ─ ├ ─ ─ values - 860 x540 │ ├ ─ ─ ├ ─ ─ values - 1024 x600 │ ├ ─ ─ ├ ─ ─ values - 1024 x768 │ ├ ─ ─ ├ ─ ─... │ ├ ─ ─ ├ ─ ─ x1440 values - 2560Copy the code
If you remember the width and height qualifier screen adaptation scheme above, you can consider the smallestWidth qualifier screen adaptation scheme as an upgrade to this scheme. The smallestWidth qualifier screen adaptation solution simply changes the value from px to DP in the dimens. XML file. The principle and usage of the smallestWidth qualifier are the same as described in the previous article. The smallestWidth qualifier screen adaptation scheme looks like this 👇
├ ─ ─ SRC/main │ ├ ─ ─ res │ ├ ─ ─ ├ ─ ─ values │ ├ ─ ─ ├ ─ ─ values - sw320dp │ ├ ─ ─ ├ ─ ─ values - sw360dp │ ├ ─ ─ ├ ─ ─ values - sw400dp │ ├ ─ ─ ├ ─ ─ values - sw411dp │ ├ ─ ─ ├ ─ ─ values - sw480dp │ ├ ─ ─ ├ ─ ─... │ ├─ ├──values-sw640dp │ ├─ ├──values-sw640dpCopy the code
The principle of
The smallestWidth qualifier screen adaptation solution is very simple. The developer first generates a set of values-sw
dp folders (containing dimens.xml) based on the minimum width of the main screen (smallestWidth). When running the project on the device, the system will match the corresponding values-sw
dp folder according to the current smallestWidth (smallestWidth), and the corresponding values-sw
DP folder dimens. XML text value. It is customized according to the smallestWidth of the current device screen, so it must be suitable for the current device
If the system does not find a values-sw
dp folder based on the current smallestWidth, it will find a values-sw
DP folder similar to the smallestWidth of the current smallestWidth. The system will only look for values-sw
dp which is less than or equal to the current smallestWidth of the device. This is the fault tolerance of the screen adaptation scheme which is better than the width and height qualified. It can also generate a lot less values-sw
DP folders, reducing the size of the App
What is a smallestWidth
SmallestWidth = minimum width
The system matches values-sw
dp according to the minimum width of the current device screen. Why not add the word minimum instead of the width?
It said that mobile devices are allowed to screen can rotate, when the screen rotation, high to width of the screen will swap, with minimum this two word, because the solution is not to distinguish the direction of the screen, it will only put the height and width of the screen the least value of party think the minimum width, the minimum width is set according to the screen, is fixed, It means that no matter how you rotate the screen, as long as the height of the screen is greater than the width, the system will only assume that the width of the screen is the minimum width, or if the width of the screen is greater than the height, the system will assume that the height of the screen is the minimum width, right
What if you want the screen width to change as the screen rotates? You can generate a set of resource files based on values-w
dp (minus the s in SW)
What if you want to differentiate the orientation of the screen for adaptation? Then you have to generate a set of resource files based on the screen orientation qualifier with -land or -port, like this, values-sw400dp-land (minimum width 400dp landscape), Values -sw400dP-port values -sw400dP-port values -sw400dP-port values
How to calculate the value of smallestWidth
We need to calculate the smallestWidth value of the current device before we know which values-sw
DP folder the current device matches
Ok, or according to the narrative of the last article, now to illustrate the chestnut, to help you better understand
Let’s assume that the device screen information is 1920 * 1080, 480 DPI
The minimum width is 1080 < 1920. Obviously 1080 px is the minimum width we are looking for, but the minimum width is in dp, so we will convert px to DP
Help you to consolidate the foundation, the following formula must not be forgotten again!
Density = dp, DPI / 160 = density, so the final formula is px/(DPI / 160) = dp
So the minimum width we get is 360 dp (1080 / (480/160) = 360.
Now we have calculated that the minimum width of the current device is 360dp. We know that the system will help us to match the dimens. XML file in the folder of values- SW360DP according to the minimum width. If there is no folder of values- SW360DP in the project, The system will match the values-sw
DP folder with similar values
The dimens. XML file is the core of the solution, so let’s take a look at how the dimens. XML file is generated in the values-sw360dp folder
How dimens. XML is generated
Since the actual value of Dimens we refer to in the layout of the project is derived from the dimens. XML in the values-sw
dp folder that matches the minimum width of the current device screen, find out how dimens. XML is generated. Helps us understand the smallestWidth qualifier screen adaptation scheme
When it comes to generating Dimens. XML, there are two factors involved. The first factor is the minimum width benchmark value, and the second factor is what minimum width your project needs to fit. Commonly known as how many values-sw
DP folders need to be generated
The first factor
What does minimum width reference mean? The simple idea is that you want to divide the screen width of the device into 360 portions. Let’s say we now set the minimum width reference value of the project to 360, then this solution would understand that you want to divide the screen width of all the devices into 360 portions. The solution will help you generate dimens references from 1 to 360 in the dimens. XML file, such as the dimens. XML in values-sw360dp looks like this
<resources>
<dimen name="dp_1">1dp</dimen>
<dimen name="dp_2">2dp</dimen>
<dimen name="dp_3">3dp</dimen>
<dimen name="dp_4">4dp</dimen>
<dimen name="dp_5">5dp</dimen>
<dimen name="dp_6">6dp</dimen>
<dimen name="dp_7">7dp</dimen>
<dimen name="dp_8">8dp</dimen>
<dimen name="dp_9">9dp</dimen>
<dimen name="dp_10">10dp</dimen>.<dimen name="dp_356">356dp</dimen>
<dimen name="dp_357">357dp</dimen>
<dimen name="dp_358">358dp</dimen>
<dimen name="dp_359">359dp</dimen>
<dimen name="dp_360">360dp</dimen>
</resources>
Copy the code
Values – SW360DP values- SW360DP values- SW360DP values- SW360DP values- SW360DP values- SW360DP values- SW360DP The dimens with the largest value reference dp_360 also has a value of 360DP, which covers the width of the screen
Let’s take a look at what dimens. XML in values- SW400DP looks like with the minimum width base set to 360
<resources>
<dimen name="dp_1">1.1111 dp</dimen>
<dimen name="dp_2">2.2222 dp</dimen>
<dimen name="dp_3">3.3333 dp</dimen>
<dimen name="dp_4">4.4444 dp</dimen>
<dimen name="dp_5">5.5556 dp</dimen>
<dimen name="dp_6">6.6667 dp</dimen>
<dimen name="dp_7">7.7778 dp</dimen>
<dimen name="dp_8">8.8889 dp</dimen>
<dimen name="dp_9">10.0000 dp</dimen>
<dimen name="dp_10">11.1111 dp</dimen>.<dimen name="dp_355">394.4444 dp</dimen>
<dimen name="dp_356">395.5556 dp</dimen>
<dimen name="dp_357">396.6667 dp</dimen>
<dimen name="dp_358">397.7778 dp</dimen>
<dimen name="dp_359">398.8889 dp</dimen>
<dimen name="dp_360">400.0000 dp</dimen>
</resources>
Copy the code
Values – sw400dp refers to the current device screen, the minimum width is 400 dp (height is greater than the width of the device, the minimum width is the width, so the device width is 400 dp), also the screen width is divided into 360, are each equal to 1.1111 dp at this moment, Each reference is incremented by 1.1111dp, and the dimens reference dp_360 with the largest value also covers the screen width, which is 400dp
By comparing two dimens. XML files, the generation principle of dimens. XML is clear. The scheme will first determine the minimum width reference value, and then allocate dimens. XML files in each values-sw
DP with the same number of copies of the minimum width reference value. Then according to the formula of minimum screen width/number of copies (minimum width benchmark value), the proportion of each DP is calculated. Ensure that in any values-sw
DP, the proportion of copies (minimum width benchmark value) * each dp value is just covering the screen width. Therefore, under the condition that the number of copies remains the same, You only need to dynamically adjust the VALUE of each DP on different devices according to the width of the screen to complete the adaptation
This ensures that no matter which device you run your project on, as long as the current device matches the corresponding values-sw
dp folder, the dimens reference in the layout will be scaled according to the current screen, ensuring a perfect fit. If it does not match the corresponding values-sw
dp folder, it does not matter, it will look for a similar values-sw
dp folder, although in this case, the dimens reference in the layout may be slightly incorrect, but it will ensure the maximum fit
With that said, you should see why I’m talking about the smallestWidth qualifier and the screen adaptation solution is also a percentage layout, so if in the layout, a View’s width refers to DP_100, it doesn’t matter which device it’s running on, The width of this View is 100 over 360 of the total width of the current device screen, provided that the project provides values-sw
dp corresponding to the current device screen. If there is no corresponding values-sw
dp, it will look for similar values-sw
dp. And then you have an error, and whether you have a large error or a small error depends on what your second factor is, right
In fact, the smallestWidth qualifier is similar to the Toutiao screen adaptation scheme, which dynamically adjusts the density of each device based on the width or height of the screen (how many pixels per DP of the current device screen). The smallestWidth qualifier screen adaptation scheme also dynamically adjusts the DP per device based on the screen width
Second factor
The second factor is what is the minimum width that needs to be adapted? For example, the minimum width you want to fit is 320DP, 360DP, 400DP, 411DP, 480DP, The solution will generate the values -SW320DP, values -SW360DP, values -SW400DP, values -SW411DP, values -SW480dp resource folders for your project, like 👇
├ ─ ─ SRC/main │ ├ ─ ─ res │ ├ ─ ─ ├ ─ ─ values │ ├ ─ ─ ├ ─ ─ values - sw320dp │ ├ ─ ─ ├ ─ ─ values - sw360dp │ ├ ─ ─ ├ ─ ─ values - sw400dp │ ├ ─ ─ ├ ─ ─ values - sw411dp │ ├ ─ ─ ├ ─ ─ values - sw480dpCopy the code
The solution will generate a set of values-sw
dp in the project for the minimum width you need to fit. As mentioned earlier, if a device does not provide it with a corresponding values-sw
dp, it will look for a similar values-sw
dp. However, if this close values-sw
dp is too far away from the expected values-sw
dp, then the adaptation effect will be greatly reduced
The more values-sw
dp is generated, the more devices are covered, the better?
No, because each values-sw
dp folder takes up a certain amount of App volume. The more values-sw
DP folders you have, the larger the size of your App will be
So be sure to properly allocate values-sw
dp, with fewer values-sw
DP folders, cover more models
Verify the feasibility of the scheme
So now that we’re done with the principle, let’s just do the usual thing, and see if it works, okay?
Assuming the total width of the design drawing is 375 dp and the size of a View on the design drawing is 50dp * 50DP, the width of this View is 13.3% of the total width of the design drawing (50/375 = 0.133).
When using the smallestWidth qualifier screen adaptation solution, we need to provide the minimum width reference value and the minimum width to be adapted. We set the minimum width reference value to 375 (consistent with the design drawing). In this case, the solution generates the values-sw
dp folder for the minimum width we need to match. The dimens. XML file in the folder is a reference of Dimens from 1 to 375, dividing the screen width of all devices into 375 pieces. So in the layout file we should reference both the height and width of the View to DP_50
Let’s verify that the ratio of the View to the width of the screen remains the same on devices with different resolutions using the smallestWidth qualifier screen adaptation scheme
Verify device 1
Device 1 has a total screen width of 1080 px, a total screen height of 1920 px, and a DPI of 480
The screen height of device 1 is larger than the screen width, so the minimum width of device 1 is the screen width. Then, according to the formula px/(DPI / 160) = dp, the minimum width of device 1 is 360 dp (1080 / (480/160) = 360).
It should match the values- SW360DP folder based on the minimum width of device 1. Assume that the values- SW360DP folder and dimens. XML within it have been generated with the minimum width base value of 375. 360/375 = 0.96, so each dp value is 0.96, and the contents in dimens. XML are as follows: 👇
<resources>
<dimen name="dp_1">0.96 dp</dimen>
<dimen name="dp_2">1.92 dp</dimen>
<dimen name="dp_3">2.88 dp</dimen>
<dimen name="dp_4">3.84 dp</dimen>
<dimen name="dp_5">4.8 dp</dimen>.<dimen name="dp_50">48dp</dimen>.<dimen name="dp_371">356.16 dp</dimen>
<dimen name="dp_372">357.12 dp</dimen>
<dimen name="dp_373">358.08 dp</dimen>
<dimen name="dp_374">359.04 dp</dimen>
<dimen name="dp_375">360dp</dimen>
</resources>
Copy the code
You can see that dp_50 is referenced in the layout and is finally fixed at 48 dp in the values-sw360dp. So the View on device 1 has a height of 48 dp and a width of 48 dp. The system will convert the height and width to px. (DPI / 160) = px, so the height and width of this View are 144 px (48 * (480/160) = 144).
144/1080 = 0.133, the proportion of the actual width of the View to the total width of the screen is the same as the proportion of the View in the design (50/375 = 0.133), so the scale is complete
Some devices have the same height and width as device 1, but the DPI may be different, and since the smallestWidth qualifier screen adaptors do not modify the density as toutiao screen adaptors do, Therefore, the system uses the default formula DPI / 160 to find the density, which in turn affects the conversion between DP and px, so it is possible that the change in DPI will affect the smallestWidth qualifier screen adaptation
So let’s try again to see if the smallestWidth qualifier screen adaptor works in this particular case
Verifying device 2
Device 2 has a total screen width of 1080 px, a total screen height of 1920 px, and a DPI of 420
The screen height of device 2 is larger than the screen width, so the minimum width of device 2 is the screen width, and then the formula px/(DPI / 160) = dp, Figure out the minimum width of device 2 as 411.429 dp (1080 / (420/160) = 411.429)
The folder values- SW411dp should match the minimum width of device 2. Assume that the folder values- SW411dp and dimens. XML inside have been generated with the minimum width base value 375. 411/375 = 1.096, so each dp is 1.096, and the contents in dimens.xml are as follows: 👇
<resources>
<dimen name="dp_1">1.096 dp</dimen>
<dimen name="dp_2">2.192 dp</dimen>
<dimen name="dp_3">3.288 dp</dimen>
<dimen name="dp_4">4.384 dp</dimen>
<dimen name="dp_5">5.48 dp</dimen>.<dimen name="dp_50">54.8 dp</dimen>.<dimen name="dp_371">406.616 dp</dimen>
<dimen name="dp_372">407.712 dp</dimen>
<dimen name="dp_373">408.808 dp</dimen>
<dimen name="dp_374">409.904 dp</dimen>
<dimen name="dp_375">411dp</dimen>
</resources>
Copy the code
As you can see, the dp_50 View is referenced in the layout and is finally fixed at 54.8dp in values-sw411dp, so the View on device 2 is 54.8dp in height and width, and the system will convert the height and width to px. (DPI / 160) = px; (DPI / 160) = px; (DPI / 160) = px;
143.85/1080 = 0.133, the actual width of the View to the total width of the screen is the same proportion as the View in the design (50/375 = 0.133), so the scale is complete
Although the height and width of the View on device 2 is 143.85px, which is 0.15px less than the 144px on device 1, the error is very small and the overall ratio has not changed much, which is completely acceptable
This error is caused by the fact that the actual minimum width of device 2 is 411.429DP, but the matching values -SW411dp have the number of digits after the decimal point (remember! The system will look for values-sw
dp less than or equal to 411.429dp, so the folder values -SW412DP, device 2 can not match), so there is a certain error, so the second factor introduced above is very important, which directly determines whether the error is large or small
It can be seen that even on devices with the same height and width but different DPI, the smallestWidth qualifier screen adaptation scheme can achieve equal proportion adaptation, which proves that this scheme is feasible. If you still have doubts, you can try other devices with different resolutions. In fact, the final ratio is around 0.133. The only variable is the second factor. If the values-sw
DP you generate are not too different from the actual minimum width of the device, then the error is within the acceptable range. If the difference is too large, then GG
advantages
-
Very stable, very low probability of accidents
-
There will be no loss of performance
-
The adaptation range can be freely controlled, will not affect the other three parties library
-
Under the cooperation of plug-in, the learning cost is low
disadvantages
-
Referencing Dimens in the layout, although cheaper to learn, is more cumbersome in routine maintenance and modification
-
High intrusion. If the project wants to switch to other screen adaptation scheme, because there are a lot of References of Dimens in each Layout file, it will take a lot of work to modify and the switching cost is very high
-
If you want to cover more models, you need to generate more resource files. However, this will increase the size of the App, and some errors will occur on the models that are not covered. Therefore, sometimes you need to make some choices in terms of adaptation effect and occupied space
-
If you want to use sp, you also need to generate a series of Dimens, resulting in another increase in the size of the App
-
It does not automatically support portrait/portrait adaptation. As mentioned above, if you want to automatically support portrait/portrait adaptation, you need to use values-w
dp or the screen orientation qualifier to generate a set of resource files, which will increase the size of the App again
-
Cannot be adapted in a highly as a benchmark, considering the plan itself is called minimum width qualifier adaptation scheme, so before using this solution should be to know the plan only in width as a benchmark for adaptation, why now the screen adaptation of solution only in one of the height or width as a benchmark for adapter, please see here
Problems in use
Some people may ask, the designer only marked px in the drawing, but to use this scheme, doesn’t it need to convert px to DP first?
In fact, you can also not convert, that is what SAO operation?
Very simple, you can set the total width of the px in the design drawing to the minimum width reference value, as in the previous example to verify feasibility
We set the minimum width reference value to 375 in the previous feasibility test. Why 375? Since the total width of the design drawing is 375 dp, if converted to px, the total width is 750 px. Let’s set the minimum width to 750 and look at the dimens. XML in values-sw360dp 👇
<resources>
<dimen name="px_1">0.48 dp</dimen>
<dimen name="px_2">0.96 dp</dimen>
<dimen name="px_3">1.44 dp</dimen>
<dimen name="px_4">1.92 dp</dimen>
<dimen name="px_5">2.4 dp</dimen>.<dimen name="px_50">24dp</dimen>.<dimen name="px_100">48dp</dimen>.<dimen name="px_746">358.08 dp</dimen>
<dimen name="px_747">358.56 dp</dimen>
<dimen name="px_748">359.04 dp</dimen>
<dimen name="px_749">359.52 dp</dimen>
<dimen name="px_750">360dp</dimen>
</resources>
Copy the code
The 360 DP is divided into 750 pieces. Compared to the previous 375 pieces, the value of each piece of DP is reduced by half. Remember the size of the View in the feasibility test example? 50dp * 50dp, if the layout is just px, then the size of the View on the layout should be 100px * 100px, so we can refer to px_100 in the layout without even thinking about it. Because dp_50 at 375 copies is exactly the same as Px_100 at 750 copies (both 48DP), there is no difference in the adaptation effect from the previous feasibility test
Got it? Use the minimum width reference and the reference in the layout in units of px to fill in the px marked on the design!
conclusion
As for the advantages and disadvantages listed in this paper, the number of disadvantages listed is indeed more than the number of advantages. However, disadvantages 3, 4, and 5 can actually be summed up as the shortcoming of occupying the App volume, because they can all solve the problem by adding resource files. While disadvantage 6 is the feature of this scheme. Adaptation can only be based on width, as the name of the scheme suggests
Please do not misinterpret the meaning of the article. Do not just compare the number of advantages and disadvantages. If the number of disadvantages is greater than the number of advantages, it must be that this scheme cannot work. No scheme is perfect, and everyone’s needs are different. As a general science article, I can only describe this scheme as comprehensively as possible
This scheme can bring you what, can’t bring you anything, I must be the description of the objective clear, it will help you make a decision, you should pay attention to what I can do in these advantages and disadvantages, what I can’t accept, whether can to some advantages to make some compromise, and not simply to see the number, this is meaningless, Some people just think stability is the most important thing, and everything else can be compromised, so other shortcomings are indifferent to them
Well, the second article in this series finished, this article is according to our tradition of excellence, write very detailed, even novice I believe should also can understand, why so many people all don’t know if I should choose what kind of plan, is because they didn’t understand the principle of these solutions, understand the principle of later know if these solutions will be what you want
The next third article will explain in detail the in-depth comparison between the two solutions and how to choose, and analyze the principle of the screen adaptation framework, AndroidAutoSize, which I optimize according to the screen adaptation scheme of Toutiao. Please look forward to it
If you want to use the smallestWidth qualifier screen adaptation scheme, you can refer to this article, which has a plugin and Demo that automatically generates resource files, since I did not use the smallestWidth qualifier screen adaptation scheme in my project. Therefore, if there is any missing knowledge in the article, please understand and add, thank you!
The public,
Search and follow my public account JessYan to learn and make progress together. If there is any update of the framework, I will inform you in the public account as soon as possible
Here’s how to upgrade your screen adaptation this year! Welcome to repost and share:
- It’s time to upgrade your screen adaptation. (I) – Toutiao adaptation scheme
- It’s time to upgrade your screen adaptation. (2) -smallestWidth qualifier adaptation solution
- Toutiao screen adaptation ultimate version officially released!
- Why is the design of AndroidAutoLayout wrong?
Hello, my name is JessYan. If you like my articles, you can follow me on the following platforms
- Personal homepage: Jessyan.me
- Making: github.com/JessYanCodi…
- The Denver nuggets: juejin. Im/user / 976022…
- Jane: www.jianshu.com/u/1d0c0bc63…
- Weibo: weibo.com/u/178626251…
— The end