【原】android【手機】屏幕適配解決方案,完美適配適配hdpi,xhdpi,xxhdpi的做法。


  • 1.先說要怎么做,后面在慢慢講解:

  • 2.現在來講解為什么要放這三套:

    • 這三套其實按內容來說就兩種,為什么這兩種可以適配hdpi,xhdpi,xxhdpi呢?

    • 那么兩種類型的dimens就可以了,為什么要用三套,為什么默認的dimens要是hdpi的?

  • 3.關於圖片的適配

  • 4.最后大概講講現有的適配方案

  • 5.附上dimens轉換的代碼


 

dp單位解決的是你所設置的按鈕的實際大小保持穩定,但是設備的物理尺寸不一定,並不能完美適配。

寫這個文章的時候只是接觸到目前的主流手機,所以對於如下關系是適用的,但是最近接觸到電視適配之后,MD我寫的這是什么鬼==。。。。當然對於平板也不適用,所以下面的內容參考參考還可以

ldpi   1dp = 0.75px    320*240      
mdpi   1dp = 1px       480*320     
hdpi   1dp = 1.5px     800*480      
xhdpi  1dp = 2px       1280*720    
xxhdpi 1dp = 3px      1920*1080 



 

1.先說要怎么做,后面在慢慢講解:

1.單位全部用dp,優先使用包裹內容和填充父窗體和權重來完成布局。

2.通過dimens文件來適配,需要三套,不考慮橫屏

  2.1 默認的dimens.xml       放按hdpi適配的參數;

  2.2 hdpi的dimens.xml      放按hdpi適配的參數;

  2.3 xhdpi的dimens.xml    放按xhdpi適配的參數;

3.適配的時候只用完美的完成一套xhdpi的dimens文件,然后通過代碼生成hdpi的,因為就dp來說,他們有固定的比例關系,代碼后面會貼出。

 

2.現在來講解為什么要放這三套:

貼一個基本知識:(僅對於一般手機來說)

ldpi   1dp = 0.75px    320*240      160dp = 120px
mdpi   1dp = 1px       480*320      160dp = 160px
hdpi   1dp = 1.5px     800*480      160dp = 240px
xhdpi  1dp = 2px       1280*720    160dp = 320px<360px      180dp = 360px
xxhdpi 1dp = 3px      1920*1080 160dp = 480px  <  540px     180dp = 540px 
 

這三套其實按內容來說就兩種,為什么這兩種可以適配hdpi,xhdpi和xxhdpi呢?

ldpi,mdpi,hdpi是一組;xhdpi和xxhdpi是一組;
從上面貼出的基本知識可以看出,160dp在ldpi,mdpi,hdpi三種下,都是屏幕寬度的一半,也就是說以dp為單位的話,在這三種分辨率下,屏幕的顯示效果是一樣的;但是高度是不一樣的,一半分別是213dp,240dp,267dp;我們適配的時候沒有適配ldpi和mdpi的;
               180dp在xhdpi和xxhdpi下的效果是一樣的,道理同上。而且寬高都成比例。
 

那么兩種類型的dimens就可以了,為什么要用三套,為什么默認的dimens要是hdpi的?

先說測試結果:

1.沒有ldpi和mdpi對應的dimens.xml的情況下:會加載默認的dimens.xml

2.而hdpi,xhdpi,xxhdpi這三種會加載最近的dimens.xml文件

下面是測試過程:

我的測試dimens:

--默認的dimens.xml

<resources>
    <dimen name="activity_horizontal_margin">5dp</dimen>
    <dimen name="activity_vertical_margin">5dp</dimen>
</resources>

--hdpi的dimens.xml:

<resources>
    <dimen name="activity_horizontal_margin">50dp</dimen>
    <dimen name="activity_vertical_margin">50dp</dimen>
</resources>

--xhdpi的dimens.xml:

<resources>
    <dimen name="activity_horizontal_margin">500dp</dimen>
    <dimen name="activity_vertical_margin">100dp</dimen>
</resources>

測試布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <TextView
        android:layout_centerInParent="true"
        android:background="#000000"
        android:layout_width="@dimen/activity_horizontal_margin"
        android:layout_height="@dimen/activity_vertical_margin"/>

</RelativeLayout>

在不同分辨率手機下的效果:(為了好看一些,圖片大小被我拉伸過),下面依次為:ldpi,mdpi,hdpi,hdpi(刪除hdpi對應的dimens之后),xhdpi,xxhdpi

           (ldpi)                                        (mdpi)   

             (hdpi)                              hdpi(刪除hdpi對應的dimens之后)    

         (xhdpi)                                      (xxhdpi)

分析結果:

1.ldpi和mdpi在沒有對應的dimens的情況下,會去加載默認的dimens。而ldpi和mdpi和hdpi可以共用一套。 所以默認的dimens放hdpi的標准。

2.hdpi,xhdpi,xxhdpi會加載最近的dimens文件,所以刪除hdpi對應的之后,加載了xhdpi的dimens。      所以要放一套hdpi的dimens。

3.xhdpi和xxhdpi用的一套標准,他們又會加載最近的。                                                                     所以要放一套xhdpi的。

 

3.關於圖片的適配

也是分兩種考慮

1.大圖且內容復雜的   2.小圖和大圖但是內容簡單的

有上面貼出的基本知識可算出,ldpi,mdpi和hdpi的寬縮放比例是一樣的;xhdpi和xxhpdi的長寬是一樣的。

 

所以關於圖片部分的解決方案就是:

1.小圖和大圖但是內容簡單的:

    我們就把圖片的控件寫死,讓圖片的xy適配控件,發生變形。 只用切一套圖,這樣圖片會有拉伸的情況出現,但是大圖但是比如純色的,拉伸也看不出來,小圖拉伸也不明顯。所以就這樣做。

 

  所以小圖或大圖且內容簡單的解決方案就是,寫死控件,讓圖片的xy適配控件。

2.大圖且內容復雜的:        

    這種圖片拉伸變形明顯,所以我們要針對不同分辨率做處理:

         其中xhdpi(1280*720)和xxhdpi(1920*1080)他們的長寬縮放是成比例的,都是1.5。所以他們可以共用一套圖片。放在xhdpi對應的drawable目錄下或者xxhdpi對應的drawable目錄下即可。

           hdpi,mdpi,ldpi,是不成比例的,所以要想獲得最佳的適配效果,我們需要分別適配這三套,但是我覺得按現在市場是的手機情況,我們在適配一下hdpi就可以了。

    所以大圖且復雜的解決方案就是,適配兩套,xhdpi的和hdpi的。

 

(ps:這里討論的是app原生布局的適配,所以不適用於填充的圖片是動態變化的且長寬不成比例的情況,比如,用戶上傳圖片,這里為健壯還要做很多處理,不在討論的范圍內)

4.最后大概講講現有的適配方案

除了用dimens適配還有用layout布局文件適配的方案,通過代碼動態設置的方案(我之前啟動界面用過一個gif圖片 ,就用的動態設置)

 

5.附上dimens轉換的代碼

對於px,dp,sp,dimens,權重這些基本概念我就不在這里一一介紹了。

轉換dimens的代碼:old放的是適配xhdpi的,

轉換比例:

水平:是xhdpi屏幕寬的一半是180dp除以hdpi屏幕寬的一半是160dp得到的1.125.

豎直:是........................320dp...................................367dp得到的1.1985

 

這樣的話只要完美適配一套xhdpi的,然后生成hdpi的就好了。

你需要區分你布局中寫的參數是水平方向的,還是豎直方向的,下面代碼中changes是轉換因子,轉換兩次,水平一次,豎直一次,自己替換轉換因子;

package convert;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class DimensTools {
     static String oldFilePath = "src/convert/dimens.xml";
     
     static String filePathHdpi="src/convert/dimensHdpi.xml";
     
  
     static float changes = 1.125f;
     public static void main(String[] args) {
          String st = convertStreamToString(oldFilePath, changes);
          DeleteFolder(filePathHdpi);
          writeFile(filePathHdpi, st);
     }
     public static String convertStreamToString(String filepath, float f) {
          StringBuilder sb = new StringBuilder();
          try {
               BufferedReader bf = new BufferedReader(new FileReader(filepath));
               String line = null;
               System.out.println("q1");
               String endmark = "dp</dimen>";
               String startmark = ">";
               while ((line = bf.readLine()) != null) {
                    if (line.contains(endmark)) {
                         int end = line.lastIndexOf(endmark);
                         int start = line.indexOf(startmark);
                         String stdp = line.substring(start + 1, end);
                         //int dp = Integer.parseInt(stpx);
                         float dp=Float.parseFloat(stdp);
                         //float newdp =  ((float) dp / f);
                         
                         System.out.println("dp:"+dp);
                         
                         float newdp=dp/f;
                         
                         System.out.println("newdp:"+newdp);
                         
                         String dpStr=String.valueOf(dp);
                         String newline;
                         if(dpStr.contains(".0")){
                             int x=dpStr.indexOf(".");
                             System.out.println("x:"+x);
                             dpStr= dpStr.substring(0,x);
                             newline= line.replace(dpStr + "dp", newdp + "dp");
                         }else{
                             newline = line.replace(dp + "dp", newdp + "dp");
                         }
                         
                         System.out.println("newline:"+newline);
                         sb.append(newline + "\r\n");
                    } else {
                         sb.append(line + "\r\n");
                    }
               }
              // System.out.println(sb.toString());
          } catch (IOException e) {
               e.printStackTrace();
          }
          return sb.toString();
     }
     public static boolean DeleteFolder(String sPath) {
          File file = new File(sPath);
          if (!file.exists()) { 
               return true;
          } else {
               if (file.isFile()) { 
                    return deleteFile(sPath);
               } else { 
               // return deleteDirectory(sPath);
               }
          }
          return false;
     }
     public static void writeFile(String filepath, String st) {
          try {
               FileWriter fw = new FileWriter(filepath);
               BufferedWriter bw = new BufferedWriter(fw);
               bw.write(st);
               bw.flush();
               bw.close();
          } catch (IOException e) {
               e.printStackTrace();
          }
     }
     public static boolean deleteFile(String sPath) {
          boolean flag = false;
          File file = new File(sPath);
          if (file.isFile() && file.exists()) {
               file.delete();
               flag = true;
          }
          return flag;
     }
}

 

補充:有人問到美工怎么出視覺規范,給android出一套xhdpi的就行,單位用px標。自己按上面的基礎知識,轉成xhdpi的dp單位。最后用代碼自動生成hdpi的一套就好了。 

 

最后,我也是自己摸索,有什么問題,還望大家指點。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM