总结Android屏幕适配(源自简书:李俊的博客)
基礎(chǔ)知識(shí)
屏幕尺寸、屏幕分辨率、屏幕像素密度
1、屏幕尺寸是指屏幕對(duì)角線的長(zhǎng)度。單位是英寸,1英寸=2.54厘米。
2、屏幕分辨率是指在橫縱向上的像素點(diǎn)數(shù),單位是px,1px=1像素點(diǎn),一般是縱向像素橫向像素,如1280×720。
3、屏幕像素密度是指每英寸上的像素點(diǎn)數(shù),單位是dpi(dot per inch),像素密度和屏幕尺寸和屏幕分辨率有關(guān)。
dip、dp、sp、dpi、px、in、pt
1、dip或dp(device independent pixels,設(shè)備獨(dú)立像素):以160dpi為基準(zhǔn),1dp=1px。
2、sp(scaled pixels):可以根據(jù)文字大小首選項(xiàng)自動(dòng)進(jìn)行縮放。
3、dpi(dots per inch,密度):屏幕像素密度的單位,屏幕每英寸所包含的像素?cái)?shù)。
4、px(pixels,像素):物理上的絕對(duì)單位。
5、in(inch,英寸):一英寸=2.54cm。
6、pt(磅):一磅=1/72英寸。
mdpi、hdpi、xdpi、xxdpi、xxxdpi
| mdpi | 120~160dpi | 320x480px | 48x48px | 1 |
| hdpi | 160~240dpi | 480x800px | 72x72px | 1.5 |
| xhdpi | 240~320dpi | 720x1280px | 96x96px | 2 |
| xxhdpi | 320~480dpi | 1080x1920px | 144x144px | 3 |
| xxxhdpi | 480~640dpi | 1440x2560px | 192x192px | 4 |
實(shí)戰(zhàn)
獲取屏幕的數(shù)據(jù)
// 獲取DisplayMetrics實(shí)例 DisplayMetrics dm = context.getResources().getDisplayMetrics();// 屏幕高的像素個(gè)數(shù) int heightPixels = dm.heightPixels; // 屏幕寬的像素個(gè)數(shù) int widthPixels = dm.widthPixels;// 屏幕密度:每英寸所含的像素的個(gè)數(shù) int densityDpi = dm.densityDpi; // 屏幕密度:densityDpi/160 float density = dm.density;dp與px相互轉(zhuǎn)換
/*** 轉(zhuǎn)換工具類*/ public class ConvertUtil {/*** dp轉(zhuǎn)換成px** @param context 上下文* @param value 多少dp* @return 返回轉(zhuǎn)換后等于多少px*/public static int dp2px(Context context, float value) {// 獲取屏幕的密度:density = densityDpi/160final float scale = context.getResources().getDisplayMetrics().density;// dp轉(zhuǎn)換成px,value*density// + 0.5f是為了四舍五入轉(zhuǎn)換成int類型return (int) (value * scale + 0.5f);}public static int px2dp(Context context, float value) {final float scale = context.getResources().getDisplayMetrics().density;// px轉(zhuǎn)換成dp,value/densityreturn (int) (value / scale + 0.5f);} }注意:因?yàn)榉直媛什灰粯?#xff0c;所以不能用px;因?yàn)槠聊粚挾炔灰粯?#xff0c;所以要小心的用dp。
解決方案
一、支持各種屏幕尺寸
1、使用wrap_content、math_parent、weight
wrap_content:根據(jù)控件的內(nèi)容設(shè)置控件的尺寸
math_parent:根據(jù)父控件的尺寸大小設(shè)置控件的尺寸
weight:權(quán)重,在線性布局中可以使用weight屬性設(shè)置控件所占的比例
實(shí)現(xiàn)下圖所顯示的效果:當(dāng)屏幕尺寸改變時(shí),new reader控件兩邊的控件大小不變,new reader控件會(huì)占完剩余的空間。
android:layout_weight
公式:所占寬度=原來(lái)寬度+剩余空間所占百分比的寬度
2、使用相對(duì)布局,禁用絕對(duì)布局
簡(jiǎn)單的布局一般都使用線性布局,而略微復(fù)雜點(diǎn)的布局,我們使用相對(duì)布局,大多數(shù)時(shí)候,我們都是使用這兩種布局的嵌套。我們使用相對(duì)布局的原因是,相對(duì)布局能在各種尺寸的屏幕上保持控件間的相對(duì)位置。
3、使用限定符
一、使用尺寸限定符
當(dāng)我們要在大屏幕上顯示不同的布局,就要使用large限定符。例如,在寬的屏幕左邊顯示列表右邊顯示列表項(xiàng)的詳細(xì)信息,在一般寬度的屏幕只顯示列表,不顯示列表項(xiàng)的詳細(xì)信息,我們就可以使用large限定符。
單面板:res/layout/activity_qualifier.xml
雙面板:res/layout-large/activity_qualifier.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><fragmentandroid:id="@+id/news_title_fragment"android:name="com.jun.androidexample.qualifier.NewsTitleFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/><FrameLayoutandroid:id="@+id/news_content_layout"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="3"><fragmentandroid:id="@+id/news_content_fragment"android:name="com.jun.androidexample.qualifier.NewsContentFragment"android:layout_width="match_parent"android:layout_height="match_parent"/></FrameLayout> </LinearLayout>如果這個(gè)程序運(yùn)行在屏幕尺寸大于7inch的設(shè)備上,系統(tǒng)就會(huì)加載res/layout-large/main.xml 而不是res/layout/main.xml,在小于7inch的設(shè)備上就會(huì)加載res/layout/main.xml。
注意:這種通過(guò)large限定符分辨屏幕尺寸的方法,只適用于android3.2之前。在android3.2之后,為了更精確地分辨屏幕尺寸大小,Google推出了最小寬度限定符。
二、使用最小寬度限定符
最小寬度限定符的使用和large基本一致,只是使用了具體的寬度限定。
單面板:res/layout/activity_qualifier.xml
雙面板:res/layout-sw600dp/activity_qualifier.xml,Small Width最小寬度
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><fragmentandroid:id="@+id/news_title_fragment"android:name="com.jun.androidexample.qualifier.NewsTitleFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/><FrameLayoutandroid:id="@+id/news_content_layout"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="3"><fragmentandroid:id="@+id/news_content_fragment"android:name="com.jun.androidexample.qualifier.NewsContentFragment"android:layout_width="match_parent"android:layout_height="match_parent"/></FrameLayout> </LinearLayout>這就要求我們維護(hù)兩個(gè)相同功能的文件,為了避免繁瑣操作,我們就要使用布局別名。
三、使用布局別名
單面板:res/layout/activity_qualifier.xml
雙面板:res/layout-large/activity_qualifier.xml
雙面板:res/layout-sw600dp/activity_qualifier.xml
因?yàn)殡p面板的布局一樣,所以為了方便管理使用以下2個(gè)文件代替上面的3個(gè)文件。
單面板:res/layout/activity_qualifier_onepane.xml
雙面板:res/layout/activity_qualifier_twopanes.xml
然后創(chuàng)建如下3個(gè)文件
默認(rèn)布局,單面板:res/values/layout.xml
Android3.2之前的大屏布局,雙面板:res/values-large/layout.xml
<resources><item name="activity_qualifier" type="layout">@layout/activity_qualifier_twopanes</item> </resources>Android3.2之后的大于600dp屏布局,雙面板:res/values-sw600dp/layout.xml
<resources><item name="activity_qualifier" type="layout">@layout/activity_qualifier_twopanes</item> </resources>這樣無(wú)論是哪一種名字都叫activity_qualifier。
記得將之前創(chuàng)建的res/layout-large和res/layout-sw600dp
雙面板:res/layout-large/activity_qualifier.xml
雙面板:res/layout-sw600dp/activity_qualifier.xml,Small Width最小寬度
都刪掉,因?yàn)橐呀?jīng)不需要了。
四、使用屏幕方向限定符
res/values-port/layout.xml,縱向,單面板
<resources><item name="activity_qualifier" type="layout">@layout/activity_qualifier_onepane</item> </resources>res/values-land/layout.xml,橫向,雙面板
<resources><item name="activity_qualifier" type="layout">@layout/activity_qualifier_twopanes</item> </resources>4、使用自動(dòng)拉伸位圖
.9.png格式圖片
二、支持各種屏幕密度
1、統(tǒng)一劃分
統(tǒng)一劃分解決分辨率不一致,寬高不一致的問(wèn)題。把需要適配的手機(jī)屏幕的寬度像素均分為320份,高度像素均分為480份。使用我們寫(xiě)好的程序自動(dòng)生成資源values-×文件夾,里面包含lay_x.xml和lay_y.xml,分別對(duì)應(yīng)寬度和高度的像素。
在Eclipse中運(yùn)行如下代碼自動(dòng)生成需要的文件
/*** 將所有不同分辨率的屏幕都分成480x320*/ public class MakeXml {// 生成文件存放的地址是C:\layoutRootprivate final static String rootPath = "C:\\layoutRoot\\values-{0}x{1}\\";// 分成480x320private final static float dw = 320f;private final static float dh = 480f;private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n";private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n";public static void main(String[] args) {setResolution();}// 設(shè)置需要適配的不同屏幕的分辨率public static void setResolution(){makeString(320, 480);makeString(480, 800);makeString(480, 854);makeString(540, 960);makeString(600, 1024);makeString(720, 1184);makeString(720, 1196);makeString(720, 1280);makeString(768, 1024);makeString(800, 1280);makeString(1080, 1812);makeString(1080, 1920);makeString(1440, 2560);}public static void makeString(int w, int h) {StringBuffer sb = new StringBuffer();sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");sb.append("<resources>");float cellw = w / dw;for (int i = 1; i < 320; i++) {sb.append(WTemplate.replace("{0}", i + "").replace("{1}",change(cellw * i) + ""));}sb.append(WTemplate.replace("{0}", "320").replace("{1}", w + ""));sb.append("</resources>");StringBuffer sb2 = new StringBuffer();sb2.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");sb2.append("<resources>");float cellh = h / dh;for (int i = 1; i < 480; i++) {sb2.append(HTemplate.replace("{0}", i + "").replace("{1}",change(cellh * i) + ""));}sb2.append(HTemplate.replace("{0}", "480").replace("{1}", h + ""));sb2.append("</resources>");String path = rootPath.replace("{0}", h + "").replace("{1}", w + "");File rootFile = new File(path);if (!rootFile.exists()) {rootFile.mkdirs();}File layxFile = new File(path + "lay_x.xml");File layyFile = new File(path + "lay_y.xml");try {PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));pw.print(sb.toString());pw.close();pw = new PrintWriter(new FileOutputStream(layyFile));pw.print(sb2.toString());pw.close();} catch (FileNotFoundException e) {e.printStackTrace();}}public static float change(float a) {int temp = (int) (a * 100);return temp / 100f;} }將C:\layoutRoot目錄下的文件拷貝到Android Studio中app/src/main/res/目錄下
使用示例:
<Buttonandroid:background="#abd123"android:layout_width="@dimen/x160"android:layout_height="@dimen/y240"/>寬和高都是屏幕的一半
2、提供備用位圖
針對(duì)不同分辨率的屏幕提供不同分辨率的位圖
res/drawable-mdpi
res/drawable-hdpi
res/drawable-xhdpi
res/drawable-xxhdpi
res/drawable-xxxhdpi
如果只提供一張位圖就應(yīng)該放置在應(yīng)對(duì)分辨率的文件夾中
三、實(shí)施自適應(yīng)用戶界面流程
1、確定當(dāng)前布局
boolean isTwoPane; // 能找到news_content_layout就是雙頁(yè)否則就是單頁(yè) View view = getActivity().findViewById(R.id.news_content_layout); if (view != null && view.getVisibility() == View.VISIBLE) {isTwoPane = true; } else {isTwoPane = false; }2、根據(jù)當(dāng)前布局做出響應(yīng)
在單面板模式下,用戶點(diǎn)擊了新聞標(biāo)題,我們要打開(kāi)一個(gè)新的Activity來(lái)顯示新聞詳細(xì)信息;在雙面板模式下,用戶點(diǎn)擊了新聞標(biāo)題,我們要在右邊面板上顯示詳細(xì)信息。
Percent Support Library(百分比布局庫(kù))
添加依賴
compile 'com.android.support:percent:23.3.0'總結(jié)
以上是生活随笔為你收集整理的总结Android屏幕适配(源自简书:李俊的博客)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 熊猫烧香制造者李俊出狱以后的六种出路
- 下一篇: Android版火狐无法同步,Firef