Android屏幕適配

1、概述

Android屏幕適配出現的原因

在我們學習如何進行屏幕適配之前,我們需要先了解下爲什麼Android需要進行屏幕適配。

由於Android系統的開放性,任何用戶、開發者、OEM廠商、運營商都可以對Android進行定製,修改成他們想要的樣子。

但是這種“碎片化”到底到達什麼程度呢?

在2012年,OpenSignalMaps(以下簡稱OSM)發佈了第一份Android碎片化報告,統計數據表明,

2012年,支持Android的設備共有3997種。
2013年,支持Android的設備共有11868種。
2014年,支持Android的設備共有18796種。
下面這張圖片所顯示的內容足以充分說明當今Android系統碎片化問題的嚴重性,因爲該圖片中的每一個矩形都代表着一種Android設備。

109779420.jpg

而隨着支持Android系統的設備(手機、平板、電視、手錶)的增多,設備碎片化、品牌碎片化、系統碎片化、傳感器碎片化和屏幕碎片化的程度也在不斷地加深。而我們今天要探討的,則是對我們開發影響比較大的——屏幕的碎片化。

下面這張圖是Android屏幕尺寸的示意圖,在這張圖裏面,藍色矩形的大小代表不同尺寸,顏色深淺則代表所佔百分比的大小。

ab2d4007f2c7e9806436184f8b80a4d0.jpg

而與之相對應的,則是下面這張圖。這張圖顯示了IOS設備所需要進行適配的屏幕尺寸和佔比。

109779430.jpg

當然,這張圖片只是4,4s,5,5c,5s和平板的尺寸,現在還應該加上新推出的iphone6和plus,但是和Android的屏幕碎片化程度相比而言,還是差的太遠。

詳細的統計數據請到這裏查看。

現在你應該很清楚爲什麼要對Android的屏幕進行適配了吧?屏幕尺寸這麼多,爲了讓我們開發的程序能夠比較美觀的顯示在不同尺寸、分辨率、像素密度(這些概念我會在下面詳細講解)的設備上,那就要在開發的過程中進行處理,至於如何去進行處理,這就是我們今天的主題了。

但是在開始進入主題之前,我們再來探討一件事情,那就是Android設備的屏幕尺寸,從幾寸的智能手機,到10寸的平板電腦,再到幾十寸的數字電視,我們應該適配哪些設備呢?

其實這個問題不應該這麼考慮,因爲對於具有相同像素密度的設備來說,像素越高,尺寸就越大,所以我們可以換個思路,將問題從單純的尺寸大小轉換到像素大小和像素密度的角度來。

下圖是2014年初,友盟統計的佔比5%以上的6個主流分辨率,可以看出,佔比最高的是480*800,320*480的設備竟然也佔據了很大比例,但是和半年前的數據相比較,中低分辨率(320*480、480*800)的比例在減少,而中高分辨率的比例則在不斷地增加。雖然每個分辨率所佔的比例在變化,但是總的趨勢沒變,還是這六種,只是分辨率在不斷地提高。

所以說,我們只要儘量適配這幾種分辨率,就可以在大部分的手機上正常運行了。

當然了,這只是手機的適配,對於平板設備(電視也可以看做是平板),我們還需要一些其他的處理。

好了,到目前爲止,我們已經弄清楚了Android開發爲什麼要進行適配,以及我們應該適配哪些對象,接下來,終於進入我們的正題了!

首先,我們先要學習幾個重要的概念。

  • 什麼是屏幕尺寸、屏幕分辨率、屏幕像素密度?
  • 什麼是dp、dip、dpi、sp、px?他們之間的關係是什麼?
  • 什麼是mdpi、hdpi、xdpi、xxdpi?如何計算和區分?
  • 在下面的內容中我們將介紹這些概念。

屏幕尺寸

屏幕尺寸指屏幕的對角線的長度,單位是英寸,1英寸=2.54釐米

比如常見的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0等

屏幕分辨率

屏幕分辨率是指在橫縱向上的像素點數,單位是px,1px=1個像素點。一般以縱向像素*橫向像素,如1960*1080。

屏幕像素密度

屏幕像素密度是指每英寸上的像素點數,單位是dpi,即“dot per inch”的縮寫。屏幕像素密度與屏幕尺寸和屏幕分辨率有關,在單一變化條件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。

dp、dip、dpi、sp、px

px我們應該是比較熟悉的,前面的分辨率就是用的像素爲單位,大多數情況下,比如UI設計、Android原生API都會以px作爲統一的計量單位,像是獲取屏幕寬高等。

dip和dp是一個意思,都是Density Independent Pixels的縮寫,即密度無關像素,上面我們說過,dpi是屏幕像素密度,假如一英寸裏面有160個像素,這個屏幕的像素密度就是160dpi,那麼在這種情況下,dp和px如何換算呢?在Android中,規定以160dpi爲基準,1dip=1px,如果密度是320dpi,則1dip=2px,以此類推。

假如同樣都是畫一條320px的線,在480*800分辨率手機上顯示爲2/3屏幕寬度,在320*480的手機上則佔滿了全屏,如果使用dp爲單位,在這兩種分辨率下,160dp都顯示爲屏幕一半的長度。這也是爲什麼在Android開發中,寫佈局的時候要儘量使用dp而不是px的原因。

而sp,即scale-independent pixels,與dp類似,但是可以根據文字大小首選項進行放縮,是設置字體大小的御用單位。

mdpi、hdpi、xdpi、xxdpi

其實之前還有個ldpi,但是隨着移動設備配置的不斷升級,這個像素密度的設備已經很罕見了,所在現在適配時不需考慮。

mdpi、hdpi、xdpi、xxdpi用來修飾Android中的drawable文件夾及values文件夾,用來區分不同像素密度下的圖片和dimen值。

dp適配:
一句話,總結下,dp能夠讓同一數值在不同的分辨率展示出大致相同的尺寸大小。但是當設備的尺寸差異較大的時候,就無能爲力了。適配的問題還需要我們自己去做,於是我們可能會這麼做:

<?xml version="1.0" encoding="utf-8"?>  
<resources>  
    <!-- values-hdpi 480X800 -->  
    <dimen name="imagewidth">120dip</dimen>      
</resources>  

<resources>  
    <!-- values-hdpi-1280x800 -->  
    <dimen name="imagewidth">220dip</dimen>      
</resources>  


<?xml version="1.0" encoding="utf-8"?>  
<resources>  
    <!-- values-hdpi  480X320 -->  
    <dimen name="imagewidth">80dip</dimen>      
</resources> 
上述代碼片段來自網絡,也就是說,我們爲了優質的用戶體驗,依然需要去針對不同的dpi設置,編寫多套數值文件。

2.適配Tips

我們再來看看一些適配的tips

  1. 多用match_parent
  2. 多用weight
  3. 自定義view解決
其實上述3tip,歸根結底還是利用百分比,match_parent相當於100%參考父控件;weight即按比例分配;自定義view無非是因爲裏面多數尺寸是按照百分比計算的;

通過這些tips,我們更加的看出如果能在Android中引入百分比的機制,將能解決大多數的適配問題,下面我們就來看看如何能夠讓Android支持百分比的概念。

3、百分比的引入

Android屏幕適配方案裏面的百分比引入以及快速生成dimen文件
Google已經添加了百分比支持庫,詳情請看:Android 百分比佈局庫
(percent-support-lib) 解析與擴展這裏簡單概述下。

android-percent-support-lib-sample

How to use :

just add percent support library to your project

dependencies {
    compile 'com.android.support:percent:22.2.0'
}

支持的佈局:

PercentRelativeLayout

<android.support.percent.PercentRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/top_left"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_alignParentTop="true"
        android:background="#ff44aacc"
        app:layout_heightPercent="20%"
        app:layout_widthPercent="70%" />

    <View
        android:id="@+id/top_right"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/top_left"
        android:background="#ffe40000"
        app:layout_heightPercent="20%"
        app:layout_widthPercent="30%" />


    <View
        android:id="@+id/bottom"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_below="@+id/top_left"
        android:background="#ff00ff22"
        app:layout_heightPercent="80%" />
</android.support.percent.PercentRelativeLayout>

PercentLinearLayout

<com.juliengenoud.percentsamples.PercentLinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
     <View
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff44aacc"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="60%"/>

    <View
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff4400cc"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="70%"/>
</com.juliengenoud.percentsamples.PercentLinearLayout>

PercentFrameLayout

<android.support.percent.PercentFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
        <!-- ... XML CODE -->
</android.support.percent.PercentFrameLayout>

支持的屬性 :

heightPercent
widthPercent
marginBottomPercent
marginEndPercent
marginLeftPercent
marginPercent
marginRightPercent
marginStartPercent
marginTopPercent
Pre-requisites

環境配置要求:

Android SDK v22
Android Build Tools v22.0.1
Android Percent Support Repository v22.2.0
Android Support v4 Repository v22.2.0
according to the the manifest minsdk is v7 (android 2.1)

詳細分析這個庫的源碼:

Android 百分比佈局庫(percent-support-lib) 解析與擴展
其實主要就幾個步驟:

  • LayoutParams中屬性的獲取
  • onMeasure中,改變params.width爲百分比計算結果,測量
  • 如果測量值過小且設置的w/h是wrap_content,重新測量
  • onLayout中,重置params.w/h爲佈局文件中編寫的值

可以看到,PercentLinearLayout,PercentRelativeLayout,PercentFrameLayout就是對LinearLayout,RelativeLayout、FrameLayout的擴展。

缺陷與完善

存在的缺陷:有些場景使用並不能滿足我的要求
1. 當使用圖片時,無法設置寬高的比例

比如我們的圖片寬高是200*100的,我們在使用過程中我們設置寬高爲20%、10%,這樣會造成圖片的比例失調。爲什麼呢?因爲20%參考的是屏幕的寬度,而10%參考的是屏幕的高度。

2.很難使用百分比定義一個正方形的控件

比如,我現在界面的右下角有一個FloatingActionButton,我希望其寬度和高度都爲屏幕寬度的10%,很難做到。

3.一個控件的margin四個方向值一致

有些時候,我設置margin,我希望四邊的邊距一致的,但是如果目前設置5%,會造成,上下爲高度的5%,左右邊距爲寬度的5%。

綜合上述這些問題,可以發現目前的percent-support-lib並不能完全滿足我們的需求,所以我們考慮對其進行擴展。說白了,我們就希望在佈局的時候可以自己設定參考看度還是高度,比如上述2,我們對於寬高可以寫成10%w,10%w。也就是在不改變原庫的用法的前提下,添加一些額外的支持。

二 擴展的功能

鴻洋大神對這個庫的修改,github地址:android-percent-support-extend,對於官方庫,做了如下的改變:

1.不改變原有庫的用法
2.添加了PercentLinearLayout
3.支持百分比指定特定的參考值,比如寬度或者高度。

例如:

app:layout_heightPercent="50%w",
app:layout_marginPercent="15%w", 
app:layout_marginBottomPercent="20%h".

4.支持通過app:layout_textSizePercent設置textView的textSize
5.對於外層套ScrollView的問題,目前可以在PercentLinearLayout的外層使用ScrollView,不過對於寬度的百分比參考的就是android.R.id.content的高度(因爲,無法參考父控件的高度,父控件的高度理論上依賴於子View高度,且模式爲UNSPECIFIED)

參考:
Android適配全攻略
Android 百分比佈局庫(percent-support-lib) 解析與擴展
Android 增強版百分比佈局庫 爲了適配而擴展

發佈了51 篇原創文章 · 獲贊 11 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章