摘要:需要注意的是,這種通過限定符分辨屏幕尺寸的方法,適用于之前。這種最小寬度限定符適用于之后,所以如果要適配全部的版本,就要使用限定符和文件同時存在于項目目錄下。
1.屏幕適配概念
而隨著支持Android系統的設備(手機、平板、電視、手表)的增多,設備碎片化、品牌碎片化、系統碎片化、傳感器碎片化和屏幕碎片化的程度也在不斷地加深。而我們今天要探討的,則是對我們開發影響比較大的——屏幕的碎片化。
下面這張圖是Android屏幕尺寸的示意圖,在這張圖里面,藍色矩形的大小代表不同尺寸,顏色深淺則代表所占百分比的大小。
下面是IOS的
通過對比可以很明顯知道adnroid的屏幕到底有多少種了吧。而蘋果只有5種包括現在最新的劉海屏
那么想要對屏幕適配的相關處理方案有一定的自己的心得,那么首先我們需要了解關于android屏幕的一定基礎
1.屏幕適配基礎那么下面是我給大家寫的一個屏幕適配基礎的思維導圖,基本為一個基礎篇的大綱,這里我不會在課上非常詳細的給大家去過,就全部體現在簡書當中
那么屏幕適配相關概念上我們需要掌握最基礎的3點
那么相對基礎的內容是給段位比較低的同學,高段位可選擇跳過
屏幕尺寸指的是:
分辨率:
屏幕像素密度(DPI
指每一英寸長度中,可顯示輸出的像素個數,
DPI的數字受屏幕尺寸和分辨率所影響,DPI可以通過計算所得
上述內容在于掃盲..畢竟還是有不清楚的同學,而DPI跟下面內容結合比較密切所以啰嗦了兩句
2.什么是dp,dip,sp,px?它們之間的關系?px:構成圖像的最小單位
dip(重點):Desity Independent pixels的縮寫,即密度無關像素
android內部在識別圖像像素時以160dpi為基準,1dip=1px或1dp=1px
例:在下列兩臺設備上使用DP進行操作
480 * 320 160dpi 那么這臺機器上的1DP會被翻譯成1px
800 * 480 240dpi 而這臺機器上的1DP會被翻譯成1.5px
也就是說當前我們設備的DP是由android給予的基礎標準按比例進行翻譯的,這也是為什么我們用DP能解決一部分適配的原因
名稱 像素密度范圍 圖片大小 mdpi 120dp~160dp 48×48px hdpi 160dp~240dp 72×72px xhdpi 240dp~320dp 96×96px xxhdpi 320dp~480dp 144×144px xxxhdpi 480dp~640dp 192×192px
在Google官方開發文檔中,說明了 mdpi:hdpi:xhdpi:xxhdpi:xxxhdpi=2:3:4:6:8 的尺寸比例進行縮放。例如,一個圖標的大小為48×48dp,表示在mdpi上,實際大小為48×48px,在hdpi像素密度上,實際尺寸為mdpi上的1.5倍,即72×72px,以此類推,可以繼續往后增加,不過一般情況下已經夠用了,這種用來去適配手機和平板之間的圖形問題
2.屏幕適配基礎篇(常識,見思維導圖,這里只詳細講一下限定符)2.1使用 "wrap_content" 和 "match_parent"
2.2相對布局控制屏幕
2.3. .9圖的應用
上面三個都是最基本的android使用,我們只需要在平常應用是注意到就行了,這里不詳細去講
我們在做屏幕的適配時在屏幕 尺寸相差不大的情況下,dp可以使不同分辨率的設備上展示效果相似。但是在屏幕尺寸相差比較大的情況下(平板),dp就失去了這種效果。所以需要以下的限定符來約束,采用多套布局,數值等方式來適配。
那么其實所謂的限定符就是android在進行資源加載的時候會按照屏幕的相關信息對文件夾對應的名字進行識別,而這些特殊名字就是我們的限定符
限定符分類: 屏幕尺寸 small 小屏幕 normal 基準屏幕 large 大屏幕 xlarge 超大屏幕 屏幕密度 ldpi <=120dpi mdpi <= 160dpi hdpi <= 240dpi xhdpi <= 320dpi xxhdpi <= 480dpi xxhdpi <= 640dpi(只用來存放icon) nodpi 與屏幕密度無關的資源.系統不會針對屏幕密度對其中資源進行壓縮或者拉伸 tvdpi 介于mdpi與hdpi之間,特定針對213dpi,專門為電視準備的,手機應用開發不需要關心這個密度值. 屏幕方向 land 橫向 port 縱向 屏幕寬高比 long 比標準屏幕寬高比明顯的高或者寬的這樣屏幕 notlong 和標準屏幕配置一樣的屏幕寬高比2.4.1使用尺寸限定符:
當我們要在大屏幕上顯示不同的布局,就要使用large限定符。例如,在寬的屏幕左邊顯示列表右邊顯示列表項的詳細信息,在一般寬度的屏幕只顯示列表,不顯示列表項的詳細信息,我們就可以使用large限定符。
res/layout/main.xml 單面板:
res/layout-large/main.xml 雙面板:
如果這個程序運行在屏幕尺寸大于7inch的設備上,系統就會加載res/layout-large/main.xml 而不是res/layout/main.xml,在小于7inch的設備上就會加載res/layout/main.xml。
需要注意的是,這種通過large限定符分辨屏幕尺寸的方法,適用于android3.2之前。在android3.2之后,為了更精確地分辨屏幕尺寸大小,Google推出了最小寬度限定符。
2.4.2使用最小寬度限定符最小寬度限定符的使用和large基本一致,只是使用了具體的寬度限定。
res/layout/main.xml,單面板(默認)布局:
res/layout-sw600dp/main.xml,雙面板布局: Small Width 最小寬度
這種方式是不區分屏幕方向的。這種最小寬度限定符適用于android3.2之后,所以如果要適配android全部的版本,就要使用large限定符和sw600dp文件同時存在于項目res目錄下。
這就要求我們維護兩個相同功能的文件。為了避免繁瑣操作,我們就要使用布局別名。
2.4.3使用布局別名
res/layout/main.xml: 單面板布局
res/layout-large/main.xml: 多面板布局
res/layout-sw600dp/main.xml: 多面板布局
由于后兩個文具文件一樣,我們可以用以下兩個文件代替上面三個布局文件:
res/layout/main.xml 單面板布局
res/layout/main_twopanes.xml 雙面板布局
然后在res下建立
res/values/layout.xml、
res/values-large/layout.xml、
res/values-sw600dp/layout.xml三個文件。
默認布局
res/values/layout.xml:
- @layout/main
Android3.2之前的平板布局
res/values-large/layout.xml:
- @layout/main_twopanes
Android3.2之后的平板布局
res/values-sw600dp/layout.xml:
- @layout/main_twopanes
這樣就有了main為別名的布局。
在activity中setContentView(R.layout.main);
這樣,程序在運行時,就會檢測手機的屏幕大小,如果是平板設備就會加載res/layout/main_twopanes.xml,如果是手機設備,就會加載res/layout/main.xml 。我們就解決了只使用一個布局文件來適配android3.2前后的所有平板設備。
2.4.4使用屏幕方向限定符
如果我們要求給橫屏、豎屏顯示的布局不一樣。就可以使用屏幕方向限定符來實現。
例如,要在平板上實現橫豎屏顯示不用的布局,可以用以下方式實現。
res/values-sw600dp-land/layouts.xml:橫屏
- @layout/main_twopanes
res/values-sw600dp-port/layouts.xml:豎屏、
- @layout/main
那么上述是最基本的屏幕適配的解決方案
這里找到一個神人給官方適配方案做的翻譯推給大家參考
https://blog.csdn.net/wzy_1988/article/details/52932875
基礎篇結束之后,我們市場上最常用的解決方案我給大家總結了兩種
1.通過自定義布局組件來完成
有聽過我公開課的同學應該知道我當時寫了一套,其核心原理是根據一個參照分辨率進行布局,然后再各個機器上提取當前機器分辨率換算出系數之后,然后再通過重新測量的方式來達到適配的效果,這一套方案基本能適用于95以上的機型,那么今天到時候再加上劉海屏的適配就OK了。
下面是代碼,
/** * Created by barry on 2018/6/7. */ public class ScreenAdaptationRelaLayout extends RelativeLayout { public ScreenAdaptationRelaLayout(Context context) { super(context); } public ScreenAdaptationRelaLayout(Context context, AttributeSet attrs) { super(context, attrs); } public ScreenAdaptationRelaLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } static boolean isFlag = true; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if(isFlag){ int count = this.getChildCount(); float scaleX = UIUtils.getInstance(this.getContext()).getHorizontalScaleValue(); float scaleY = UIUtils.getInstance(this.getContext()).getVerticalScaleValue(); Log.i("testbarry","x系數:"+scaleX); Log.i("testbarry","y系數:"+scaleY); for (int i = 0;i < count;i++){ View child = this.getChildAt(i); //代表的是當前空間的所有屬性列表 LayoutParams layoutParams = (LayoutParams) child.getLayoutParams(); layoutParams.width = (int) (layoutParams.width * scaleX); layoutParams.height = (int) (layoutParams.height * scaleY); layoutParams.rightMargin = (int) (layoutParams.rightMargin * scaleX); layoutParams.leftMargin = (int) (layoutParams.leftMargin * scaleX); layoutParams.topMargin = (int) (layoutParams.topMargin * scaleY); layoutParams.bottomMargin = (int) (layoutParams.bottomMargin * scaleY); } isFlag = false; } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } }
public class UIUtils { private Context context; private static UIUtils utils ; public static UIUtils getInstance(Context context){ if(utils == null){ utils = new UIUtils(context); } return utils; } //參照寬高 public final float STANDARD_WIDTH = 720; public final float STANDARD_HEIGHT = 1232; //當前設備實際寬高 public float displayMetricsWidth ; public float displayMetricsHeight ; private final String DIMEN_CLASS = "com.android.internal.R$dimen"; private UIUtils(Context context){ this.context = context; // WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); //加載當前界面信息 DisplayMetrics displayMetrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(displayMetrics); if(displayMetricsWidth == 0.0f || displayMetricsHeight == 0.0f){ //獲取狀態框信息 int systemBarHeight = getValue(context,"system_bar_height",48); if(displayMetrics.widthPixels > displayMetrics.heightPixels){ this.displayMetricsWidth = displayMetrics.heightPixels; this.displayMetricsHeight = displayMetrics.widthPixels - systemBarHeight; }else{ this.displayMetricsWidth = displayMetrics.widthPixels; this.displayMetricsHeight = displayMetrics.heightPixels - systemBarHeight; } } } //對外提供系數 public float getHorizontalScaleValue(){ return displayMetricsWidth / STANDARD_WIDTH; } public float getVerticalScaleValue(){ Log.i("testbarry","displayMetricsHeight:"+displayMetricsHeight); return displayMetricsHeight / STANDARD_HEIGHT; } public int getValue(Context context,String systemid,int defValue) { try { Class> clazz = Class.forName(DIMEN_CLASS); Object r = clazz.newInstance(); Field field = clazz.getField(systemid); int x = (int) field.get(r); return context.getResources().getDimensionPixelOffset(x); } catch (Exception e) { return defValue; } }
}
2.給各個分辨率多帶帶適配,res,dimens里設置各個對應的px,再統一調用,由系統篩選。這種方式比較久遠了,但是確實還是有很多項目在使用到這種方式
其原理就是據設備屏幕的分辨率各自寫一套dimens.xml文件,然后根據一個基準分辨率(例如720x1080),將寬度分成720份,取值為1px——720px,將高度分成1080份,取值為1px——1080px。生成各自dimens.xml文件對應的值。
但是今天我根據這個方法,在這個方案的基礎之上給大家做了一次改變,運用之前所見的DP的概念,結合之前講的限定符,用DP來升級了這種方案,dp適配原理與px適配一樣,區別就在于px適配是根據屏幕分辨率,即拿px值等比例縮放,而dp適配是拿dp值來等比縮放而已。
既然原理都一樣,都需要多套dimens.xml文件,為什么說dp適配就比px適配好呢?
因為px適配是根據屏幕分辨率的,Android設備分辨率一大堆,而且還要考慮虛擬鍵盤。而dp適配無論手機屏幕的像素多少,密度比值多少,80%的手機的最小寬度dp值(widthPixels / density)都為360dp,這樣就大大減少了dimens.xml文件
PS:(現在基本上手機的dpi都在350+以上 那么按最低算 350/160=2.1 那么360 2.1 = 720+ 基本上手機的分辨率都會在360dp之內 上面例子19201080的情況 500/160=3.125 那么 360*3.125=1125其實也在360之內)
那么傳統做法:
改良后的做法:
獲取最小寬度獲取如下:
DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); int widthPixels = dm.widthPixels; float density = dm.density; float widthDP = widthPixels / density;
所以通過這種兩種形式的結合能夠達到我們整體適配任意機型的目的
作者:Barry
原文鏈接:https://www.jianshu.com/p/0586c7e7e212
閱讀更多
適配不同尺寸屏幕,自動拉伸位圖9.圖片的使用|處理
適配不同尺寸屏幕幾個關鍵點分享
屏幕適配之尺寸的相關概論《一》
2018 Android面試心得,已拿到offer
2018 Android面試心得,已拿到offer
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71496.html
摘要:下圖為圖標的各個屏幕密度的對應尺寸屏幕密度圖標尺寸解析解析獲取屏幕分辨率信息的三種方法第一種第二種第三種屏幕適配出現的原因什么是像素點屏幕分辨率是指在橫縱向上的像素點數,單位是,個像素點。 目錄介紹 1.屏幕適配定義 2.相關重要的概念 2.1 屏幕尺寸[物理尺寸] 2.2 屏幕分辨率[px] 2.3 屏幕像素密度[dpi] 2.4 dp、dip、dpi、sp、px 2.5 md...
摘要:下圖為圖標的各個屏幕密度的對應尺寸屏幕密度圖標尺寸解析解析獲取屏幕分辨率信息的三種方法第一種第二種第三種屏幕適配出現的原因什么是像素點屏幕分辨率是指在橫縱向上的像素點數,單位是,個像素點。 目錄介紹 1.屏幕適配定義 2.相關重要的概念 2.1 屏幕尺寸[物理尺寸] 2.2 屏幕分辨率[px] 2.3 屏幕像素密度[dpi] 2.4 dp、dip、dpi、sp、px 2.5 md...
閱讀 1534·2023-04-26 02:50
閱讀 3535·2023-04-26 00:28
閱讀 1931·2023-04-25 15:18
閱讀 3209·2021-11-24 10:31
閱讀 986·2019-08-30 13:00
閱讀 1000·2019-08-29 15:19
閱讀 1766·2019-08-29 13:09
閱讀 2975·2019-08-29 13:06