導航:首頁 > 操作系統 > android百分比適配

android百分比適配

發布時間:2023-04-05 15:06:04

『壹』 android 屏幕解析度適配

Android屏幕解析度千奇百怪,怎麼讓app在不同的解析度的設備上「看起來一樣」呢?
你也許還有以下疑惑:

這篇文章將會針對以上問題一一解答。

Pixels 我們看到屏幕上的圖像由一個個像素組成,像素里包含色彩信息。
如常說的手機解析度:1080 x 1920 指的是手機寬度可展示1080像素,高度可展示1920像素。

Pixels Per Inch 每英寸長度所具有的像素個數,單位面積內像素越多,圖像顯示越清晰。
ppi一般用在顯示器、手機、平板等描述屏幕精細度。

Dots Per Inch 每英寸長度所具有的點數。
dpi一般用來描述列印(書本、雜志、電報)的精細度

density-independent pixels (device-independent pixels 我查了一下,官網更多時候使用前者,有的時候也顯示後者),dip是縮寫,也可以更簡單些稱作dp。該單位的目的是屏蔽不同設備密度差異,後面細說。

Scalable pixels 用於設置字體,在用戶更改字體大小時候會適配。

澄清了基本概念,我們現在從一個例子開始說明以上單位之間的區別與聯系。

布局文件里有個View,長寬都是200px,分別在解析度為480(寬)x800(高)簡稱A設備、1080(寬)x1920(高)簡稱B設備,效果如下:

左邊是A設備,右邊是B設備。問題出來了,同樣長寬都是200px,為啥A設備顯示很大,B設備顯示很小呢?你可能會說B設備的橫向解析度1080比A設備的480大,所以在B設備上看起來比較小。來看看A、B設備橫向到底是多少英寸,怎麼來計算呢?這時候就需要用到ppi了,既然知道橫向的像素點個數,也知道每英寸能容納的像素點,當然可以得知橫向的尺寸了。

其中一種方式獲取DisplayMetrics對象:

A設備寬度尺寸:480(px)/240(ppi)=2inch
B設備寬度尺寸:1080(px)/420(ppi)=2.5inch
可以看出,A、B設備尺寸差別不大。A設備ppi=240 B設備ppi=420,明顯地看出B設備單位長度上比A設備能夠容納更多的像素,因此同樣的200px,B設備只需要較小的尺寸就能夠顯示,因此在B設備上的view看起來比A設備小很多。
知道了問題的原因,然而顯示的效果卻不能接受。

我們總不能自己判斷每個設備的ppi,然後計算實際需要多少像素,再動態設置view的大小吧,那layout里的靜態布局大小就無法動態更改適應了。想當然的能有一個統一的地方替我們轉換,沒錯!Android系統已經幫我們實現了轉換。接下來就是dpi、dp出場了。

Android系統使用dpi來描述屏幕的密度,使用dp來描述密度與像素的關系。
A設備dpi=240
B設備dpi=420
Android系統最終識別的單位是px,怎麼將dpi和px關聯起來呢?,答案是dp。
Android規定當dpi=160時,1dp=1px,當dpi=240時,1dp=1.5px,依此類推,並且給各個范圍的dpi取了簡易的名字加以直觀的識別,如120<dpi<=160,稱作為mdpi,120<dpi<=240 稱作hdpi,最終形成如下規則:

現在知道了dp能夠在不同dpi設備上對應不同px,相當於中間轉換層,我們只需要將view長寬單位設置為合適的dp,就無需關注設備之間密度差異,系統會幫我們完成dp-px轉換。將我們之前的例子稍微更改,再看看效果驗證一下:

通過上面對dp的了解,我們知道在設定view大小、間距時使用dp能最大限度地屏蔽設備密度之間的差異。可能你就會問了,那bitmap展示的時候如何適配不同密度的設備呢?

自定義view從磁碟上載入一張圖片,並將之顯示在view上,view的大小決定於bitmap大小。依舊以上述A、B設備為例,展示結果如下:

左邊是A設備,右邊是B設備。
明顯地看出,在A設備顯示比B設備大很多,實際上和我們之前用px來描述view的大小原理是一樣的,bitmap的寬、高都是px在描述,而bitmap決定了view的寬、高,最終導致A設備和B設備上的view大小(寬、高像素)是一樣的,而它們屏幕密度又不相同,因此產生了差異。
那不會每次都需要我們自己根據屏幕密度來轉換bitmap大小吧?幸運的是,Android已經為我們考慮到了。

生成不同密度的目錄有什麼作用?
A設備dpi=240,根據dpi范圍,屬於hdpi
B設備dpi=420,根據dpi范圍,屬於xxhdpi
圖片原始尺寸:photo1.jpg(寬高 172px-172px)
當我們想要在不同密度設備上顯示同一張圖片並且想要「看起來一樣大時」。假設設計的時候以hdpi為准,放置photo1.jpg為172*172,那麼根據計算規則在xxhdpi上需要設置photo1.jpg為:

現在hdpi和xxhdpi目錄下分別存放了同名圖片:photo1.jpg,只是大小不同。當程序運行的時候:

來看看效果:

左邊A設備,右邊B設備
針對不同的密度設計不同的圖片大小,最大限度保證了同一圖片在不同密度設備上表現「看起來差不多大」。
來看看A、B設備上圖片占內存大小:

說明在B設備上顯示photo1.jpg需要更多的內存。
上邊只是列舉了hdpi、xxhdipi,同理對於mdpi、xhdpi、xxxhdpi根據規則放入相應大小的圖片,程序會根據不同的設備密度從對應的mipmap文件夾下載入資源。如此一來,我們無需關注bitmap在不同密度設備上顯示問題了。

在mipmap各個文件夾下都放置同一套資源的不同尺寸文件似乎有點太佔apk大小,能否只放某個密度下圖片,其餘的靠系統自己適配呢?
現在只保留hdpi下的photo1.jpg圖片,看看在A、B設備上運行情況如何:

看起來和上張圖差不多,說明系統會幫我們適配B設備上的圖片。
再來看看A、B設備上圖片占內存大小:
先看A設備:

對比photo1.jpg 分別放在hdpi、xxhdpi和只放在hdpi下可以看出:B設備上圖片所佔內存變小了。為什麼呢?接下來從源碼里尋找答案。

A、B設備同樣載入hdpi/photo1.jpg,返回的bitmap大小不相同,我們從這方法開始一探究竟。

上面涉及到的關鍵點是density,分別是TypedValue的density和Options的density。
先來看看TypedValue density:

再來看看Options density

現在分析B設備載入hdpi/photo1.jpg如何做的:

和我們之前調試的結果一致。

B設備是怎麼決定使用hdpi下的圖片資源呢?
根據實驗(嘗試找了源碼,沒怎麼看懂,因此只是做了實驗,可能在不同密度設備上找尋規則不一樣):B設備先找屬於自己密度范圍文件夾下的圖片,B設備屬於xxhdpi,先查看xxhdpi有沒有photo1.jpg,如果沒有則往更高的密度找,比它高的密度是xxxhdpi,還是沒有,則往低密度找,找xhdpi,沒有再找hdpi,找到了則返回構造好的TypedValue,剩下的就是我們前面分析的。
既然我們只想放某個密度下的一份切圖,該放哪個密度下呢?從系統尋找規則看,更推薦放置在更高密度下的,因為如果放在低密度下,那麼當運行在高密度設備上時,圖片會進行放大,可能導致不清晰。我一般習慣放在xxhdpi下。

Android Studio默認創建了不同密度的mipmap文件夾,默認放置了ic_launcher.png。我們普通的切圖該放drawable還是mipmap下呢?對於這個問題網上也是眾說紛紜,實際上對於我們來說,關注的重點是圖片放在drawable或者mipmap,載入出來bitmap是否有差異,如果沒有差異放在哪就看習慣了。通過實踐,普通的切圖放drawable和mipmap下載入出來的bitmap是沒有差異的,只不過用drawable的話需要自己創建不同密度的文件夾。我習慣於放在drawable下(啟動圖標logo還是放在mipmap下)。

前邊 [注1] 留了個問題,我們使用dp來表示view的大小了,為啥兩個看起來還是有些差距?下面我們更加直觀地看一個例子。
A設備dpi=240 密度1.5 解析度(寬高px):480 * 800
B設備dpi=420 密度2.625 解析度(寬高px):1080 * 1794
換算成dp
A設備解析度:320dp * 533dp
B設備解析度:411dp * 683dp
依舊是上邊的例子:

將view寬高分別設置為320dp,看看效果:

左邊A設備,右邊B設備
可以看出同樣的320dp大小,A設備鋪滿了屏幕,而B設備沒有。這效果顯然是不能接受的,Android考慮到不同設備寬高不同,推出了"寬高限定符"。以A、B設備為例:
在res文件夾下創建文件夾:

假設設計師出圖是按照800x480,那麼我們創建dimen文件的時候

該文件放在values-800x480文件夾下。
根據解析度比例算出1794x1080的dimen值

這樣子,A、B設備載入資源的時候使用對應解析度限定符下的px,如果找不到再找默認值,可以在一定程度上解決屏幕寬高碎片化適配問題。
但是這樣子的限定比較嚴格,需要測試各種解析度,後來Android又推出了"smallest-width"簡稱最小寬度限制。
A設備寬320dp
B設備寬411dp
假設設計師切圖標准屏幕寬是320dp(A設備),那麼可以定義如下dimen.xml文件

該文件放在values-sw320dp文件夾下
根據規則,計算B設備dimen.xml

現在我們繼續來看之前的view

通過對dimen引用,A設備尋找和自己寬度一樣的dimen文件,找到values-sw320dp,dp320=320dp。B設備尋找和自己寬度一樣的dimen文件,找到values-sw411dp,dp320=410dp。這樣子同樣的dp320,得出不同的值,就適配了屏幕寬度不同的問題。
看看效果:

這次B設備也鋪滿了屏寬。

綜上,為了適配不同屏幕大小,推薦使用dp+smallest-width。

獲取設備dpi最終都是從這方法獲取的,實際上就是讀取系統的配置文件。因此我們也可以通過adb shell 獲取:

可以看出dpi是系統配置好的,當然有些手機是可以設置解析度的,設置之後我們查看解析度:

解析度變低了,dpi也變小了。

『貳』 如何添加android百分比布局支持庫

相信大家都已經對Android API所提供的布局方式非常熟悉了。也許在接觸Android的時候都有過這樣的想法,如果可以按照百分比的方式進行界面布局,這樣適配各種屏幕就簡單多了吧!谷歌正式提供百分比布局支持庫(android-support-percent-lib)。當然了android-percent-support這個庫,基本可以解決上述問題,下面我們將對這個支持庫進行介紹
這個庫提供了:
兩種布局供大家使用:
PercentRelativeLayout、PercentFrameLayout,通過名字就可以看出,這是繼承自FrameLayout和RelativeLayout兩個容器類;
支持的屬性有:
layout_widthPercent、layout_heightPercent、
layout_marginPercent、layout_marginLeftPercent、
layout_marginTopPercent、layout_marginRightPercent、
layout_marginBottomPercent、layout_marginStartPercent、layout_marginEndPercent。

『叄』 android屏幕適配

android設備碎片化嚴重,因此在實際開發的時候需要做屏幕適配
適配主要是在以下幾個方面:

常見的布局適配主要是以下幾點:
a.避免寫死布局尺寸,使用wrap_content或者martch_parent
b.使用權重,比如linearlayout中的weight;
c.使用relative的相對位置擺放,比如layout_centerInParent="true"
d.ConstraintLayout 原理類似於relatvie,相對擺放,但是性能相對於relatvie會好一點
e.android官方的庫Percent-support-lib,該庫主要是用的是百分比適配

a. .9圖適配,這個是使用了.9圖可以在特別區域拉伸不失真的特性來適配
b. 使用多套點陣圖,匹配不同的解析度,比如在mipmap,mipmap-xhdpi,mipmap-xxhdpi,等文件夾下面放多套解析度不同的內容相同的圖片

是指同一個業務邏輯,在不同的設備上執行不同的跳轉方式,比如在手機上打開一個新的activity,但是在平板上,可以在橫屏狀態下,右側增加一個fragment,展示打開的頁面。

a.解析度限定符,使用drawable-dpi,drawable-hdpi等
b.尺寸限定符
c.最小寬度限定符
d.屏幕方向限定符

a.android9.0開始 有官方的api進行適配
b.華為,小米,魅族,vivo,oppo各大room廠商有對應的api進行適配

除了以上這些,還有dimens適配,但是都各有缺點,有的需要多套圖,有的需要多套資源文件,dimens適配的dimens文件過多,需要針對不同的屏幕解析度來生成對應的文件,比較繁瑣

以上,實際開發中,做的最多的適配為布局適配

開發中屏幕適配的核心是在於屏幕縮放,不論是哪種屏幕適配,都是以這個縮放為基礎

已知:設計圖手機像素(W,H),設計圖上控制項的像素值(ViewW,ViewH),目標設備解析度(TargetW,TargetH)
求:目標設備上view的寬高(TargetViewW,TargetViewH)
公式:寬:ViewW / W * TargetW=TargetViewW
高:ViewH / H * TargetH =TargetViewH
原理:根據當前設備的解析度,計算出設計圖上的控制項在該設備上的縮放比,然後根據縮放比,來動態的設置view, 最終換算出來的單位為px
該適配方式是通過自定義外部的ViewGroup,比如LinearLayout,RelativeLayout,在onMeasure方法中,遍歷子view,設置寬高以及padding,margin
以下是封裝了一個工具類,用來獲取屏幕寬高以及計算縮放比:

未完待續

『肆』 Android平板應用適配

首先是尺寸的適配,android平板和手機相比,由於pad的大屏特性,屏幕的尺寸和解析度的差別就很明顯,例如以下平板信息:

小米平板:4.4.4 densityDpi:320 size:1536x2048

華為平板:5.1.1 densityDpi:240 size:1200x1920

華為榮耀某平板:6.1 densityDpi:320 size:1200x1920

三星平板:6.0.1 densityDpi:320 size:1600x2560

同樣的一套mdpi下的layout或者values放在上面華為榮耀平板和三星平板上顯示差別就很大。下面是開發中關於設計的一些心得:

1. 開發中保持不增加布局層級的情況下採用百分比weight屬性;針對不同尺寸的設備百分比縮放是體驗最完美的,但由於實際開發中復雜界面如果採用百分比,無疑增加了層級復雜度,反而降低了性能,降低了可維護性和擴展性。

2. layout中使用的dp/sp值採用@dimen引用方式寫進dimens.xml裡面;為了方便採用多個values文件夾例如values-sw600dp,values-1280x720等針對特定屏幕適配。自然也可以採用layout-1280x720這樣的來區分不同布局,但如果只是尺寸上的適配,無疑用dimens維護幾套尺寸值是最容易的,還可以寫個讀寫文件工具,修改一個values里的dimens文件後更新到所有的values文件;

3. 以上面的華為榮耀平板為例,採用sw(smallwidth)的方式進行適配,比較簡單的計算方式,以mdpi(160)為標准,此平板的screenWidthDips = 1200/(320/160) = 600dp,所以values-sw600dp可以適配此平板(有的平板系統寬高是包含屏幕的虛擬按鍵的高度);

4. 為了苛求在不同尺寸平板上的體驗,採用values-1200x1920,values-1600x2560這種方式,即為每個屏幕增加尺寸適配,工作量和效率來說不會影響太大,畢竟可以通過軟體工具生成多套;

除了界面方面,平板開發上的模塊化採用Fragment更多,以及Fragment嵌套Fragment:

5. Fragment中調用startActivityForResult,如果要在Fragment的onActivityResult里回調處理,那麼不要採用getActivity().startActivityForResult方法,且宿主Activity如果重寫了onActivityResult方法的,必須調用super.onActivityResult,否則Fragment的onActivityResult方法不會回調,這點可以從Activity的源碼中看出來;

6. 嵌套在Fragment里的子Fragment的onActivityResult如果需要回調則要自己處理;

7. Fragment嵌套Fragment時,在Fragment里採用getChildFragmentManager()管理子Fragment,用法跟getSupportFragmentManager()一樣;子Fragment之間的通信,可以採用事件匯流排方案進行解耦,例如Otto/EventBus,但可讀性會下降,所以詳細的注釋還是必要的;

閱讀全文

與android百分比適配相關的資料

熱點內容
如何查看電腦系統伺服器ip地址查詢 瀏覽:389
把文件夾設鎖 瀏覽:570
命令行語句 瀏覽:218
企友3e財務如何連接伺服器 瀏覽:984
華為手機如何刪除卸載app殘留數據 瀏覽:543
rpm的命令作用 瀏覽:365
如何查看網站的伺服器時間 瀏覽:850
編譯局和人民出版社 瀏覽:652
java泛型extends 瀏覽:326
頭條程序員教學 瀏覽:772
安卓合並什麼意思 瀏覽:530
linux在光碟引導 瀏覽:537
imap伺服器地址怎麼查 瀏覽:654
作曲教程pdf 瀏覽:506
pr怎麼壓縮文件大小 瀏覽:863
查看oracle字元集命令 瀏覽:179
鋰電池增加密度 瀏覽:661
linux用戶密碼忘記 瀏覽:242
gb壓縮天然氣 瀏覽:635
圖片拼接不壓縮app 瀏覽:670