前言
屏幕適配網上有很多解決方案,下面我羅列一部分:
*Google的官方權威適配文檔
- 郭霖: Android官方提供的支持不同屏幕大小的全部方法
- Stormzhang:Android 屏幕適配
- 鴻洋:Android 屏幕適配方案
- 凱子: Android屏幕適配全攻略(最權威的官方適配指導)
一、屏幕尺寸,屏幕分辨率,屏幕像素密度
1.屏幕尺寸
- 屏幕尺寸:就是手機對角線的物理長度
-
單位:英寸 1英寸=2.5cm
用圖來表示說明
image.png
2.屏幕分辨率
-
含義:手機在橫向、縱向上的像素點數總和
如圖,1920*1080就是屏幕的分辨率
image.png
3.像素密度
-
含義:每英寸的像素點數
單位:dpi
image.png
4.他們三者之間的關系
對角線長度=(屏幕的寬^2 + 屏幕的高^2)的開方
dpi=對角線/屏幕尺寸
density=dpi/160dpi
px= dp x density=dp x (dpi /160)
dip和dp是一個意思,即密度無關像素,規定以160dpi為基準,1dip=1px
5.mdpi hdpi xhdpi xxhdpi xxxhdpi的區分
名稱 | 像素密度范圍 | dp轉px | 圖標尺寸 | 對應的屏幕分辨率 |
---|---|---|---|---|
mdpi | 120*160dpi | 1dp=1px | 48*48px | 320x480 |
hdpi | 160*240dpi | 1dp=1.5px | 72*72px | 480x800 |
xhdpi | 240*320dpi | 1dp=2px | 96*96px | 720x1280 |
xxhdpi | 320*480dpi | 1dp=3px | 144*144px | 1080x1920 |
xxxhdpi | 480*640dpi | 1dp=4px | 192*192px | 3840*2160 |
二、屏幕適配
1、使用wrap_content,match_parent,weight進行適配
2、.9圖進行適配
3、限定符適配
3.1、平板適配
順帶說一下平板適配,雖然大多數app都不會做平板適配(我們公司也一樣)但是可以了解一下
我們在做屏幕的適配時在屏幕 尺寸相差不大的情況下,dp可以使不同分辨率的設備上展示效果相似。但是在屏幕尺寸相差比較大的情況下(平板),dp就失去了這種效果。所以需要以下的限定符來約束,采用多套布局,數值等方式來適配。
限定符就是android在進行資源加載的時候會按照屏幕的相關信息對文件夾對應的名字進行識別,而這些特殊名字就是我們的限定符
限定符分類:
屏幕尺寸
small 小屏幕
normal 基準屏幕
large 大屏幕
xlarge 超大屏幕
屏幕密度
ldpi <=120dpi
mdpi <= 160dpi
hdpi <= 240dpi
xhdpi <= 320dpi
xxhdpi <= 480dpi
xxhdpi <= 640dpi(只用來存放icon)
nodpi 與屏幕密度無關的資源.系統不會針對屏幕密度對其中資源進行壓縮或者拉伸
tvdpi 介于mdpi與hdpi之間,特定針對213dpi,專門為電視準備的,手機應用開發不需要關心這個密度值.
屏幕方向
land 橫向
port 縱向
屏幕寬高比
long 比標準屏幕寬高比明顯的高或者寬的這樣屏幕
notlong 和標準屏幕配置一樣的屏幕寬高比
3.1.1 使用尺寸限定符:
適用于android3.2之前,Google推出了最小寬度限定符
當我們要在大屏幕上顯示不同的布局,就要使用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="match_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="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<!-- 列表 -->
<fragment android:id="@+id/headlines"
android:layout_height="match_parent"
android:name="com.example.android.newsreader.HeadlinesFragment"
android:layout_width="400dp"
android:layout_marginRight="10dp"/>
<!-- 列表項的詳細信息 -->
<fragment android:id="@+id/article"
android:layout_height="match_parent"
android:name="com.example.android.newsreader.ArticleFragment"
android:layout_width="match_parent" />
</LinearLayout>
如果這個程序運行在屏幕尺寸大于7inch的設備上,系統就會加載res/layout-large/main.xml 而不是res/layout/main.xml,在小于7inch的設備上就會加載res/layout/main.xml。
3.1.2 最小寬度限定符:
最小寬度限定符的使用和large基本一致,只是使用了具體的寬度限定。
res/layout/main.xml,單面板(默認)布局:同上
res/layout-sw600dp/main.xml,雙面板布局: Small Width 最小寬度 同上
這種方式是不區分屏幕方向的。所以如果要適配android全部的版本,就要使用large限定符和sw600dp文件同時存在于項目res目錄下。
1.使用布局別名加載
res/layout/main.xml: 單面板布局
res/layout-large/main.xml: 多面板布局
res/layout-sw600dp/main.xml: 多面板布局
代替上面的限定符布局,改為
res/layout/main.xml 單面板布局
res/layout/main_twopanes.xml 雙面板布局
然后在res下建立
res/values/layout.xml、
res/values-large/layout.xml、
res/values-sw600dp/layout.xml三個文件。
例:
<resources>
<item name="main" type="layout">@layout/main</item>
</resources>
2.使用屏幕方向限定符
如果我們要求給橫屏、豎屏顯示的布局不一樣。就可以使用屏幕方向限定符來實現。
例如,要在平板上實現橫豎屏顯示不用的布局,可以用以下方式實現。
res/values-sw600dp-land/layouts.xml:橫屏
res/values-sw600dp-port/layouts.xml:豎屏
4.手機屏幕適配
4.1、限定符的使用
這里推薦一個Android插件 ScreenMatch
插件應用步驟:
第一步安裝插件不用說吧
第二步:右鍵點擊app出現下圖
點擊screenMatch,點擊ok出現以下圖
點擊ok,會生成三個文件
若values沒有dimens,在values下面新建dimens,將screenMatch_example_dimens中的所有dimens 拷貝到dimens中,再次右擊項目,點擊screenMatch,就會生成我們需要的dimens文件了
這里可能大家有個疑問為啥用360dp為基準呢,因為這里采用的最小寬度限定符sw360
sw360dp 的平板屏幕分辨率為1920*1080 尺寸:5-6 dpi 440左右,我們換算成手機的分辨率:
440/160 *360=990<1080 所以可以適配大部分機型,相當于xxhdpi的尺寸
4.2 對于自定義view,我們怎么適配呢
這里實際上我們定義一個屏幕分辨率的標準,然后傳入實際屏幕的寬高,算出他們的寬高分別的scale就可以啦
public class UIUtils {
private Context context;
private static UIUtils utils ;
public static UIUtils getInstance(Context context){
if(utils == null){
utils = new UIUtils(context);
}
return utils;
}
//參照寬高
public final float STANDARD_WIDTH = 720;
public final float STANDARD_HEIGHT = 1232;
//當前設備實際寬高
public float displayMetricsWidth ;
public float displayMetricsHeight ;
private final String DIMEN_CLASS = "com.android.internal.R$dimen";
private UIUtils(Context context){
this.context = context;
//
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//加載當前界面信息
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
if(displayMetricsWidth == 0.0f || displayMetricsHeight == 0.0f){
//獲取狀態框信息
int systemBarHeight = getValue(context,"system_bar_height",48);
//這里要減去狀態欄的寬高
if(displayMetrics.widthPixels > displayMetrics.heightPixels){//橫屏
this.displayMetricsWidth = displayMetrics.heightPixels;
this.displayMetricsHeight = displayMetrics.widthPixels - systemBarHeight;
}else{//豎屏
this.displayMetricsWidth = displayMetrics.widthPixels;
this.displayMetricsHeight = displayMetrics.heightPixels - systemBarHeight;
}
}
}
//對外提供系數
public float getHorizontalScaleValue(){
return displayMetricsWidth / STANDARD_WIDTH;
}
public float getVerticalScaleValue(){
Log.i("testbarry","displayMetricsHeight:"+displayMetricsHeight);
return displayMetricsHeight / STANDARD_HEIGHT;
}
public int getValue(Context context,String systemid,int defValue) {
try {
Class<?> clazz = Class.forName(DIMEN_CLASS);
Object r = clazz.newInstance();
Field field = clazz.getField(systemid);
int x = (int) field.get(r);
return context.getResources().getDimensionPixelOffset(x);
} catch (Exception e) {
return defValue;
}
}
}
在外邊調用:
float scaleX = UIUtils.getInstance(this.getContext()).getHorizontalScaleValue();
float scaleY = UIUtils.getInstance(this.getContext()).getVerticalScaleValue();
LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
layoutParams.width = (int) (layoutParams.width * scaleX);
layoutParams.height = (int) (layoutParams.height * scaleY);
5.全面屏適配
在manifest下面的activity節點加入以下代碼就好了
<!-- 全面屏適配 -->
<meta-data android:name="android.max_aspect"
android:value="2.1"/>
6.劉海屏
不同的廠商有不同的適配規則,去他們的開方平臺查看官方文檔即可
內容引用的文章:http://www.lxweimin.com/p/bb80ad6f25e5
http://www.lxweimin.com/p/ec5a1a30694b