屏幕適配總結

前言

屏幕適配網上有很多解決方案,下面我羅列一部分:
*Google的官方權威適配文檔

一、屏幕尺寸,屏幕分辨率,屏幕像素密度

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出現下圖

image.png

點擊screenMatch,點擊ok出現以下圖
image.png

點擊ok,會生成三個文件
image.png

image.png

若values沒有dimens,在values下面新建dimens,將screenMatch_example_dimens中的所有dimens 拷貝到dimens中,再次右擊項目,點擊screenMatch,就會生成我們需要的dimens文件了


image.png

這里可能大家有個疑問為啥用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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容