Android適配:DP簡述

上一篇文章發到掘金後,發現省略了內容後,居然不少人說看不懂;這就尷尬了。我本來以爲DP這個東西提及來實在布同樣長,並且是入門的東西,不用在討論。但發現不少人對DP適配存在誤區,尤爲還有人任務不一樣設備屏幕像素不同須要適配的問題。因此這裏說一下DP究竟怎麼來的。android

像素(pixel)

先直接看Wiki 像素。簡單說,像素就是表示一個點的RGB顏色;這個點,是數學上的概念,是沒有大小的(回顧一下z初中數學,我沒記錯吧)。就是說,咱們要描述一幅圖像(好比清明上河圖),能夠轉換成X*Y像素的位圖(Bitmap),但轉換後咱們是不知道這個Bitmap原來的物理尺寸,就這樣丟失了。爲何會這樣?由於現實世界是連續的,不可能記錄下來(有限的存儲空間放不下無限量的數據)。Bitmap也是沒有物理大小的。bash

屏幕分辨率

把Bitmap從新表示出來,咱們接觸到最多的就是屏幕和打印了。要展現像素,最簡單的就是在屏幕上取一個點對應一個像素的點就好了。假如把屏幕分爲1080*1920個點,這樣一樣1080*1920像素的Bitmap恰好展現。屏幕上的點雖然對應像素的點,但它是有物理尺寸的(經過屏幕寬高除以份數獲得)。知道了展現規則,雖然像素自己是沒有大小的,但咱們也能夠用像素來表示一個圖形展現時究竟有多大。好比一個字體是16px,這不是說它的物理尺寸有多大,而是它顯示時會佔據多少個點。網絡

體驗問題

屏幕點和像素對應,很長時間內都是這樣過來的,直到後來手機從奢侈品變成日用品再變成消耗品。手機的普及,每一個人成天都抱着手機屏幕盯着看,而後發現了問題:屏幕顆粒看起來太大。屏幕上每英寸上點的數量,咱們叫作DPI(dots per inch,由於屏幕上面每一個點對應一個像素,因此也有叫PPI;二者大部分狀況混用,有時候又不同,能夠參考,不展開討論)。當DPI小的時候,每一個點的物理尺寸就變大(點的大小理解爲 DPI 分之一 英寸;好比DPI是160,每一個點就是 1/160 英寸);因此要解決屏幕顆粒大的問題,提升DPI值就能夠了。但DPI提升後,又出現了另一個問題:一樣像素的Bitmap在新的屏幕上看起來小了。假設把DPI從160提升到320,原來160像素在新屏幕上就只覆蓋了1/4英寸。ide

DP方案

無規矩不成方圓。要完整的解決問題,須要訂立新的標準,不能再讓屏幕點和像素一一對應了。這裏是屏幕展現大小,爲何咱們不直接以尺寸爲標準呢?簡單粗暴直接規定一英寸就是160dp,若是是160dpi的設備,1dp對應一個點(像素);若是是320dpi的設備,1dp對應兩個點(像素)。這樣咱們要描述一個控件究竟多大,原來用像素的地方,就改爲DP。好比一個用戶頭像能夠是48dp,表示它的大小是48/160英寸。注意,這裏DP只是取代了像素做爲描述控件展現大小的做用,實際展現時屏幕上仍是點,系統內部Bitmap用的仍是Px。使用DP的好處是把控件大小轉換爲物理上的尺寸,讓不一樣dpi上的控件能夠看起來大小同樣。
這個DP固然也能夠從其餘方面理解,原來用px表示大小(一個px對應一個點),如今屏幕dpi提升了一倍,以前一個點的大小如今就要對應4個點。這樣用px表示大小就不合適了,得從新取個名字(dp),固然也有叫pt的(iOS大小單位)。無論這個單位叫什麼,它表示的都是一個物理尺寸的單位,把物理尺寸大小和和最終展現點的數量進行了剝離。
用DP做爲描述大小的單位後,Bitmap展現的問題尚未解決。在160dpi上鋪滿一平方英寸須要160*160像素,但320dpi上須要320*320像素(依然使用160*160只能鋪滿1/4,前面提到的問題)。這個問題如今解決起來也簡單,咱們把160做爲標準(mdpi),把320做爲兩倍圖(xhdpi),爲每一個標準建立一個文件夾,一樣的圖片在mdpi裏面放標準的,在xhdpi放mdpi 2倍大的。再擴展一下,還能夠支持0.75倍的,1.5倍的,3倍的,4倍的。 到這裏,咱們用dp解決了大小單位的表示問題,還兼容了原來的Bitmap展現。DP是Android方案,實際上iOS用的pt也是一樣的思路,mmdpi、xhdpi也對應iOS的1倍圖、2倍圖。須要注意的是,上面說1英寸爲160dp,不是強制的,而是靈活的;硬件廠商能夠是必定範圍爲調整,但總的1dp的視覺大小並不會差距太大;這也是DP的出發點,讓一樣單位(dp)的控件再不一樣設備上看起來同樣大。
就這樣,新的單位訂好了,也解決了和像素直接的轉換問題。工具

原型設計

引入了DP,這是對開發而已的。對於設計師來講,他面對的仍然是px。對於手機App的設計而已,設計師會取720p、1080p或者750*1334做爲原型大小開發。對應到市面上的手機,咱們能夠直接任務720p、750p是xhdpi的,1080是xxxhdpi的。一個控件的dp單位的大小用它px的大小除以2或者3就能夠獲得;如今有原型工具也支持這種換算。這能夠理解成是一個約定好的尺寸,或者一個實踐得出的結果。實際上,設計師也是遵循設計指導的,好比Material Design(雖然官方建議margin padding用8的倍數,但不少設計師用各類奇怪的大小)。佈局

屏幕適配

屏幕適配是任何UI設計須要面對的問題,從移動設備出來以前,PC軟件和Web就積累了屏幕適配的方案了。咱們先說屏幕適配的來源,再說以前的經驗,最後說點實踐。
引入了DP概念後,對開發而已,屏幕的大小就是以dp來看的。Android是開放系統,設備衆多,比較通用的能夠分爲兩類:手機和平板。這些設備的都是ldpi-xxxxhdpi的(實際上Google本身還弄出了420dpi和560dpi的設備);由於如今UI設計上通常認爲垂直方向是能夠無限延長的(上下滾動),高是必定知足展現的,更多的咱們要注意不一樣寬度的屏幕適配。以手機爲例,通常寬度介於320到411dp之間。這就是說開發是適配手機(不包括平板),佈局必須能適應320到411dp之間的任何寬度,這就是開發要面對的適配問題。
在PC軟件和Web上,它們不只要適配不一樣屏幕的像素,還要處理同個屏幕上父窗口的不一樣大小;這個在覈心上是和移動適配是一致的,可是要不一樣尺寸的外部約束下,很好的處理內部的控件位置。這個適配處理,其實是個設計問題。主要的思路是,設計時以屏幕上下左右做爲錨點擺放控件,規定好控件的margin和padding,寬高會變化的控件自適應(TextView,各類父佈局),寬高固定的控件寫死大小(頭像控件等)。開發者還原出設計師的設計思路,就能作出知足屏幕適配的佈局。這裏我強調還原設計思路,而不是還原設計。設計圖不能展現在不一樣尺寸上的效果,但設計思路已經設計到了。仍是上一篇文章的例子,頂部的tab設計圖上是308dp,設計思路是要表示它距離左右兩側22dp(這樣左側恰好和返回按鈕右側對齊)。 post

圖片來自網絡http://www.shui-mai.com/2017/07/11/androidduanuishejiqietubiaozhubanfa/
圖片來自網絡

在具體實踐上,還原一個設計最好的父佈局是RelativeLayout,它自己就是表面不一樣控件之間的位置關係的,和設計思路一致。這裏直接實現設計圖中列表的item

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:padding="16dp"
    android:background="@color/white"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/iv_avatar"
        android:layout_marginRight="15dp"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:scaleType="fitXY"
        android:src="@drawable/img_avatar" />

    <TextView
        android:id="@+id/tv_name"
        android:layout_toRightOf="@+id/iv_avatar"
        android:layout_toLeftOf="@+id/tv_price"
        android:layout_marginRight="15dp"
        android:singleLine="true"
        android:maxEms="8"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:text="朱霸天"
        android:textColor="#FF222222"
        android:textSize="15sp"
        />

    <TextView
        android:id="@+id/tv_price"
        android:gravity="center_vertical"
        android:layout_alignParentRight="true"
        android:singleLine="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:text="+50"
        android:textColor="@color/red"
        android:textSize="15sp"
        />

    <TextView
        android:layout_alignBottom="@+id/iv_avatar"
        android:layout_toRightOf="@+id/iv_avatar"
        android:singleLine="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FF9C9FA2"
        android:textSize="13sp"
        tools:text="2018-08-28"
        />

</RelativeLayout>

複製代碼

上面的代碼,在320dp到411dp的手機上都是適配了的;代碼也很簡單。這裏個人確是作了適配的,還原了控件之間的關係(價格在屏幕右側,標題和時間在頭像右側);設計圖上名字「朱霸天」是三個字,實踐上TextView都要考慮內容過多換行或擠到右側的問題(名字擠到右側紅色價格,會重疊),因此須要限制爲SingleLine和maxEms,名字控件必須是在價格控件左側(android:layout_toLeftOf="@+id/tv_price")。字體

更多

上面說到手機屏幕適配就是適配320到411dp的設備,這個數據可能不許確。手機屏幕衆多,這只是我看到的大部分的屏幕。但這個並不影響適配的效果,就算是擴展到480dp甚至平板的600dp,按dp適配也是能兼容的。固然有些效果可能不是太好,這更應該是設計問題,而不是適配問題,畢竟有些UI的確不適合在大屏上顯示,內容會顯得太空。雖然不是很準確,但知道這個很重要。好比你不能看到一行能夠顯示50個文字寫死了一個TextView的寬度,畢竟你看的效果多是360dp的,在320dp上一行50個字會放不下。
DP適配後徹底不用管屏幕像素也不太準確,畢竟該作的仍是要作的。該作的也說過了,給不一樣xxxxdpi的文件夾放對應的資源文件。
在高度的處理上,前面也說到如今UI通常認爲高度是無限延長的。若是是一個特別長的列表,適配時會使用ListView或ScrollView實現無限延長效果。要當心的是一個看起來是一個屏幕大小的佈局,不能假設頁面必定有640dp高或者其餘。原本Android屏幕的高度就不同;有些設備的系統按鍵多是虛擬的,會佔據一部分屏幕;Android 添加了分屏效果(multi-window)後,屏幕高度可能不是App窗口的高度了。
DP適配固然不是什麼問題都沒有。好比實現一個啓動頁面上放一張滿屏的圖片,要兼容像素和寬高比例的屏幕的話很難保證不拉伸。這些問題又變成了一個設計問題,我近來看到像網易雲音樂或QQ音樂啓動廣告頁底部都留了一截顯示App名稱,讓圖片自帶寬高比例,這種設計就很好。對於Android而已,整個系統是基於DP機制的,甚至還有sp機制,整個適配也並不複雜。ui

最後

沒有了;看狀況待續。spa

相關文章
相關標籤/搜索