1. 程式人生 > >騰訊面試後感悟的Android適配原理

騰訊面試後感悟的Android適配原理

為何要使用適配

其實在一開始的時候。我接觸的Android認知可能就是Android的機型太多。理應找一個好的適配框架,然後也學習了鴻詳大神的一些適配原理。確實也應用到框架體系裡面。適配也還算挺成功的。

然鵝,在上一次騰訊的面試中,好像這點就栽了很大的跟斗,當面試官問道我的框架適配的時候,我信心滿滿說出自己的見解,然後說出了自己是怎麼把適配框架應用到自己的Android專案裡的。當我還沉浸在自己的世界一頓海說的時候

面試官直接:“咳咳~ 那個, 你說你用的這套適配框架我贊同, 請問一下您, 為何沒有考慮過谷歌原生的適配框架呢?”
我:“ 這個。 (我確實沒有看過原生的。當時適配要的急,直接詢問了個大神,大神推薦給我的適配,我就直接去學習看的。確實沒有考慮過適配的前因後果) ” 我臨場能力還是很強:” 然後補充道,原生的適配在很多不同的機型上還是有侷限性,所以沒考慮,直接用的現在這套體系”
面試官一聽好像也有怎麼回事,繼續補充道:“哦? 那可以深入的說一下谷歌的適配的缺陷性嗎?”
我:“GG”

從騰訊大樓出來以後還是挺後悔的。騰訊畢竟也還是萬千程式猿想去的公司包括我,然而自己卻浪費了這一次的大好機會,不過也確實是自己還有知識的缺陷性。所以打算好好整理一番,鬥志不能缺。誒~ 遲早。我王老五還會殺回去的。

Android螢幕適配出現的原因

下面這張圖片所顯示的內容足以充分說明當今Android系統碎片化問題的嚴重性,因為該圖片中的每一個矩形都代表著一種Android裝置。
這裡寫圖片描述

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類似,但是可以根據文字大小首選項進行放縮,是設定字型大小的御用單位。

Google官方指定按照下列標準進行區分:

名稱 畫素密度範圍
mdpi 120dpi~160dpi
hdpi 160dpi~240dpi
xhdpi 240dpi~320dpi
xxhdpi 320dpi~480dpi
xxxhdpi 480dpi~640dpi
mdpi、hdpi、xdpi、xxdpi用來修飾Android中的drawable資料夾及values資料夾,用來區分不同畫素密度下的圖片和dimen值。

使用尺寸限定符

很多應用會在較大的螢幕上實施“雙面板”模式,即在一個面板上顯示專案列表,而在另一面板上顯示對應內容。平板電腦和電視的螢幕已經大到可以同時容納這兩個面板了,但手機螢幕就需要分別顯示。因此,我們可以使用以下檔案以便實施這些佈局:

res/layout/main.xml,單面板(預設)佈局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:orientation="vertical"  
android:layout_width="match_parent"  
android:layout_height="match_parent">  

<fragment android:id="@+id/headlines"  
          android:layout_height="fill_parent"  
          android:name="com.example.android.newsreader.HeadlinesFragment"  
          android:layout_width="match_parent" />  

res/layout-large/main.xml,雙面板佈局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:layout_width="fill_parent"  
android:layout_height="fill_parent"  
android:orientation="horizontal">  
<fragment android:id="@+id/headlines"  
          android:layout_height="fill_parent"  
          android:name="com.example.android.newsreader.HeadlinesFragment"  
          android:layout_width="400dp"  
          android:layout_marginRight="10dp"/>  
<fragment android:id="@+id/article"  
          android:layout_height="fill_parent"  
          android:name="com.example.android.newsreader.ArticleFragment"  
          android:layout_width="fill_parent" />  

使用最小寬度限定符

res/layout/main.xml,單面板(預設)佈局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:orientation="vertical"  
android:layout_width="match_parent"  
android:layout_height="match_parent">  

<fragment android:id="@+id/headlines"  
          android:layout_height="fill_parent"  
          android:name="com.example.android.newsreader.HeadlinesFragment"  
          android:layout_width="match_parent" />  

res/layout-sw600dp/main.xml,雙面板佈局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:layout_width="fill_parent"  
android:layout_height="fill_parent"  
android:orientation="horizontal">  
<fragment android:id="@+id/headlines"  
          android:layout_height="fill_parent"  
          android:name="com.example.android.newsreader.HeadlinesFragment"  
          android:layout_width="400dp"  
          android:layout_marginRight="10dp"/>  
<fragment android:id="@+id/article"  
          android:layout_height="fill_parent"  
          android:name="com.example.android.newsreader.ArticleFragment"  
          android:layout_width="fill_parent" />  

使用佈局別名

  1. res/layout/main.xml: 單面板佈局
  2. res/layout-large: 多面板佈局
  3. res/layout-sw600dp: 多面板佈局

使用螢幕方向限定符

某些佈局會同時支援橫向模式和縱向模式,但我們可以通過調整優化其中大部分佈局的效果。在新聞閱讀器示例應用中,每種螢幕尺寸和螢幕方向下的佈局行為方式如下所示:

小螢幕,縱向:單面板,帶徽標
小螢幕,橫向:單面板,帶徽標
7 英寸平板電腦,縱向:單面板,帶操作欄
7 英寸平板電腦,橫向:雙面板,寬,帶操作欄
10 英寸平板電腦,縱向:雙面板,窄,帶操作欄
10 英寸平板電腦,橫向:雙面板,寬,帶操作欄
電視,橫向:雙面板,寬,帶操作欄

谷歌適配為什麼有侷限性呢?

谷歌的dp其實就已經做了適配呢
我們都已經用了dp了,為什麼會出現這種情況呢?

你聽我慢慢道來。

雖然說dp可以去除不同畫素密度的問題,使得1dp在不同畫素密度上面的顯示效果相同,但是還是由於Android螢幕裝置的多樣性,如果使用dp來作為度量單位,並不是所有的螢幕的寬度都是相同的dp長度,比如說,Nexus S和Nexus One屬於hdpi,螢幕寬度是320dp,而Nexus 5屬於xxhdpi,螢幕寬度是360dp,Galaxy Nexus屬於xhdpi,螢幕寬度是384dp,Nexus 6 屬於xxxhdpi,螢幕寬度是410dp。所以說,光Google自己一家的產品就已經有這麼多的標準,而且螢幕寬度和畫素密度沒有任何關聯關係,即使我們使用dp,在320dp寬度的裝置和410dp的裝置上,還是會有90dp的差別。當然,我們儘量使用match_parent和wrap_content,儘可能少的用dp來指定控制元件的具體長寬,再結合上權重,大部分的情況我們都是可以做到適配的。

適配原理思路

大家拿到UI給的設計圖以後,是不是抱怨過尼瑪你標識的都是px,我專案裡面用dp,這什麼玩意,和UI人員解釋,UI妹妹也不理解。那麼本例同樣可以解決Android工程師和UI妹妹間的矛盾~UI給出一個固定尺寸的設計稿,然後你在編寫佈局的時候不用思考,無腦照抄上面標識的畫素值,就能達到完美適配,理想豐不豐滿~~。

但是web前段人員卻從來沒有適配的困擾。因為前段的適配的思路從來都是百分比的。Android卻沒有這種佈局, 可能就需要認為的計算

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

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

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

不過谷歌也開始引入百分比的機制來進行Android的適配了