Android屏幕values-sw适配

一、适配原则

  • Android3.2之后可以通过values后面添加不同的后缀进行适配不同的手机的布局。因为项目中采用了values-sw的方式,所以针对该种方式做了自己的一些调研和研究。
  • values-sw360dp,sw理解为smallwidth,该最小宽度的计算方式为:屏幕宽度/屏幕密度。其中屏幕宽度为metric.widthPixels/metric.density。通过对一些手机进行打印计算,发现大多数该值都是在320dp~360dp范围内,所以在项目中配置了默认的values和values-sw360dp文件夹。当计算出来的值既不是values也不是360时,会按照最接近360还是values进行读取相关文件夹里面的值。

二、计算原则

    其中两个文件夹里面的dimen计算原则如下:
  • values默认的为1dp对应2px,将px转换成dp,作为基础值。
  • values-sw360dp,按照360xvalues基础值/320,将values基础值对应的dp转换成在sw360dp对应的该px下对应的dp。
  • 统一以dimes_xxpx进行命名,方便开发人员进行使用该值。
  • 举例说明下: 20px->在values下写入的就是 10dp ->在values-sw360dp下就是11.25dp

三、便捷小工具开发

    为了方便开发进行开发,快速在项目中添加px值,同时也为了统一开发的适配原则,开发小工具协助开发添加px,想添加px时,只要在项目中运行main方法即可,代码如下:
package com.library;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by wenjing.liu on 17/4/27.
 * 自动生成dimens.xml文件
 * 

* 只要对main方法里面的调用方法的参数配置下就可以完成自动添加UI工程师给定的dimen尺寸. * 具体的还在完善中...2017/05/03 * 1、支持添加UI标记的尺寸对应'DIMEN'标记 * 2、支持添加UI标记的字体对应'F'标记 * 3、尺寸标记的计算规则:(不支持奇数尺寸) * 由于UI给的是IOS的UI图,所以该文件转换的规则为 (UI标注的px/2) * 每增加一个尺寸需要在sw360dp添加对应的,转换公式为(360/320)x 基础dimens参数,其中360为对应的文件夹的名称 * 4、字体的计算规则:(不支持>99的字体大小) * 默认的/320文件夹下的为 (UI标注值/2 -1) * 360/400的为 (UI标注值/2 ) * 480的为 (UI标注值/2 +1 ) 完工2017/05/04 by wenjing.liu */ public class DimenAutoAddManager { /** * 对应的文件夹的根路径 */ private static final String VALUE_ROOT_PATH = "./app/src/main/res/values"; /** * 对应的不同类型的文件夹 */ private static final int VALUE = 0; private static final int VALUE320 = 320; private static final int VALUE360 = 360; private static final int VALUE400 = 400; private static final int VALUE480 = 480; /*** * 不同的生成name的前缀 */ private static final String DIMEN = "dimen"; //对应的UI标记尺寸 private static final String F = "f"; //对应的字体 /*** * 对应的UI设计的标准,是按照640p还是1080p */ private enum Rule { UI640P, UI1080P } private static List officialFont = new ArrayList(); public static void main(String[] args) { initOfficialFont(); for (int i = 28; i < 90; i += 4) { autoAddDimensForDifferentValue(i, DIMEN); } autoAddDimensForDifferentValue(34, F); autoAddDimensForDifferentValue(30, F); autoAddDimensForDifferentValue(28, F); autoAddDimensForDifferentValue(24, F); } /*** * 默认 对应生成是values和values-sw360dp下对应的dimens.xml文件 * @param uiPx UI工程师标记的UI尺寸 * @param pre 生成dimen的name对应的前缀 */ private static void autoAddDimensForDifferentValue(int uiPx, String pre) { autoAddDimensForDifferentValue(uiPx, pre, VALUE); autoAddDimensForDifferentValue(uiPx, pre, VALUE360); } /*** * * @param uiPx UI工程师标记的UI尺寸 * @param pre 生成dimen的name对应的前缀 * @param value 对应生成是values/values-sw360dp...下对应的dimens.xml文件 */ private static void autoAddDimensForDifferentValue(int uiPx, String pre, int value) { if (uiPx % 2 != 0) { systemOutPrintln("Warning: do not define odd px , you can + 1 or - 1 !", (Object)null); return; } if (uiPx > 99 && F.equals(pre)) { systemOutPrintln("Warning: do not define font > 99 !",(Object) null); return; } File file = getXmlFileByValue(value); if (file == null) { return; } if (file.length() <= 0) { //说明是个空文件,要将xml文件写好 writeForEmptyDimenXml(uiPx, pre, value, file); return; } //写入一个已经存在的xml文件 writeForExistDimenXml(uiPx, pre, value, file); } private static boolean hasPre = false; //是否存在过该前缀 private static boolean isExistPxBreak = false;//是否需要中断该次循环 /*** * 已经有dimens.xml文件了 * @param uiPx * @param pre * @param value * @param file */ private static void writeForExistDimenXml(int uiPx, String pre, int value, File file) { boolean reWrite = false; List dimens = new ArrayList(); BufferedReader reader = null; hasPre = false;// 已经存在过对应的pre标签的定义 isExistPxBreak = false; //是否需要中断该次循环 try { reader = new BufferedReader(new FileReader(file)); String lineString; while ((lineString = reader.readLine()) != null) { //写过了就不用在写了!!!!! if (isLineEndWithTagNotWrite(lineString, "", reWrite)) { reWrite = handleMiddleDimen(uiPx, pre, value, lineString, dimens); if (isExistPxBreak) { isExistPxBreak = false; break; } } else if (isLineEndWithTagNotWrite(lineString.trim(), "", reWrite)) { //已经是最后一个标签了,但是reWrite还是false,说明是最大一个 reWrite = handleMaxDimen(uiPx, pre, value, dimens); } //其他不需要处理的dimen一直都到dimens集合中 dimens.add(lineString); } systemOutPrintln("You have finished to read %d dimens .", dimens.size()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (reader != null) reader.close(); } catch (IOException e) { e.printStackTrace(); } } if (!reWrite) return; writeDimenXml(uiPx + "px", dimens, file); } /*** * 该行是不是以tag结尾 * @param lineString * @param tag * @return */ private static boolean isLineEndWithTagNotWrite(String lineString, String tag, boolean isWrited) { return lineString.endsWith(tag) && !isWrited; } /*** * 该uiPx是中间的大小,要按照从小到大的顺序插入到集合中 * @param uiPx * @param pre * @param value * @param lineString * @param dimens * @return true插入成功 */ private static boolean handleMiddleDimen(int uiPx, String pre, int value, String lineString, List dimens) { boolean isSuccess = false; String name = getDimenNameFromAttr(lineString); //截取dimen_20px,即属性名 int pXing = getUiPxFromAttr(name); String existName = getPreFromAttr(name); //systemOutPrintln("existName = " + existName + " , pXing = " + pXing, null); //如果是字体,要将标准的三位只取后两位 if (existName.contains(F) && pXing > 99) { pXing = pXing % 100; //只取后两位 } if (existName.contains(pre)) { hasPre = true; //即使重复不添加 if (uiPx == pXing) { systemOutPrintln("Warning: You has already added %dpx .", uiPx); isSuccess = false; isExistPxBreak = true; } else if (uiPx < pXing) { // 先加入小的 dimens.add(getConvertAttrForXml(uiPx, value, pre)); //该UI像素值恰好为中间像素,转换完之后,在add到list里面 isSuccess = true; } return isSuccess; } if (!hasPre) { //没有添加过该前缀,也没有该前缀 return isSuccess; } //已经不存在该pre标签了,但是之前已经有过该标签,标示已经是最大的uiPx了,所以仍要累加到最后 dimens.add(getConvertAttrForXml(uiPx, value, pre)); isSuccess = true; return isSuccess; } /*** * 该uiPx是所有中最大的一个尺寸 * @param uiPx * @param pre * @param value * @param dimens * @return */ private static boolean handleMaxDimen(int uiPx, String pre, int value, List dimens) { dimens.add(getConvertAttrForXml(uiPx, value, pre)); return true; } /*** * 第一次往dimen.xml文件中写dimens * @param uiPx * @param pre * @param value * @return */ private static void writeForEmptyDimenXml(int uiPx, String pre, int value, File file) { List dimens = new ArrayList<>(); String str = "\n"; dimens.add(str); str = "\n"; dimens.add(str); str = " \n"; dimens.add(str); str = getConvertAttrForXml(uiPx, value, pre); dimens.add(str + "\n"); str = "\n"; dimens.add(str); systemOutPrintln("You are lucky , you first write %d size for dimens.xml !", dimens.size()); writeDimenXml(uiPx + "px", dimens, file); } /*** * 初始化UI规定的6种字体值 */ private static void initOfficialFont() { officialFont.add(48); officialFont.add(36); officialFont.add(34); officialFont.add(30); officialFont.add(28); officialFont.add(24); } /*** * 根据不同的前缀获得对应的字符串 * @param uiPx * @param value * @param pre * @return */ private static String getConvertAttrForXml(int uiPx, int value, String pre) { if (DIMEN.startsWith(pre)) { return getConvertDimenForXml(uiPx, value); } else if (F.startsWith(pre)) { return getConvertFontForXml(uiPx, value); } return ""; } /*** * 得到写入xml文件中的定义的dimen * @param uiPx UI标记的尺寸 * @param value 是写入value还是value-swxxx文件中 * @return */ private static String getConvertDimenForXml(int uiPx, int value) { String result = getConvertDimensByRule(uiPx, value); String lineString = String.format(" %sdp", DIMEN, uiPx, result); systemOutPrintln("You will add %dpx, to \"%s\"in dimens.xml !", uiPx, lineString); return lineString; } /*** * 得到对应的UI设计的字体 * @param uiFont UI标记的尺寸 * @param value 是写入value还是value-swxxx文件中 * @return */ private static String getConvertFontForXml(int uiFont, int value) { String result = getConvertFontByRule(uiFont, value); String addPre = uiFontInOfficialFont(uiFont); String lineString = String.format(" %ssp", F, addPre, uiFont, result); systemOutPrintln("You will add %d f, to \"%s\"in dimens.xml !", uiFont, lineString); return lineString; } /*** * 获得字体对应的前缀 * @param font * @return */ private static String uiFontInOfficialFont(int font) { int result = officialFont.indexOf(font) + 1; if (result == 0) return ""; return String.format("0%d", result); } /*** *获得对应转换的dp值,默认为rule为640p * @param uiPx * @param value 320 360.... * @return */ private static String getConvertDimensByRule(int uiPx, int value) { return getConvertDimensByRule(uiPx, Rule.UI640P, value); } /*** * 获得对应转换的dp值 * @param uiPx * @param rule 640p还是1080p * @param value 320 360.... * @return */ private static String getConvertDimensByRule(int uiPx, Rule rule, int value) { double result = 1; double multiple = 1; float valueTimes = value <= 320 ? 1 : value / 320.0f; //对应不同的文件夹获得的dp switch (rule) { case UI640P: multiple = 1.0 / 2.0 * valueTimes; //2.0 为IOS 640P的时候1:2px break; case UI1080P: multiple = 1.0 / 2.5 * valueTimes;//2.0 为IOS 1080P的时候1:2.5px break; } result = result * multiple * uiPx; String back = formatResultByTwoDecimal(result); return back; } /*** * 根据规则转换对应的字体大小对应值 * @param uiFont * @param value 320 360.... * @return */ private static String getConvertFontByRule(int uiFont, int value) { int font = uiFont / 2; switch (value) { case VALUE: case VALUE320: font = font - 1; break; case VALUE480: font = font + 1; break; } return String.valueOf(font); } /*** * 保留两位小数 * @param dimen * @return */ private static String formatResultByTwoDecimal(double dimen) { DecimalFormat dFormat = new DecimalFormat("0.00"); String result = dFormat.format(dimen); return result; } /*** * 写xml文件 * @param dimenResult * @param rewrite */ private static void writeDimenXml(String dimenResult, List rewrite, File file) { systemOutPrintln("You will write %s in dimens.xml, all dimens size is %d .", dimenResult, rewrite.size()); BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(file, false)); for (String str : rewrite) writer.write(str + "\n"); writer.close(); systemOutPrintln("You write dimens.xml success.", (Object)null); } catch (IOException e) { e.printStackTrace(); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } } /*** * 屏幕输出 * @param format * @param args */ private static void systemOutPrintln(boolean isDebug, String format, Object... args) { if (isDebug) System.out.println(String.format(format, args)); } /*** * 屏幕输出 * @param format * @param args */ private static void systemOutPrintln(String format, Object... args) { systemOutPrintln(true, format, args);// 默认应为true } /*** * 获得dimen.xml * @param value * @return */ private static File getXmlFileByValue(int value) { String suffix = value <= 0 ? "/" : "-sw" + value + "dp/"; String folderPath = VALUE_ROOT_PATH + suffix; String path = folderPath + "dimens.xml"; File file = new File(path); if (file.exists()) return file; try { File folder = new File(folderPath); if (!folder.exists()) folder.mkdirs(); boolean isCreate = file.createNewFile(); if (isCreate) return file; } catch (IOException e) { e.printStackTrace(); } return null; } private static String getDimenNameFromAttr(String lineString) { int start = lineString.indexOf("\""); int end = lineString.lastIndexOf("\""); String name = lineString.substring(start + 1, end); //截取dimen_20px,即属性名 return name; } /*** * 从属性中获取字符串的UI标记尺寸,方便把要加入的尺寸放入到xml文件中 * @param attr * @return */ private static int getUiPxFromAttr(String attr) { int result = -1; String rule = "[^0-9]"; Pattern p = Pattern.compile(rule); Matcher matcher = p.matcher(attr); try { result = Integer.parseInt(matcher.replaceAll("")); } catch (Exception e) { } return result; } /*** * 获取属性中的前缀,是dimen/f/size * @param attr * @return */ private static String getPreFromAttr(String attr) { String result = null; String rule = "[^a-z^A-Z]"; Pattern p = Pattern.compile(rule); Matcher matcher = p.matcher(attr); try { result = matcher.replaceAll(""); } catch (Exception e) { } return result; } }

你可能感兴趣的:(android基本知识)