版權聲明:本文爲HaiyuKing原創文章,轉載請註明出處!html
這裏只是根據參考資料整理下,具體內容請閱讀參考資料。git
推薦1倍效果圖,即採用 720 * 360 大小( 1280 *720:兩倍圖 \ 1920 * 1080: 三倍圖),最主要的緣由就是1px = 1dp,效果圖標多大的px,佈局就寫多大dp。github
1. 每英寸中的像素數(假如設備分辨率爲320*240,屏幕長2英寸寬1.5英寸,dpi=320/2 = 240/1.5 =160)
2. 對應於DisplayMetrics類中屬性densityDpi的值;
3. 固然這種寬和高的dpi都相同的狀況如今已經不多見,因此實際計算方式見下圖;app
像素密度(dpi)、屏幕尺寸、分辨率三者關係:ide
舉例說明:屏幕分辨率爲:1920*1080,屏幕尺寸爲5吋的話,那麼dpi爲440:svg
1. 每平方英寸中的像素數(density = dpi / 160 );
3. 對應於DisplayMetrics類中屬性density的值;
4. 可用於px與px與dip的互相轉換 :dp = px / density ;工具
720P,和1080P的手機,dpi是不一樣的,這也就意味着,不一樣的分辨率中,1dp對應不一樣數量的px(720P中,1dp=2px,1080P中1dp=3px)。佈局
1.不一樣設備有不一樣的顯示效果,不依賴像素(dp = px / density = px / (dpi / 160) )
2.dpi(像素密度)爲160 的設備上1dp = 1px。字體
public class Dp2Px { public static int dp2px(Context context, int dp) { return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5); } public static int px2dp(Context context, int px) { return (int) (px / context.getResources().getDisplayMetrics().density + 0.5); } }
說明:0.5 是爲了不損失精度。this
在AndroidStudio的資源目錄res下有五個層級圖片文件夾,分別用來存放不一樣分辨率的圖片:
在對應的文件夾下放置不一樣分辨率的圖片就能夠很好的對圖片進行適配。
隨着屏幕愈來愈大,推薦xxdpi的一套切圖,這樣就能夠向下和向上兼容,節省資源。
建議圖標使用svg格式,圖片仍然使用png格式,svg的圖標大小約是png的1/4,在很大的項目中,圖標有不少,這個時候svg的優點就凸顯無疑了。
在layout以外,根據不一樣分辨率,建立不一樣的佈局文件夾:
手機會根據分辨率去找設定的不一樣大小的layout的佈局。實際開發中這種使用的狀況很是少,由於佔用太多資源,慎用。
當兩個或者更多佈局佔滿屏幕寬或高的時候,子佈局可使用權重適配,常見於LinearLayout線性佈局中。
詳細內容請閱讀參考資料。如下內容均是引用!
這基本是最原始的Android適配方案。
wrap_content,match_parent,layout_weight等,咱們就要絕不猶豫的使用,並且在高這個維度上,咱們要依照狀況設計爲可滑動的方式,或者match_parent,儘可能不要寫死。總之,全部的適配方案都不是用來取代match_parent,wrap_content的,而是用來完善他們的。
(1)這隻能保證咱們寫出來的界面適配絕大部分手機,部分手機仍然須要單獨適配;
爲何dp只解決了90%的適配問題,由於並非全部的1080P的手機dpi都是480,好比Google 的Pixel2(1920*1080)的dpi是420,也就是說,在Pixel2中,1dp=2.625px,這樣會致使相同分辨率的手機中,這樣,一個100dp*100dp的控件,在通常的1080P手機上,可能都是300px,而Pixel 2 中 ,就只有262.5px,這樣控件的實際大小會有所不一樣。
(2)這種方式沒法快速高效的把設計師的設計稿實現到佈局代碼中,經過dp直接適配,咱們只能讓UI基本適配不一樣的手機,可是在設計圖和UI代碼之間的鴻溝,dp是沒法解決的,由於dp不是真實像素。並且,設計稿的寬高每每和Android的手機真實寬高差異極大,以咱們的設計稿爲例,設計稿的寬高是375px*750px,而真實手機可能廣泛是1080*1920;那麼在平常開發中咱們是怎麼跨過這個鴻溝的呢?基本都是經過百分比啊,或者經過估算,或者設定一個規範值等等。總之,當咱們拿到設計稿的時候,設計稿的ImageView是128px*128px,當咱們在編寫layout文件的時候,卻不能直接寫成128dp*128dp。在把設計稿向UI代碼轉換的過程當中,咱們須要耗費至關的精力去轉換尺寸,這會極大的下降咱們的生產力,拉低開發效率。
根據市面上手機分辨率的佔比分析,咱們選定一個佔比例值大的(好比1280*720)設定爲一個基準,而後其餘分辨率根據這個基準作適配。
基準的意思(好比320*480的分辨率爲基準)是:
寬爲320,將任何分辨率的寬度分爲320份,取值爲x1到x320
長爲480,將任何分辨率的高度分爲480份,取值爲y1到y480
例如對於800 * 480的分辨率設備來說,須要在項目中values-800x480目錄下的dimens.xml文件中的以下設置(固然了,能夠經過工具自動生成):
<?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="x1">1.5px</dimen> <dimen name="x2">3.0px</dimen> <dimen name="x3">4.5px</dimen> <dimen name="x4">6.0px</dimen> <dimen name="x5">7.5px</dimen>
能夠看到x1 = 480 / 基準 = 480 / 320 = 1.5 ;它的意思就是一樣的1px,在320/480分辨率的手機上是1px,在480/800的分辨率的手機上就是1*1.5px,px會根據咱們指定的不一樣values文件夾自動適配爲合適的大小。
第一,Android不一樣分辨率的手機實在太多了,可能你說主流就能夠,的確小公司主流就能夠,淘寶這種App確定不能只適配主流手機。
第二,控件在設計圖上顯示的大小以及控件之間的間隙在小分辨率和大分辨率手機上天壤之別,你會發現大屏幕手機上控件超級大。可能你會以爲正常,畢竟分辨率不一樣。但實際效果大的有些誇張。
第三,設計圖(好比360640)上的內容佔據屏幕的2/3,按照這種適配,特長手機(29601440 S8)上的內容也會佔據2/3,這確定不合理,控件之間的間隙會特別大,一看就不符合設計效果,手機長,內容佔據低於2/3才正常,好比可能佔據1/3.第四,佔據資源大:好幾百KB,甚至多達1M或跟多。
這種適配依據的是最小寬度限定符。指的是Android會識別屏幕可用高度和寬度的最小尺寸的dp值(其實就是手機的寬度值),而後根據識別到的結果去資源文件中尋找對應限定符的文件夾下的資源文件。這種機制和上文提到的寬高限定符適配原理上是同樣的,都是系統經過特定的規則來選擇對應的文件。
舉個例子,小米5的dpi是480,橫向像素是1080px,根據px=dp(dpi/160),橫向的dp值是1080/(480/160),也就是360dp,系統就會去尋找是否存在value-sw360dp的文件夾以及對應的資源文件。
這套方案對老項目是不太友好的,由於修改了系統的density值以後,整個佈局的實際尺寸都會發生改變,若是想要在老項目文件中使用,恐怕整個佈局文件中的尺寸均可能要從新按照設計稿修改一遍才行。所以,若是你是在維護或者改造老項目,使用這套方案就要三思了。
經過修改density值,強行把全部不一樣尺寸分辨率的手機的寬度dp值改爲一個統一的值,這樣就解決了全部的適配問題。
好比,設計稿寬度是360px,那麼開發這邊就會把目標dp值設爲360dp,在不一樣的設備中,動態修改density值,從而保證(手機像素寬度)px/density這個值始終是360dp,這樣的話,就能保證UI在不一樣的設備上表現一致了。
UI設計圖是按屏幕寬度爲360dp來設計的,那麼在上述設備上,屏幕寬度其實爲1080/(440/160)=392.7dp,也就是屏幕是比設計圖要寬的。這種狀況下, 即便使用dp也是沒法在不一樣設備上顯示爲一樣效果的。 同時還存在部分設備屏幕寬度不足360dp,這時就會致使按360dp寬度來開發實際顯示不全。加上16:九、4:3甚至其餘寬高比層出不窮,寬高比不一樣,顯示徹底一致就不可能了。
一般下,咱們只須要以寬或高一個維度去適配,好比咱們Feed是上下滑動的,只須要保證在全部設備中寬的維度上顯示一致便可,再好比一個不支持上下滑動的頁面,那麼須要保證在高這個維度上都顯示一致,尤爲不能存在某些設備上顯示不全的狀況。
今日頭條的適配方式,今日頭條適配方案默認項目中只能以高或寬中的一個做爲基準,進行適配。
px = dp * density(dp是360dp),想要px正好是屏幕寬度的話,只能修改density。
/** * 適配:修改設備密度 */ private static float sNoncompatDensity; private static float sNoncompatScaledDensity; public static void setCustomDensity(@NonNull Activity activity, @NonNull final Application application) { DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics(); if (sNoncompatDensity == 0) { sNoncompatDensity = appDisplayMetrics.density; sNoncompatScaledDensity = appDisplayMetrics.scaledDensity; // 防止系統切換後不起做用 application.registerComponentCallbacks(new ComponentCallbacks() { @Override public void onConfigurationChanged(Configuration newConfig) { if (newConfig != null && newConfig.fontScale > 0) { sNoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity; } } @Override public void onLowMemory() { } }); } float targetDensity = appDisplayMetrics.widthPixels / 360; // 防止字體變小 float targetScaleDensity = targetDensity * (sNoncompatScaledDensity / sNoncompatDensity); int targetDensityDpi = (int) (160 * targetDensity); appDisplayMetrics.density = targetDensity; appDisplayMetrics.scaledDensity = targetScaleDensity; appDisplayMetrics.densityDpi = targetDensityDpi; final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics(); activityDisplayMetrics.density = targetDensity; activityDisplayMetrics.scaledDensity = targetScaleDensity; activityDisplayMetrics.densityDpi = targetDensityDpi; }
只須要在baseActivity中添加一句話便可。適配就是這麼簡單。
DisplayUtil.setCustomDensity(this, getApplication());