-
1.先說要怎么做,后面在慢慢講解:
-
2.現在來講解為什么要放這三套:
-
這三套其實按內容來說就兩種,為什么這兩種可以適配hdpi,xhdpi,xxhdpi呢?
-
那么兩種類型的dimens就可以了,為什么要用三套,為什么默認的dimens要是hdpi的?
-
3.關於圖片的適配
-
4.最后大概講講現有的適配方案
-
5.附上dimens轉換的代碼
dp單位解決的是你所設置的按鈕的實際大小保持穩定,但是設備的物理尺寸不一定,並不能完美適配。
寫這個文章的時候只是接觸到目前的主流手機,所以對於如下關系是適用的,但是最近接觸到電視適配之后,MD我寫的這是什么鬼==。。。。當然對於平板也不適用,所以下面的內容參考參考還可以
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.現在來講解為什么要放這三套:
貼一個基本知識:(僅對於一般手機來說)
這三套其實按內容來說就兩種,為什么這兩種可以適配hdpi,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的一套就好了。
最后,我也是自己摸索,有什么問題,還望大家指點。