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>
相关文章
相关标签/搜索