Android屏幕values-sw适配

来源:互联网 发布:安卓手机vb6.0编程软件 编辑:程序博客网 时间:2024/05/16 13:51

一、适配原则

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

二、计算原则

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

三、便捷小工具开发

为了方便开发进行开发,快速在项目中添加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文件 * <p> * 只要对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<Integer> 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, "</dimen>", reWrite)) {                    reWrite = handleMiddleDimen(uiPx, pre, value, lineString, dimens);                    if (isExistPxBreak) {                        isExistPxBreak = false;                        break;                    }                } else if (isLineEndWithTagNotWrite(lineString.trim(), "</resources>", 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<String> 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<String> 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<String> dimens = new ArrayList<>();        String str = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";        dimens.add(str);        str = "<resources>\n";        dimens.add(str);        str = "  <!-- Default screen margins, per the Android Design guidelines.\n" +                "    1、尺寸标记的计算规则:\n" +                "       由于UI给的是IOS的UI图,所以该文件转换的规则为 (UI标注的px/2)\n" +                "       每增加一个尺寸需要在sw360dp添加对应的,转换公式为(360/320)x 基础dimens参数,其中360为对应的文件夹的名称 \n" +                "    2、字体的计算规则:\n" +                "       默认的/320文件夹下的为 (UI标注值/2 -1) \n" +                "       360的为 (UI标注值/2 )\n" +                "       480的为 (UI标注值/2 +1 )\n" +                "    -->\n";        dimens.add(str);        str = getConvertAttrForXml(uiPx, value, pre);        dimens.add(str + "\n");        str = "</resources>\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("    <dimen name=\"%s_%dpx\">%sdp</dimen>", 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("    <dimen name=\"%s%s_%d\">%ssp</dimen>", 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<String> 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;    }}
0 0