文章大綱 一、屏幕適配是什麼二、 重要概念講解三、屏幕適配實戰四、項目源碼下載 一、屏幕適配是什麼 Android中屏幕適配就是通過對尺寸單位、圖片、文字、佈局這四種類型的資源進行合理的設計和規劃,在佈局時合理利用各種類型的資源,讓佈局擁有適應能力,能在各種設備下保持良好的展現效果。 二、常見屏幕適 ...
文章大綱
一、屏幕適配是什麼
二、 重要概念講解
三、屏幕適配實戰
四、項目源碼下載
一、屏幕適配是什麼
Android中屏幕適配就是通過對尺寸單位、圖片、文字、佈局這四種類型的資源進行合理的設計和規劃,在佈局時合理利用各種類型的資源,讓佈局擁有適應能力,能在各種設備下保持良好的展現效果。
二、常見屏幕適配方法介紹
1 屏幕尺寸
屏幕尺寸是指屏幕對角線的長度,單位是英寸,1英寸=2.54釐米
2 屏幕解析度
屏幕解析度是指橫縱向上的像素點數,單位是px,1px=1個像素點,一般以縱向像素橫向像素,如19201080,解析度越高,顯示效果越好。
3 屏幕像素密度
屏幕像素密度是指每英寸上的像素點數,單位是dpi,屏幕像素密度與屏幕尺寸和屏幕解析度有關。
4. px、dp、sp
(1)安卓裡面獲取屏幕寬和高,也是以px作為單位的。
(2)在160dpi(即解析度是480*320)基準下,1dip=1px(也就是px不能適配所有機型),如下圖所示,要充滿屏幕,箭頭的px值是不一樣的。1dp=那個機型dpi/160px。所以用dp會比px好。
(3)在使用sp(設置文字的)時候,使用偶數,不要使用奇數或者小數,最最推薦的是12.14.18,22sp的文字大小(儘量不要使用12sp以下的大小,用戶可能看不清楚)。
5. mdpi,hdpi,xdpi,xxdpi
安卓軟體運行時,會自動根據屏幕像素去不同文件夾載入對應圖片。
三、屏幕適配實戰
1. 使用dp設置控制項大小,sp設置字體大小(不可行)
activity_main2.xml佈局代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="200dp"
android:layout_height="50dp"
android:textSize="20sp"
android:text="按鈕1"/>
<Button
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_marginTop="20dp"
android:textSize="20sp"
android:text="按鈕2"/>
</LinearLayout>
運行結果如下:
得出結論:即使使用dp設置控制項大小,sp設置字體大小,也是無法適配所有手機的。因為這是谷歌自己的一個標準。dp是根據屏幕像素和解析度一起來解決的。但是有些手機像素和解析度不是對應關係,所以不行。
2. weight屬性使用
activity_main3.xml佈局代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="20sp"
android:text="按鈕1"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:textSize="20sp"
android:text="按鈕2"/>
</LinearLayout>
運行結果如下:
得出結論:採用weight,可以使得組件按屏幕大小進行放大縮小,weight的計算方式如下:
如果將xml中的android:layout_weight屬性值1和2互換,則結果是相反的,有興趣伙伴可以下載源碼看看效果。
3. 使用自動拉伸點陣圖.9圖
什麼是.9圖
因為Android有太多的解析度了,當圓角矩形控制項在被拉伸放大的時候,圓角的部分就會出現模糊的情況。而點九切圖就不同,它可以保證不管你上下還是左右拉伸,放大都可以保持原有的清晰度。
.9圖存放位置
4. 屏幕方向限定符large
比如我們想在屏幕豎屏時候載入什麼佈局,在屏幕橫線時候載入什麼佈局。在手機載入什麼佈局,在平板電腦載入什麼佈局。
該文章暫不展開討論,將在Fragment使用中進行講解。
5.多文件適配(重要)
大家經過上面的學習之後,已經知道有些手機像素和解析度不是對應關係,無法使用dp等單位來解決,那麼我們可以以某個常見的屏幕解析度作為基準,自定義需要適配到的屏幕解析度的xml文件,如下圖所示:
使用生成器生成對應的文件
生成器代碼(使用320*480作為基準)如下:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
/**
* Created by 吳曉暢
*/
public class GenerateValueFiles {
private int baseW;
private int baseH;
private String dirStr = "./res";
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";
private final static String VALUE_TEMPLATE = "values-{0}x{1}";
//新增文件的解析度,以x,x;隔開
private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,960;600,1024;720,1184;720,1196;720,1280;768,1024;768,1280;800,1280;1080,1812;1080,1920;1440,2560;";
private String supportStr = SUPPORT_DIMESION;
public GenerateValueFiles(int baseX, int baseY, String supportStr) {
this.baseW = baseX;
this.baseH = baseY;
if (!this.supportStr.contains(baseX + "," + baseY)) {
this.supportStr += baseX + "," + baseY + ";";
}
this.supportStr += validateInput(supportStr);
System.out.println(supportStr);
File dir = new File(dirStr);
if (!dir.exists()) {
dir.mkdir();
}
System.out.println(dir.getAbsoluteFile());
}
private String validateInput(String supportStr) {
StringBuffer sb = new StringBuffer();
String[] vals = supportStr.split("_");
int w = -1;
int h = -1;
String[] wh;
for (String val : vals) {
try {
if (val == null || val.trim().length() == 0)
continue;
wh = val.split(",");
w = Integer.parseInt(wh[0]);
h = Integer.parseInt(wh[1]);
} catch (Exception e) {
System.out.println("skip invalidate params : w,h = " + val);
continue;
}
sb.append(w + "," + h + ";");
}
return sb.toString();
}
public void generate() {
String[] vals = supportStr.split(";");
for (String val : vals) {
String[] wh = val.split(",");
generateXmlFile(Integer.parseInt(wh[0]), Integer.parseInt(wh[1]));
}
}
private void generateXmlFile(int w, int h) {
StringBuffer sbForWidth = new StringBuffer();
sbForWidth.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sbForWidth.append("<resources>");
float cellw = w * 1.0f / baseW;
System.out.println("width : " + w + "," + baseW + "," + cellw);
for (int i = 1; i < baseW; i++) {
sbForWidth.append(WTemplate.replace("{0}", i + "").replace("{1}",
change(cellw * i) + ""));
}
sbForWidth.append(WTemplate.replace("{0}", baseW + "").replace("{1}",
w + ""));
sbForWidth.append("</resources>");
StringBuffer sbForHeight = new StringBuffer();
sbForHeight.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sbForHeight.append("<resources>");
float cellh = h *1.0f/ baseH;
System.out.println("height : "+ h + "," + baseH + "," + cellh);
for (int i = 1; i < baseH; i++) {
sbForHeight.append(HTemplate.replace("{0}", i + "").replace("{1}",
change(cellh * i) + ""));
}
sbForHeight.append(HTemplate.replace("{0}", baseH + "").replace("{1}",
h + ""));
sbForHeight.append("</resources>");
File fileDir = new File(dirStr + File.separator
+ VALUE_TEMPLATE.replace("{0}", h + "")//
.replace("{1}", w + ""));
fileDir.mkdir();
File layxFile = new File(fileDir.getAbsolutePath(), "lay_x.xml");
File layyFile = new File(fileDir.getAbsolutePath(), "lay_y.xml");
try {
PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
pw.print(sbForWidth.toString());
pw.close();
pw = new PrintWriter(new FileOutputStream(layyFile));
pw.print(sbForHeight.toString());
pw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static float change(float a) {
int temp = (int) (a * 100);
return temp / 100f;
}
public static void main(String[] args) {
//基準大小,比如320.480,其他則以這個基準進行放大縮小
int baseW = 320;
int baseH = 480;
String addition = "";
try {
if (args.length >= 3) {
baseW = Integer.parseInt(args[0]);
baseH = Integer.parseInt(args[1]);
addition = args[2];
} else if (args.length >= 2) {
baseW = Integer.parseInt(args[0]);
baseH = Integer.parseInt(args[1]);
} else if (args.length >= 1) {
addition = args[0];
}
} catch (NumberFormatException e) {
System.err
.println("right input params : java -jar xxx.jar width height w,h_w,h_..._w,h;");
e.printStackTrace();
System.exit(-1);
}
new GenerateValueFiles(baseW, baseH, addition).generate();
}
}
運行代碼,結果會在項目的res文件夾中生成對應的內容,如下圖所示:
溫馨提示:上圖每個文件夾是以320*480作為基準進行放大縮小後的px值
將上面生成的文件夾複製到實際項目中
複製所有文件夾,右擊studio中的res文件夾進行粘貼
xml佈局中進行引用
activity_main4.xml代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="@dimen/x200"
android:layout_height="@dimen/y30"
android:text="按鈕1"/>
<Button
android:layout_width="@dimen/x200"
android:layout_height="@dimen/y30"
android:layout_marginTop="@dimen/y30"
android:text="按鈕2"/>
</LinearLayout>
運行結果如下圖所示:
溫馨提示:
- 如果運行後發現某個尺寸的屏幕沒有是配到,那麼可以在生成器中添加對應屏幕尺寸,重新生成文件夾,之後拷貝到項目中即可
- 圖片適配則可以採用圖片放在不同文件夾裡面,系統會自動選圖,但最好每次切圖都包含多種解析度的圖片,例如某一測試的機器是xxhdpi密度的,所以當把圖片放在xxhdpi時候(其他文件夾沒放),載入時候占用記憶體是較小的。預設是沒有載入任何東西(運行一個空白app)占用的記憶體。如果載入其他像素下的圖片,則會占用很多內容。所以總結來說就是要各個文件夾都放有圖片,可以減少占用記憶體的載入。
四、項目源碼下載
鏈接:https://pan.baidu.com/s/1xDRVaSS9Kk9OGLzloBeneA
提取碼:0zyt