Android resolution adaptation test

Android resolution adaptation test

Overview

When developing for Android, you will definitely find screen adaptation a particularly painful thing. It is extremely painful to adapt to various screen sizes. If we look at this issue from another angle, I wonder if you have learned about web front-end development, or you are familiar with web pages. In fact, the adaptation problem also exists in the design of web pages in theory. Why do I say that? The resolution of computer monitors, including mobile phone resolutions, I dare say that the types of resolutions far exceed the resolution of Android devices, then there is a very strange phenomenon:

Why do web page designers never say that adaptation is so troublesome?

So, what is the reason that the design of the web page can still give users a high-quality experience in a wide range of resolutions? With this doubt, I asked my wife (front-end staff), and she opened her eyes and asked me: What is adaptation? fc, damn, it seems that there is indeed no such problem. Later, after I asked her carefully, she told me, oh, this size, I always set it to 20%~~ In the final analysis, there is actually one reason, the web page provides a percentage calculation size.

Similarly, after getting the design drawings from the UI, have you ever complained that the UI staff marked all the numbers in px, but my project uses dp? What the hell, I explained it to the UI staff, but they still didn't understand. Then this example can also solve the conflict between Android engineers and UI staff. The UI gives a design draft of a fixed size, and then you don't have to think when writing the layout. Just copy the pixel values ​​marked above and you can achieve perfect adaptation. Isn't it ideal?

However, the adaptation scheme given by Android for different screens is dp, so what is the difference between dp and percentage?

dp vs percentage

dp

Let's first look at the definition of dp:

Density-independent pixel (dp) is independent pixel density. The standard is 160dip. That is, 1dp corresponds to 1 pixel. The calculation formula is: px = dp * (dpi / 160). The higher the screen density, the more pixels 1dp corresponds to.

There is a dpi in the above formula, dpi is Dots Per Inch (dots printed per inch), that is, when the dpi of the device is 160, 1px=1dp;

Well, it doesn’t matter whether you remember the above concepts or not. Just remember that dp has nothing to do with pixels. In actual use, 1dp is approximately equal to 1/160 inch.

So what adaptation problem does dp solve? It can be seen that 1dp = 1/160 inch; then it can at least solve one problem, that is, if you write a View's width and height as 160dp160dp in the layout file, the displayed size of this View on any screen resolution is approximately the same (maybe not accurate), about 1 inch by 1 inch.

However, this does not solve all adaptation problems:

The rendering effect will still be different, it is just similar

When the physical size of the devices is different, dp becomes powerless. A UI prepared for a 4.3-inch screen may have a lot of blank space on the right and bottom when running on a 5.0-inch screen. And a 5.0-inch UI may not fit on a 4.3-inch device.

The above two points come from reference link 1

In a word, dp can make the same value appear roughly the same size at different resolutions. But when the size of the device is very different, it is powerless. We still need to solve the adaptation problem ourselves, so we may do this:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <resources>
  3. <! -- values-hdpi 480X800 -->  
  4. <dimen name = "imagewidth" >120dip</dimen>
  5. </resources>
  6.  
  7. <resources>
  8. <! -- values-hdpi-1280x800 -->  
  9. <dimen name = "imagewidth" >220dip</dimen>
  10. </resources>
  11.  
  12. <?xml version= "1.0" encoding= "utf-8" ?>
  13. <resources>
  14. <! -- values-hdpi 480X320 -->  
  15. <dimen name = "imagewidth" >80dip</dimen>
  16. </resources>

The above code snippets come from the Internet. In other words, in order to provide a high-quality user experience, we still need to write multiple sets of value files for different DPI settings.

It can be seen that dp does not solve the adaptation problem. Let's look at the percentages.

percentage

This concept is self-explanatory. The width of the supported controls on the web can be set as a percentage based on the width of the parent control, and the width of the outermost control can be set as a percentage based on the screen size. In fact, in Android devices, it is sufficient to support controls that can calculate the width and height based on the percentage of the screen.

For example, I have the following requirements:

For the image display banner, in order to achieve the desired effect, I hope that the height displayed on any mobile phone is 1/4 of the screen height.

My homepage is divided into two columns, I hope that the screen height of each column is 11/24, and the interval in the middle is 1/12

The width of slidingmenu is 80% of the screen width

Of course, this is just from a broad perspective. In fact, for a small-scale layout, percentages may be more useful.

Percentages are not supported now. To achieve the above requirements, you may need 1. Code to dynamically calculate (many people directly pass, too troublesome); 2. Use weight (weight must rely on Linearlayout and cannot be applied to all scenarios)

For example, I want the height and width of a floating button to be 1/12 of the screen height, and the width of a button to be 1/3 of the screen width. All of the above requirements cannot be met using dp. We hope that the size of the control can be written as follows:

  1. <Button
  2. android:text= "@string/hello_world"  
  3. android:layout_width= "20%w"  
  4. android:layout_height= "10%h" />

Use the ratio of the screen width to height to define the width and height of the View.

Okay, now we can see the difference between dp and percentage, and percentage can better solve our adaptation problem.

some adaptation tips

Let's take a look at some adaptation tips

Use match_parent more often

Multi-use weight

Custom view solution

In fact, the above three tips are all about percentages. match_parent is equivalent to 100% reference to the parent control; weight is proportional distribution; custom view is nothing more than most of the sizes in it are calculated according to percentages;

Through these tips, we can see more clearly that if we can introduce the percentage mechanism in Android, most of the adaptation problems will be solved. Let's take a look at how to make Android support the concept of percentage.

Introduction of percentage

1. Introduction

In fact, our solution is to create a folder for each mobile phone screen resolution you need to adapt in the project.

As shown below:

Then we use a benchmark, which means:

For example, the resolution of 480*320 is the benchmark

The width is 320, and the width of any resolution is divided into 320 parts, with the value x1-x320

The height is 480, and the height of any resolution is divided into 480 parts, with the value of y1-y480

For example, for 800*480 with a width of 480:

You can see that x1 = 480 / base = 480 / 320 = 1.5; other resolutions are similar~~

You may ask, with so many files, do we have to calculate them manually and then write them ourselves? Don't be afraid, I will explain it below.

So, you may have a question, what are the benefits of writing like this?

Suppose I need to have a button in the center of the screen, with a width and height that is 1/2 of the width of our screen, how can I write a layout file?

  1. <FrameLayout>
  2.  
  3. <Button
  4.  
  5. android:layout_gravity= "center"  
  6.  
  7. android:gravity= "center"  
  8.  
  9. android:text= "@string/hello_world"  
  10.  
  11. android:layout_width= "@dimen/x160"  
  12.  
  13. android:layout_height= "@dimen/x160" />
  14.  
  15. </FrameLayout>

You can see that our width and height are defined as x160, which is actually 50% of the width;

Then the effect diagram:

You can see that no matter what the resolution of the model, the width and height of our button is always half the width of the screen.

For design drawings

Assuming that the current UI design is designed according to 480*320, and the width and height markers above are both px values, you can directly convert px into x[1-320], y[1-480], so that the layout written can basically be adapted to the full resolution.

You may ask: What if the resolution of the designer's design is not fixed? The following will explain~

For the several DPs mentioned above that cannot be done

You can try it yourself by introducing percentages~~

Well, there is a major problem that we didn't mention, which is that with so many resolutions, do we have to calculate and then write them by hand?

2. Automatic generation tools

Well, actually, you can also write such folders by hand. Just compile a set according to the resolution you need to support and use it all the time.

Of course, as programmers, how can we do such a low-level job? We must implement it with a program:

Then the implementation requires the following steps:

1). Analyze the resolution required for support

I have integrated the mainstream resolutions into our program. Of course, for special ones, you can specify them through parameters. For screen resolution information, you can check this website: http://screensiz.es/phone| 00daae956ab82373e1f8431e7cd28c3516 |

2). Write a program to automatically generate files

The code is as follows

  1. import java.io.File;
  2. import java.io.FileNotFoundException;
  3. import java.io.FileOutputStream;
  4. import java.io.PrintWriter;
  5.  
  6. /**
  7. * Created by zhy on 15/5/3.
  8. */
  9. public class GenerateValueFiles {
  10.  
  11. private int baseW;
  12. private int baseH;
  13.  
  14. private String dirStr = "./res" ;
  15.  
  16. private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n" ;
  17. private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n" ;
  18.  
  19. /**
  20. * {0}-HEIGHT
  21. */
  22. private final static String VALUE_TEMPLATE = "values-{0}x{1}" ;
  23.  
  24. private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,960;600,1024;720,1184;720,1196;720,1280;768,1024;800,1280;1080,1812;1080,1920;1440,2560;" ;
  25.  
  26. private String supportStr = SUPPORT_DIMESION;
  27.  
  28. public GenerateValueFiles( int baseX, int baseY, String supportStr) {
  29. this.baseW = baseX;
  30. this.baseH = baseY;
  31.  
  32. if (!this.supportStr. contains (baseX + "," + baseY)) {
  33. this.supportStr += baseX + "," + baseY + ";" ;
  34. }
  35.  
  36. this.supportStr += validateInput(supportStr);
  37.  
  38. System. out .println(supportStr);
  39.  
  40. File dir = new File(dirStr);
  41. if (!dir.exists()) {
  42. dir.mkdir();
  43.  
  44. }
  45. System. out .println(dir.getAbsoluteFile());
  46.  
  47. }
  48.  
  49. /**
  50. * @param supportStr
  51. * w,h_...w,h;
  52. * @return  
  53. */
  54. private String validateInput(String supportStr) {
  55. StringBuffer sb = new StringBuffer();
  56. String[] vals = supportStr.split( "_" );
  57. int w = -1;
  58. int h = -1;
  59. String[] wh;
  60. for (String val : vals) {
  61. try {
  62. if (val == null || val.trim().length() == 0)
  63. continue ;
  64.  
  65. wh = val.split( "," );
  66. w = Integer .parseInt(wh[0]);
  67. h = Integer .parseInt(wh[1]);
  68. } catch (Exception e) {
  69. System. out .println( "skip invalidate params : w,h = " + val);
  70. continue ;
  71. }
  72. sb.append(w + "," + h + ";" );
  73. }
  74.  
  75. return sb.toString();
  76. }
  77.  
  78. public void generate() {
  79. String[] vals = supportStr.split( ";" );
  80. for (String val : vals) {
  81. String[] wh = val.split( "," );
  82. generateXmlFile( Integer .parseInt(wh[0]), Integer .parseInt(wh[1]));
  83. }
  84.  
  85. }
  86.  
  87. private void generateXmlFile( int w, int h) {
  88.  
  89. StringBuffer sbForWidth = new StringBuffer();
  90. sbForWidth.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" );
  91. sbForWidth.append( "<resources>" );
  92. float cellw = w * 1.0f / baseW;
  93.  
  94. System. out .println( "width : " + w + "," + baseW + "," + cellw);
  95. for ( int i = 1; i < baseW; i++) {
  96. sbForWidth.append(WTemplate. replace ( "{0}" , i + "" ). replace ( "{1}" ,
  97. change(cellw * i) + "" ));
  98. }
  99. sbForWidth.append(WTemplate. replace ( "{0}" , baseW + "" ). replace ( "{1}" ,
  100. w + "" ));
  101. sbForWidth.append( "</resources>" );
  102.  
  103. StringBuffer sbForHeight = new StringBuffer();
  104. sbForHeight.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" );
  105. sbForHeight.append( "<resources>" );
  106. float cellh = h *1.0f/ baseH;
  107. System. out .println( "height : " + h + "," + baseH + "," + cellh);
  108. for ( int i = 1; i < baseH; i++) {
  109. sbForHeight.append(HTemplate. replace ( "{0}" , i + "" ). replace ( "{1}" ,
  110. change(cellh * i) + "" ));
  111. }
  112. sbForHeight.append(HTemplate. replace ( "{0}" , baseH + "" ). replace ( "{1}" ,
  113. h + "" ));
  114. sbForHeight.append( "</resources>" );
  115.  
  116. File fileDir = new File(dirStr + File.separator
  117. + VALUE_TEMPLATE. replace ( "{0}" , h + "" )//
  118. .replace ( "{1}" , w + "" ));
  119. fileDir.mkdir();
  120.  
  121. File layxFile = new File(fileDir.getAbsolutePath(), "lay_x.xml" );
  122. File layyFile = new File(fileDir.getAbsolutePath(), "lay_y.xml" );
  123. try {
  124. PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
  125. pw.print(sbForWidth.toString());
  126. pw.close ();
  127. pw = new PrintWriter(new FileOutputStream(layyFile));
  128. pw.print(sbForHeight.toString());
  129. pw.close ();
  130. } catch (FileNotFoundException e) {
  131. e.printStackTrace();
  132. }
  133. }
  134.  
  135. public   static   float change( float a ) {
  136. int   temp = ( int ) (a * 100);
  137. return   temp / 100f;
  138. }
  139.  
  140. public   static void main(String[] args) {
  141. int baseW = 320;
  142. int baseH = 400;
  143. String addition = "" ;
  144. try {
  145. if (args.length >= 3) {
  146. baseW = Integer .parseInt(args[0]);
  147. baseH = Integer .parseInt(args[1]);
  148. addition = args[2];
  149. } else if (args.length >= 2) {
  150. baseW = Integer .parseInt(args[0]);
  151. baseH = Integer .parseInt(args[1]);
  152. } else if (args.length >= 1) {
  153. addition = args[0];
  154. }
  155. } catch (NumberFormatException e) {
  156.  
  157. System.err
  158. .println( "right input params : java -jar xxx.jar width height w,h_w,h_..._w,h;" );
  159. e.printStackTrace();
  160. System.exit(-1);
  161. }
  162.  
  163. new GenerateValueFiles(baseW, baseH, addition).generate();
  164. }
  165.  
  166. }

At the same time, I provide a jar package. By default, you can generate it by double-clicking it. Instructions for use:

The download address is at the end of the article. Common resolutions are built in, and the default benchmark is 480*320. Of course, for special needs, you can specify it through the command line:

For example: base 1280 800, additional supported sizes: 1152 735; 4500 * 3200;

according to

Java -jar xx.jar width height width,height_width,height

The above format is sufficient.

Conclusion

So far, we have written a tool to generate all the values ​​files that need to adapt to the resolution based on a certain benchmark size, so that when writing layout files, we can refer to the screen resolution; in the design diagram given by the UI, we can quickly write the layout according to the px unit marked by it. The adaptation problem has been basically solved. Welcome to like and comment, and also welcome to comment and exchange on the author's blog.

<<:  iOS - Solution to NSTimer circular reference

>>:  The core of natural language processing: sequence learning

Recommend

Three subtle details of Swift extensions

Whenever I first look at a document, I skim throu...

Beichen Asia Market: Analysis of Beijing Automobile Market in May 2023

New car transactions In May , Beijing's new c...

6 channels for private domain traffic!

Many people don’t know how to generate private do...

What is a suitable gift for teachers on Teacher's Day?

The annual Teachers' Day is here again. I saw...

Augmented reality prospects: Can Microsoft HoloLens herald the future?

Many people were shocked after watching the Micro...

Do you always want to check your partner's phone? It may be your hormones

Review expert: Chen Mingxin, national second-leve...

Case analysis: Xiaohongshu advertising strategy!

This article will take Cemoy, an Australian skinc...