Android屏幕適配方式探索

基本定義

屏幕尺寸L

例子:華為P10(VTR-AL00/全網(wǎng)通)這臺(tái)手機(jī)的尺寸為5.1英寸
含義:手機(jī)對(duì)角線的物理尺寸
單位:英寸(inch)日矫,1英寸=2.54cm

屏幕分辨率W*H

例子:華為P10(VTR-AL00/全網(wǎng)通)的屏幕分辨率為1920x1080像素,即寬度方向上均勻填充1080個(gè)像素點(diǎn)盈魁,在高度方向上均勻填充1920個(gè)像素
含義:手機(jī)在橫向、縱向上的像素點(diǎn)數(shù)總和
一般描述成屏幕的"寬x高”=AxB赤套,屏幕在橫向方向(寬度)上有A個(gè)像素點(diǎn)珊膜,在縱向方向(高)有B個(gè)像素點(diǎn)
單位:px(pixel),UI設(shè)計(jì)師的設(shè)計(jì)圖會(huì)以px作為統(tǒng)一的計(jì)量單位

屏幕像素密度 dpi

含義:每英寸的像素點(diǎn)數(shù)
單位:dpi(dots per ich)
假設(shè)設(shè)備內(nèi)每英寸有160個(gè)像素剔氏,那么該設(shè)備的屏幕像素密度=160dpi

密度無(wú)關(guān)像素dp

含義:density-independent pixel谈跛,叫dp或dip塑陵,與終端上的實(shí)際物理像素點(diǎn)無(wú)關(guān)。
單位:dp阻桅,可以保證在不同屏幕像素密度的設(shè)備上顯示相同的效果
Android開(kāi)發(fā)時(shí)用dp而不是px單位設(shè)置圖片大小,是Android特有的單位
場(chǎng)景:假如同樣都是畫一條長(zhǎng)度是屏幕一半的線稽寒,如果使用px作為計(jì)量單位输瓜,那么在480x800分辨率手機(jī)上設(shè)置應(yīng)為240px;在320x480的手機(jī)上 應(yīng)設(shè)置為160px搔啊,二者設(shè)置就不同了北戏;如果使用dp為單位,在這兩種分辨率下旧蛾,160dp都顯示為屏幕一半的長(zhǎng)度蠕嫁。

dp與px的轉(zhuǎn)換 px = density * dp ,density = dpi / 160

在Android中病袄,規(guī)定以160dpi(即屏幕分辨率為320x480)為基準(zhǔn):1dp=1px = 1px/density = 1px * 160 / dpi

屏幕尺寸益缠、分辨率基公、像素密度三者關(guān)系

dpi = sqrt(W的平方+H的平方) / L = 對(duì)角線像素個(gè)數(shù) / 對(duì)角線物理尺寸 = 一英寸的屏幕長(zhǎng)度里填充了多少個(gè)像素點(diǎn)
density = dpi / 160 = 一英寸的屏幕長(zhǎng)度里填充了多少個(gè)像素點(diǎn) 乘以 一個(gè)固定常數(shù)
所以對(duì)于每臺(tái)手機(jī)來(lái)說(shuō),density值是有固定的物理意義的

探索方案

理解了上述定義胰伍,我們?cè)偻驴矗?/p>

約定設(shè)計(jì)規(guī)則

在屏幕適配的問(wèn)題上喇辽,首先要確保設(shè)計(jì)稿是按照一個(gè)恒定標(biāo)準(zhǔn)輸出的

比如按照一臺(tái)屏幕寬高比為16:9雨席,屏幕分辨率為1920*1080,density = 3的手機(jī)去設(shè)計(jì)UI
px = density * dp 抽米,由于規(guī)則恒定,我們可以根據(jù)設(shè)計(jì)稿給定的尺寸(像素)轉(zhuǎn)化為(密度無(wú)關(guān)像素dp)

我們可得知設(shè)計(jì)稿期望的是一個(gè)360dp(DESIGN_WIDTH)*640dp(DESIGN_HEIGHT)的畫布(屏幕分辨率除以density即為像素與dp的換算結(jié)果)

具體適配工作

故適配工作就變成了我們要盡可能的將屏幕在寬度上的像素點(diǎn)分為360組是目,在高度上的像素點(diǎn)分為640組懊纳,每組計(jì)為一個(gè)dp,則適配者需要的做的就是改變系統(tǒng)的density值使px 與 dp 的換算比例發(fā)生變化嗤疯,最終實(shí)現(xiàn)按照期望分組的愿望,density對(duì)于寬度與高度的像素轉(zhuǎn)化關(guān)系是共用的茂缚,故對(duì)于16:9的機(jī)型下述兩種方式都能得到期望的density值
density = W/ DESIGN_WIDTH
density = H / DESIGN_HEIGHT

不同屏幕寬高比所面臨的問(wèn)題

但這個(gè)愿望能實(shí)現(xiàn)的基礎(chǔ)是屏幕的像素寬高比是16:9(640:360)屋谭,對(duì)于大于或小于16:9的機(jī)型會(huì)出現(xiàn)什么問(wèn)題呢?
當(dāng)我們處理一個(gè)屏幕分辨率比值大于16:9的機(jī)型時(shí)桐磁,
如18:9(2340 1080)的機(jī)型時(shí)我擂,
按照寬度的分辨率改變density的值,則
density = W / DESIGN_WIDTH = 3
此時(shí)density的改變會(huì)影響H(屏幕寬度)的像素分組
分組結(jié)果為 H / density = 2340 / 3 = 780dp
該結(jié)果大于我們期望的640dp,此時(shí)會(huì)造成設(shè)計(jì)稿只占用了屏幕寬度分組總數(shù)720組的640組像素郎任,使得80dp的空間為空白
按照高度的分辨率改變density的值
density = 2340 / 6440 = 3.65625
此時(shí)density的改變會(huì)影響W(屏幕寬度)的像素分組
分組結(jié)果為 W / density = 1080 / 3.65625 = 295.38dp
則此時(shí)會(huì)造成設(shè)計(jì)稿占用了屏幕寬度分組總數(shù)295.38組的360組像素舶治,使得部分設(shè)計(jì)稿的視圖不足以展示在屏幕內(nèi)而被遮擋顯示不全

當(dāng)我們處理一個(gè)比值小于 16:9的機(jī)型時(shí)同理霉猛,若按照寬度的分辨率去改變density的值,則會(huì)使高度方向的設(shè)計(jì)內(nèi)容有一部分被遮擋惜浅,
若按照高度的分辨率去改變density的值,則會(huì)使寬度方向的設(shè)計(jì)內(nèi)容展示完全后有一部分空白

適應(yīng)場(chǎng)景

故針對(duì)此方案承绸,需要根據(jù)實(shí)際設(shè)計(jì)需求挣轨,區(qū)分對(duì)當(dāng)前activity來(lái)說(shuō),是寬度優(yōu)先還是高度優(yōu)先

代碼實(shí)現(xiàn)

kotlin實(shí)現(xiàn)的工具類如下

...
/**
* description :Android屏幕適配方式 按照設(shè)計(jì)稿寬度為360dp*640dp處理
* 解決問(wèn)題場(chǎng)景:假設(shè)UI設(shè)計(jì)圖按屏幕寬度360dp設(shè)計(jì)荡澎,在一個(gè)1920*1080摩幔、屏幕尺寸為5的手機(jī)上抖甘,
* dpi為440(sqrt(寬的平方+高的平方)/尺寸)衔彻,屏幕寬度其實(shí)為1080/(440/160)=392.7dp
* 此時(shí)屏幕是比設(shè)計(jì)圖要寬的,故此時(shí)在布局文件中使用dp也無(wú)法在不同設(shè)備上顯示為同樣效果澄港,同時(shí)還存在部分設(shè)備屏幕寬度不足360dp導(dǎo)致實(shí)際顯示不全的情況
* Created by Wangpeng  on 2019-11-27
*/
private var sSysDensity: Float =0f
private var sSysScaledDensity: Float =0f
private val DESIGN_WIDTH =360
private val DESIGN_HEIGHT =640
// 在Android中回梧,規(guī)定以160dpi(即屏幕分辨率為320x480)為基準(zhǔn):1dp=1px
private val ANDROID_DESIGN_STANTARD =160
/**
* 只關(guān)注寬度的精確適配
*/
fun setCustomDensitySuitWidth(activity: Activity, application: Application) {
  setCustomDensity(activity, application, true)
}
/**
* 只關(guān)注高度的精確適配
*/
fun setCustomDensitySuitHeight(activity: Activity, application: Application) {
  setCustomDensity(activity, application, false)
}

private fun setCustomDensity(activity: Activity, application: Application, isSuitWidth: Boolean) {
  val appDisplayMetrics = application.resources.displayMetrics
  if (sSysDensity ==0f) {
  sSysDensity = appDisplayMetrics.density
  sSysScaledDensity = appDisplayMetrics.scaledDensity
  // 監(jiān)聽(tīng)系統(tǒng)字體變化
  application.registerComponentCallbacks(object : ComponentCallbacks {
    override fun onConfigurationChanged(newConfig: Configuration?) {
      if (newConfig !=null &&newConfig.fontScale >0) {
        sSysScaledDensity = application.resources.displayMetrics.scaledDensity
      }
    }
    override fun onLowMemory() {}
    })
  }
  // 設(shè)計(jì)稿寬度為360dp,高度為640dp狱意,屏幕寬度(像素為單位)除以設(shè)計(jì)稿寬度(dp為單位) 可以得到實(shí)際需要的density
  var targetDensity =if (isSuitWidth) {
    (appDisplayMetrics.widthPixels /DESIGN_WIDTH).toFloat()
  }else {
    (appDisplayMetrics.heightPixels /DESIGN_HEIGHT).toFloat()
  }
  val targetScaleDensity = targetDensity * (sSysScaledDensity /sSysDensity)
  val targetDensityDpi = (ANDROID_DESIGN_STANTARD * targetDensity).toInt()
  appDisplayMetrics.density = targetDensity
  appDisplayMetrics.scaledDensity = targetScaleDensity
  appDisplayMetrics.densityDpi = targetDensityDpi
  val atyDisplayMetrics = activity.resources.displayMetrics
  atyDisplayMetrics.density = targetDensity
  atyDisplayMetrics.scaledDensity = targetScaleDensity
  atyDisplayMetrics.densityDpi = targetDensityDpi
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末详囤,一起剝皮案震驚了整個(gè)濱河市藏姐,隨后出現(xiàn)的幾起案子羔杨,更是在濱河造成了極大的恐慌,老刑警劉巖兜材,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件护姆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡秩铆,警方通過(guò)查閱死者的電腦和手機(jī)殴玛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門滚粟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凡壤,“玉大人耙替,你說(shuō)我怎么就攤上這事∠趵茫” “怎么了铜幽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵狮杨,是天一觀的道長(zhǎng)到忽。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么陷遮? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮垦江,結(jié)果婚禮上帽馋,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好绽族,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布姨涡。 她就那樣靜靜地躺著,像睡著了一般吧慢。 火紅的嫁衣襯著肌膚如雪涛漂。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天检诗,我揣著相機(jī)與錄音匈仗,去河邊找鬼。 笑死逢慌,一個(gè)胖子當(dāng)著我的面吹牛悠轩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播攻泼,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼音比!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起骚亿,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤震鹉,失蹤者是張志新(化名)和其女友劉穎迎膜,沒(méi)想到半個(gè)月后珊豹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體店茶,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡段直,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年喧务,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了功茴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尘应,到底是詐尸還是另有隱情,我是刑警寧澤玷犹,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響肺魁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贷痪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一舱沧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧牵寺,春花似錦、人聲如沸杏节。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至升略,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間翰撑,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工球拦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弯屈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345