android屏幕適配的全攻略--支持不一樣的屏幕尺寸適配平板和手機

一. 核心概念與單位詳解

1. 什麼是屏幕尺寸、屏幕分辨率、屏幕像素密度?

屏幕分辨率越大,手機越清晰android

 

 

dpi就是dot per inch dot意思是點,就是每英寸上面的像素點數程序員

 

android原始的api返回的單位都是px,得到屏幕的寬度高度返回的單位都是px,ui設計師在設計圖片的時候的單位通常也是px做爲單位api

咱們在xml佈局的時候,android推薦咱們使用dp做爲單位,最後不要直接使用px做爲單位工具

咱們來看下面的一個案例佈局

列如,咱們要實現這樣的一個需求,畫一條直接填充整個屏幕的寬度性能

 

若是使用xml佈局使用px做爲單位,第一個屏幕須要320px,第二個屏幕須要480px。這也就是說使用px做爲單位,並不能保證在不一樣的屏幕分辨率、不一樣的屏幕像素密度不一樣的dpi下面保存相同的顯示效果。開發工具

使用dp單位就能夠,咱們來在160dpi下面,1dp=1px,上面320px,對應的dp就是320dp,第二個手機像素密度是240dpi,若是設置320dp,轉換成像素就是320*(240/160)=480pxui

這樣就保證了同一條直接在不一樣的手機屏幕上都具備填充滿整個屏幕的效果spa

 

換算的單位是:.net

據px = dip * density / 160,則當屏幕密度爲160時,px = dip

 

 

和上面的填充屏幕寬度同樣,推薦使用sp做爲文字的大小,sp可以依據屏幕的不一樣的分辨率進行縮放達到屏幕適配的效果。

不一樣屏幕像素密度的區分,爲啥android須要對不一樣的像素密度進行區分了,這主要也是爲了屏幕的適配,由於同一張圖片在不一樣的像素密度下顯示的效果是不同的,爲了保證不一樣的設備具備相同的顯示效果,咱們須要爲不一樣的設備提供不一樣尺寸的圖片,就可以大致的知足屏幕的適配,咱們在新建項目的時候,開發工具會自動建立下面的文件夾,程序員須要把當前手機對應像素密度的圖片放在對應的文件夾下面,當程序運行的時候,系統會按照當前手機的dpi到對應的文件夾下面去加載對應的圖片,drawable文件夾是爲了解決不一樣的dpi手機上圖片具備相同的顯示效果。

工程的value文件夾是爲了保證相同的效果,在不一樣的dpi的手機密度下顯示不一樣的dimen的值

 

 

例如爲了達到一樣的顯示效果,在低dpi下面的間隔就會小一點,在高dpi下面的間隔就會大一點,咱們就能夠在不一樣的修飾符限定的value文件夾下面

設置不一樣的dimen的值,可是不一樣的value下面的name值是同樣的,例如上面的不一樣的value下面name都是login_photo_top只是不一樣的value下面的值是不同的。

這樣程序在運行的時候會依據當前手機的dpi自動去得到對應限定符下面的value下的值。

ldpi: 屏幕密度爲120的手機設備

mdpi: 屏幕密度爲160的手機設備(此爲baseline,其餘均以此爲基準,在此設備上,1dp = 1px)

hdpi: 屏幕密度爲240的手機設備

xhdpi: 屏幕密度爲320的手機設備

xxhdpi:屏幕密度爲480的手機設備

 

例如當前的首先是440dpi就會對應的drawable--xxhdpi下面的文件去找對應的圖片,到對應的value下面找對應的值。

依據dip(dp)單位根據公式像素值 = [dip*(dpi/160)](px)(其中px是單位)轉化爲屏幕像素。根據此公式能夠計算出一個dip分別在120dpi、160dpi、240dpi、320dpi屏幕中對應的像素數分別爲0.7五、一、1.五、2.0,比例爲3:4:6:8,以下圖。所以,在不一樣屏幕密度上,以mdpi做爲基準,對位圖進行3:4:6:8比例的放縮會達到適配的效果。

例如:在mdpi上面設計師給了一個ui的設計圖

好比:如今有一個手機是中等密度的屏幕(160dpi),在mdpi下放置了一個48*48px的圖片,要知足圖片在不一樣分辨率的適配性,應該遵循3:4:6:8:12:16的原則。

 

 

 

那麼在ldpi下應該放置36*36px的圖片(12*3

在hdpi文件下就應該放置72*72的圖片(12*4

 

在xhdpi下就應該放置96*96的圖片(12*6

 

在xxhdpi下就應該放置144*144的圖片(12*8

 

上面官方文檔有問題,180*180應該是144*144 (12*12

 

經過上面的大概比例的設置,咱們就知道大致須要的圖片了。

因此一個設計師給了一個在160dpi下面是48*48的圖片,適配不一樣的手機的dpi,程序員需就須要叫設計師給出在xxhdpi下面是144*144px的圖片,咱們只須要按照這個寬和高就行比較就能夠了,就可以大致知足在不一樣的手機上面圖片具備相同的顯示效果。

不一樣的屏幕密度使用不一樣的圖片

因爲Android設備的屏幕密度是各類各樣的,您應該爲不一樣密度的屏幕提供不一樣的圖片資源,這樣在各類像素密度的屏幕上都能得到最好的圖形質量和性能。

在原有矢量圖的基礎上按照以下的縮放比例來分別生成不一樣屏幕密度的圖片資源:

  • xhdpi: 2.0

  • hdpi: 1.5

  • mdpi: 1.0 (baseline)

  • ldpi: 0.75

這意味着對於xhdpi 的設備須要使用200×200的圖片;對於hdpi的設備只須要 150×150 的圖片;而對於mdpi的設備須要 100×100 的圖片; 對於ldpi 的設備只須要75×75 的圖片。

把這些圖片放到位於res/目錄下對於的圖片目錄中:

MyProject/
  res/
    drawable-xhdpi/
        awesomeimage.png
    drawable-hdpi/
        awesomeimage.png
    drawable-mdpi/
        awesomeimage.png
    drawable-ldpi/
        awesomeimage.png

而後,當您使用@drawable/awesomeimage的時候, 系統會根據當前設備的屏幕密度爲您選擇最優的圖片。

二. 解決方案-支持各類屏幕尺寸

咱們能夠經過如下幾種方式來支持各類屏幕尺寸:

1. 使用wrap_content、math_parent、weight

wrap_content:根據控件的內容設置控件的尺寸
math_parent:根據父控件的尺寸大小設置控件的尺寸
weight:權重,在線性佈局中可使用weight屬性設置控件所佔的比例

例如,咱們要實現下圖所顯示的效果:當屏幕尺寸改變時,new reader控件兩邊的控件大小不變,new reader控件會佔完剩餘的空間。

線性佈局中使用weight屬性

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    
android:layout_width="match_parent"    
android:layout_height="match_parent"    
android:orientation="horizontal">    
<TextView        
      android:layout_width="80dp"        
      android:layout_height="80dp"        
      android:layout_weight="0"        
      android:background="#028330"/>    
<TextView        
      android:layout_width="wrap_content"        
      android:layout_height="80dp"        
      android:text="new
reader"        
      android:textSize="22sp"        
      android:layout_weight="1"/>    
<TextView        
      android:layout_width="160dp"        
      android:layout_height="80dp"       
      android:text="Politics"        
      android:textSize="18sp"        
      android:layout_weight="0"        
      android:background="#028330"/>
</LinearLayout>

小插曲:關於android:layout_weight屬性

公式:所佔寬度=原來寬度+剩餘空間所佔百分比的寬度

通常狀況,咱們都是設置要進行比例分配的方向的寬度爲0dp,而後再用權重進行分配。以下:

<Button    
      android:layout_width="0dp"    
      android:layout_height="wrap_content"    
      android:layout_weight="1"    
      android:text="Button1" />
<Button    
     android:layout_width="0dp"    
     android:layout_height="wrap_content"    
     android:layout_weight="2"    
     android:text="Button2" />

效果爲:

 

而後咱們修改佈局文件後

LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="horizontal" >  
  
    <Button  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_weight="1"  
        android:text="buttton1" />  
  
    <Button  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_weight="2"  
        android:text="button2" />  
  
</LinearLayout>  

 

 

 

咱們來分析下:

屏幕的寬度是L

剩餘空間所佔百分比的寬度:如今按鈕1的寬度是L,按鈕2的寬度是L,剩餘空間就是屏幕的寬度減去按鈕1和按鈕2所佔的寬度,L-2L

寬度爲match_parent時,所佔比例

button1寬度=L+(L-2L)×1/3=2/3L
button2寬度=L+(L-2L)×2/3=1/3L

2. 使用相對佈局,禁用絕對佈局

簡單的佈局通常都使用線性佈局,而略微複雜點的佈局,咱們使用相對佈局,大多數時候,咱們都是使用這兩種佈局的嵌套。

咱們使用相對佈局的緣由是,相對佈局能在各類尺寸的屏幕上保持控件間的相對位置。

案例以下:

完成界面的適配

 

3. 使用限定符

    • 使用尺寸限定符
      當咱們要在大屏幕上顯示不一樣的佈局,就要使用large限定符。例如,在寬的屏幕左邊顯示列表右邊顯示列表項的詳細信息,在通常寬度的屏幕只顯示列表,不顯示列表項的詳細信息,咱們就可使用large限定符。

 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" />
</LinearLayout>

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" />
</LinearLayout>

若是這個程序運行在屏幕尺寸大於7inch的設備上,系統就會加載res/layout-large/main.xml 而不是res/layout/main.xml,在小於7inch的設備上就會加載res/layout/main.xml

須要注意的是,這種經過large限定符分辨屏幕尺寸的方法,適用於android3.2以前。在android3.2以後,爲了更精確地分辨屏幕尺寸大小,Google推出了最小寬度限定符

最小寬度限定符的使用和large基本一致,只是使用了具體的寬度限定。
res/layout/main.xml,單面板(默認)佈局:

nearLayout 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" />
</LinearLayout>

res/layout-sw600dp/main.xml,雙面板佈局: Small Width 最小寬度

<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" />
</LinearLayout>

 Small Width 最小寬度這裏不限定是橫屏、仍是縱屏的寬度,只要寬度的最小值大於600dp,就加載雙面板的佈局

這種最小寬度限定符適用於android3.2以後,因此若是要適配android所有的版本,就要使用large限定符和sw600dp文件同時存在於項目res目錄下。

這就要求咱們維護兩個相同功能的文件。爲了不繁瑣操做,咱們就要使用佈局別名。

使用佈局別名
res/layout/main.xml: 單面板佈局
res/layout-large/main.xml: 多面板佈局(支持3.2版本以前的平板設備)
res/layout-sw600dp/main.xml: 多面板佈局(支持3.2版本以後的平板設備)

l

因爲後兩個文具文件同樣,咱們能夠用如下兩個文件代替上面三個佈局文件:

res/layout/main.xml 單面板佈局
res/layout/main_twopanes.xml 雙面板佈局

而後在res下創建
res/values/layout.xml
res/values-large/layout.xml
res/values-sw600dp/layout.xml三個文件。

默認佈局
res/values/layout.xml:

<resources> <item name="main1" type="layout">@layout/main</item> </resources>

Android3.2以前的平板佈局
res/values-large/layout.xml:

<resources> <item name="main1" type="layout">@layout/main_twopanes</item> </resources>

Android3.2以後的平板佈局
res/values-sw600dp/layout.xml:

<resources> <item name="main1" type="layout">@layout/main_twopanes</item> </resources>

這樣就有了main爲別名的佈局。
在activity中setContentView(R.layout.main1);

這樣,程序在運行時,就會檢測手機的屏幕大小,若是是平板設備就會加載res/layout/main_twopanes.xml,若是是手機設備,就會加載res/layout/main.xml 。咱們就解決了只使用一個佈局文件來適配android3.2先後的全部平板設備。

注意幾點:values-sw600dp和values-large下面的名字不必定都命名成layout.xml只要xml裏面的內容都寫成一致的就能夠了。

使用屏幕方向限定符

若是咱們要求給橫屏、豎屏顯示的佈局不同。就可使用屏幕方向限定符來實現。
例如,要在平板上實現橫豎屏顯示不用的佈局,能夠用如下方式實現。
res/values-sw600dp-land/layouts.xml:橫屏

<resources> <item name="main" type="layout">@layout/main_twopanes</item> </resources>

res/values-sw600dp-port/layouts.xml:豎屏

<resources> <item name="main" type="layout">@layout/main</item> </resources>
相關文章
相關標籤/搜索