├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── duke │ │ └── phonescreenmatch_test │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── duke │ │ │ └── phonescreenmatch_test │ │ │ ├── MainActivity.java │ │ │ ├── dp │ │ │ ├── DimenItem.java │ │ │ ├── Main.java │ │ │ ├── SAXReadHandler.java │ │ │ ├── Tools.java │ │ │ └── XmlIO.java │ │ │ └── px │ │ │ └── GenerateValueFiles.java │ ├── res │ │ ├── layout │ │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ ├── values-sw1024dp │ │ │ └── dimens.xml │ │ ├── values-sw1280dp │ │ │ └── dimens.xml │ │ ├── values-sw384dp │ │ │ └── dimens.xml │ │ ├── values-sw392dp │ │ │ └── dimens.xml │ │ ├── values-sw400dp │ │ │ └── dimens.xml │ │ ├── values-sw410dp │ │ │ └── dimens.xml │ │ ├── values-sw411dp │ │ │ └── dimens.xml │ │ ├── values-sw480dp │ │ │ └── dimens.xml │ │ ├── values-sw533dp │ │ │ └── dimens.xml │ │ ├── values-sw592dp │ │ │ └── dimens.xml │ │ ├── values-sw600dp │ │ │ └── dimens.xml │ │ ├── values-sw640dp │ │ │ └── dimens.xml │ │ ├── values-sw662dp │ │ │ └── dimens.xml │ │ ├── values-sw720dp │ │ │ └── dimens.xml │ │ ├── values-sw768dp │ │ │ └── dimens.xml │ │ ├── values-sw800dp │ │ │ └── dimens.xml │ │ ├── values-sw811dp │ │ │ └── dimens.xml │ │ ├── values-sw820dp │ │ │ └── dimens.xml │ │ ├── values-sw960dp │ │ │ └── dimens.xml │ │ ├── values-sw961dp │ │ │ └── dimens.xml │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── screenMatchDP.bat │ ├── screenMatchDP.jar │ ├── screenMatchPX.bat │ └── screenMatchPX.jar │ └── test │ └── java │ └── com │ └── duke │ └── phonescreenmatch_test │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── res └── values │ └── dimens.xml ├── screenMatch.properties ├── screenMatchDP.bat ├── screenMatchDP.jar ├── screenMatchPX.bat ├── screenMatchPX.jar ├── screenMatch_example_dimens.xml ├── settings.gradle └── values └── dimens.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PhoneScreenMatch -- (Android Studio) 2 | * 两套屏幕适配方案源码分享,dp和px。 3 | * 或者在项目中直接使用已经打包好的jar和bat工具。 4 | 5 | ##适配原理和用法请参考[我的csdn博客](http://blog.csdn.net/fesdgasdgasdg/article/details/52325590 "适配方案详解") 6 | 7 | Android Studio plugin source code : https://github.com/mengzhinan/ScreenMatch 8 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.duke.phonescreenmatch_test" 7 | minSdkVersion 15 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:26.1.0' 24 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 28 | } 29 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/duke/phonescreenmatch_test/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.duke.phonescreenmatch_test; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/duke/phonescreenmatch_test/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.duke.phonescreenmatch_test; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.util.DisplayMetrics; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.Button; 10 | import android.widget.TextView; 11 | 12 | /** 13 | * 获取手机屏幕相关数据 14 | */ 15 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 16 | private TextView show; 17 | private Button get; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | get = (Button) findViewById(R.id.get_btn); 24 | get.setOnClickListener(this); 25 | 26 | show = (TextView) findViewById(R.id.show_tv); 27 | show.setText(getScreenParams()); 28 | data(); 29 | } 30 | 31 | private void data() { 32 | Log.v("Build.BOARD",""+ Build.BOARD); 33 | Log.v("Build.BOOTLOADER",""+ Build.BOOTLOADER); 34 | Log.v("Build.BRAND",""+ Build.BRAND); 35 | Log.v("Build.DEVICE",""+ Build.DEVICE); 36 | Log.v("Build.DISPLAY",""+ Build.DISPLAY); 37 | Log.v("Build.FINGERPRINT",""+ Build.FINGERPRINT); 38 | Log.v("Build.HARDWARE",""+ Build.HARDWARE); 39 | Log.v("Build.HOST",""+ Build.HOST); 40 | Log.v("Build.ID",""+ Build.ID); 41 | Log.v("Build.MANUFACTURER",""+ Build.MANUFACTURER); 42 | Log.v("Build.MODEL",""+ Build.MODEL); 43 | Log.v("Build.PRODUCT",""+ Build.PRODUCT); 44 | Log.v("Build.SERIAL",""+ Build.SERIAL); 45 | Log.v("Build.TAGS",""+ Build.TAGS); 46 | Log.v("Build.TYPE",""+ Build.TYPE); 47 | Log.v("Build.UNKNOWN",""+ Build.UNKNOWN); 48 | Log.v("Build.USER",""+ Build.USER); 49 | Log.v("Build.VERSION.SDK_INT",""+ Build.VERSION.SDK_INT); 50 | Log.v("Build.VERSION.CODENAME",""+ Build.VERSION.CODENAME); 51 | Log.v("Build.V.INCREMENTAL",""+ Build.VERSION.INCREMENTAL); 52 | Log.v("Build.VERSION.RELEASE",""+ Build.VERSION.RELEASE); 53 | Log.v("Build.VERSION_CODES.M",""+ Build.VERSION_CODES.M); 54 | } 55 | 56 | @Override 57 | public void onClick(View v) { 58 | show.setText(getScreenParams()); 59 | } 60 | 61 | public String getScreenParams() { 62 | DisplayMetrics dm = new DisplayMetrics(); 63 | // dm = getResources().getDisplayMetrics(); 64 | getWindowManager().getDefaultDisplay().getMetrics(dm); 65 | int heightPixels = dm.heightPixels; 66 | int widthPixels = dm.widthPixels; 67 | float xdpi = dm.xdpi; 68 | float ydpi = dm.ydpi; 69 | int densityDpi = dm.densityDpi; 70 | float density = dm.density; 71 | float scaledDensity = dm.scaledDensity; 72 | float heightDP = heightPixels / density; 73 | float widthDP = widthPixels / density; 74 | String str = "heightPixels: " + heightPixels + "px"; 75 | str += "\nwidthPixels: " + widthPixels + "px"; 76 | str += "\nxdpi: " + xdpi + "dpi"; 77 | str += "\nydpi: " + ydpi + "dpi"; 78 | str += "\ndensityDpi: " + densityDpi + "dpi"; 79 | str += "\ndensity: " + density; 80 | str += "\nscaledDensity: " + scaledDensity; 81 | str += "\nheightDP: " + heightDP + "dp"; 82 | str += "\nwidthDP: " + widthDP + "dp"; 83 | return str; 84 | } 85 | } -------------------------------------------------------------------------------- /app/src/main/java/com/duke/phonescreenmatch_test/dp/DimenItem.java: -------------------------------------------------------------------------------- 1 | package com.duke.phonescreenmatch_test.dp; 2 | 3 | /** 4 | * @Author: duke 5 | * @DateTime: 2016-08-24 17:32 6 | * @UpdateTime: 2017-09-29 09:55 7 | * @Description: dimens文件中的dimen数据项 8 | */ 9 | public class DimenItem { 10 | public String name; 11 | public String value; 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/duke/phonescreenmatch_test/dp/Main.java: -------------------------------------------------------------------------------- 1 | package com.duke.phonescreenmatch_test.dp; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | import java.util.Iterator; 8 | 9 | /** 10 | * @Author: duke 11 | * @DateTime: 2016-08-24 16:16 12 | * @UpdateTime: 2017-09-29 09:55 13 | * @Description: 入口 14 | */ 15 | public class Main { 16 | //基准dp,比喻:360dp 17 | private static final double DEFAULT_DP = 360; 18 | private static double baseDP = DEFAULT_DP; 19 | //默认支持的dp值 20 | private static final String[] defaultDPArr = new String[]{"384", "392", "400", "410", "411", "480", "533", "592", "600", "640", "662", "720", "768", "800", "811", "820", "960", "961", "1024", "1280", "1365"}; 21 | 22 | //生成的values目录格式(代码中替换XXX字符串) 23 | public static String LETTER_REPLACE = "XXX"; 24 | private static String VALUES_OLD_FOLDER = "values-wXXXdp";//values-w410dp,这个目录需要删除 25 | private static String VALUES_NEW_FOLDER = "values-swXXXdp";//values-sw410dp 26 | 27 | //是否删除旧的目录格式 28 | private static final boolean isDeleteAnotherFolder = true; 29 | 30 | //去重复的数据集合 31 | private static HashSet dataSet = new HashSet<>(); 32 | 33 | /** 34 | * 命令行入口 35 | * 36 | * @param args 命令行参数[注意,命令行是以空格分割的] 37 | */ 38 | public static void main(String[] args) { 39 | //获取当前目录的绝对路径 40 | String resFolderPath = new File("./res/").getAbsolutePath(); 41 | String tempBaseDP = null; 42 | String[] needMatchs = null; 43 | String[] ignoreMatchs = null; 44 | if (args != null && args.length > 0) { 45 | /** 46 | * 调用Main函数,默认数组第一个为基准适配dp值 47 | */ 48 | tempBaseDP = args[0]; 49 | ignoreMatchs = new String[]{tempBaseDP}; 50 | if (args.length > 1) { 51 | needMatchs = Arrays.copyOfRange(args, 1, args.length); 52 | } 53 | } 54 | start(true, tempBaseDP, needMatchs, ignoreMatchs, resFolderPath, true); 55 | } 56 | 57 | 58 | /** 59 | * 适配文件调用入口 60 | * 61 | * @param isFontMatch 字体是否也适配(是否与dp尺寸一样等比缩放) 62 | * @param tempBaseDP 基准dp值 63 | * @param needMatchs 待适配宽度dp值 64 | * @param ignoreMatchs 待忽略宽度dp值 65 | * @param resFolderPath base dimens.xml 文件的res目录 66 | * @param isUseNewFolder 是否创建 values-swXXXdp 新格式的目录 67 | * @return 返回消息 68 | */ 69 | public static String start(boolean isFontMatch, String tempBaseDP, String[] needMatchs, String[] ignoreMatchs, String resFolderPath, boolean isUseNewFolder) { 70 | if (tempBaseDP != null && !"".equals(tempBaseDP.trim())) { 71 | try { 72 | baseDP = Double.parseDouble(tempBaseDP.trim()); 73 | if (baseDP <= 0) { 74 | baseDP = DEFAULT_DP; 75 | } 76 | } catch (NumberFormatException e) { 77 | baseDP = DEFAULT_DP; 78 | e.printStackTrace(); 79 | } 80 | } else { 81 | baseDP = DEFAULT_DP; 82 | } 83 | 84 | //添加默认的数据 85 | for (String aDefaultDPArr : defaultDPArr) { 86 | if (aDefaultDPArr == null || "".equals(aDefaultDPArr.trim())) { 87 | continue; 88 | } 89 | try { 90 | dataSet.add(Double.parseDouble(aDefaultDPArr.trim())); 91 | } catch (NumberFormatException e) { 92 | e.printStackTrace(); 93 | } 94 | } 95 | if (needMatchs != null) { 96 | for (String needMatch : needMatchs) { 97 | if (needMatch == null || "".equals(needMatch.trim())) { 98 | continue; 99 | } 100 | try { 101 | double needMatchDouble = Double.parseDouble(needMatch.trim()); 102 | if (needMatchDouble > 0) { 103 | dataSet.add(needMatchDouble); 104 | } 105 | } catch (NumberFormatException e) { 106 | e.printStackTrace(); 107 | } 108 | } 109 | } 110 | if (ignoreMatchs != null) { 111 | for (String ignoreMatch : ignoreMatchs) { 112 | if (ignoreMatch == null || "".equals(ignoreMatch.trim())) { 113 | continue; 114 | } 115 | try { 116 | dataSet.remove(Double.parseDouble(ignoreMatch.trim())); 117 | } catch (NumberFormatException e) { 118 | e.printStackTrace(); 119 | } 120 | } 121 | } 122 | 123 | System.out.println("基准宽度dp值:[ " + Tools.cutLastZero(baseDP) + " dp ]"); 124 | System.out.println("本次待适配的宽度dp值: [ " + Tools.getOrderedString(dataSet) + " ]"); 125 | //获取基准的dimens.xml文件 126 | String baseDimenFilePath = resFolderPath + File.separator + "values" + File.separator + "dimens.xml"; 127 | File testBaseDimenFile = new File(baseDimenFilePath); 128 | //判断基准文件是否存在 129 | if (!testBaseDimenFile.exists()) { 130 | System.out.println("DK WARNING: \"./res/values/dimens.xml\" 路径下的文件找不到!"); 131 | return "对应Module \"./res/values/dimens.xml\" 路径下的文件找不到!"; 132 | } 133 | //解析源dimens.xml文件 134 | ArrayList list = XmlIO.readDimenFile(baseDimenFilePath); 135 | if (list == null || list.size() <= 0) { 136 | System.out.println("DK WARNING: \"./res/values/dimens.xml\" 文件无数据!"); 137 | return "\"./res/values/dimens.xml\" 文件无数据!"; 138 | } else { 139 | System.out.println("OK \"./res/values/dimens.xml\" 基准dimens文件解析成功!"); 140 | } 141 | try { 142 | //循环指定的dp参数,生成对应的dimens-swXXXdp.xml文件 143 | Iterator iterator = dataSet.iterator(); 144 | while (iterator.hasNext()) { 145 | double item = iterator.next(); 146 | //获取当前dp除以baseDP后的倍数 147 | double multiple = item / baseDP; 148 | 149 | //待输出的目录 150 | String outFolderPath = ""; 151 | //待删除的目录 152 | String delFolderPath = ""; 153 | //values目录上带的dp整数值 154 | String folderDP = String.valueOf((int) item); 155 | 156 | if (isUseNewFolder) { 157 | outFolderPath = VALUES_NEW_FOLDER.replace(LETTER_REPLACE, folderDP); 158 | delFolderPath = VALUES_OLD_FOLDER.replace(LETTER_REPLACE, folderDP); 159 | } else { 160 | outFolderPath = VALUES_OLD_FOLDER.replace(LETTER_REPLACE, folderDP); 161 | delFolderPath = VALUES_NEW_FOLDER.replace(LETTER_REPLACE, folderDP); 162 | } 163 | outFolderPath = resFolderPath + File.separator + outFolderPath + File.separator; 164 | delFolderPath = resFolderPath + File.separator + delFolderPath + File.separator; 165 | 166 | 167 | if (isDeleteAnotherFolder) { 168 | /** 169 | * 删除以前适配方式的目录values-wXXXdp 170 | */ 171 | File oldFile = new File(delFolderPath); 172 | if (oldFile.exists() && oldFile.isDirectory() && Tools.isOldFolder(oldFile.getName(), isUseNewFolder)) { 173 | //找出res目录下符合要求的values目录,然后递归删除values目录 174 | Tools.deleteFile(oldFile); 175 | } 176 | } 177 | 178 | 179 | /** 180 | * 生成新的目录values-swXXXdp 181 | */ 182 | //创建当前dp对应的dimens文件目录 183 | new File(outFolderPath).mkdirs(); 184 | 185 | 186 | //生成的dimens文件的路径 187 | String outPutFile = outFolderPath + "dimens.xml"; 188 | //生成目标文件dimens.xml输出目录 189 | XmlIO.createDestinationDimens(isFontMatch, list, multiple, outPutFile); 190 | } 191 | System.out.println("OK ALL OVER,全部生成完毕!"); 192 | //适配完成 193 | return "Over, adapt successful"; 194 | } catch (Exception e) { 195 | return "ERROR: " + e.getMessage(); 196 | } 197 | } 198 | } -------------------------------------------------------------------------------- /app/src/main/java/com/duke/phonescreenmatch_test/dp/SAXReadHandler.java: -------------------------------------------------------------------------------- 1 | package com.duke.phonescreenmatch_test.dp; 2 | 3 | import org.xml.sax.Attributes; 4 | import org.xml.sax.SAXException; 5 | import org.xml.sax.helpers.DefaultHandler; 6 | 7 | import java.util.ArrayList; 8 | 9 | /** 10 | * @Author: duke 11 | * @DateTime: 2016-08-24 17:27 12 | * @UpdateTime: 2017-09-29 09:55 13 | * @Description: 解析xml工具类 14 | */ 15 | public class SAXReadHandler extends DefaultHandler { 16 | private ArrayList list = null; 17 | private DimenItem dimenBean; 18 | private String tempElement; 19 | static final String ELEMENT_RESOURCE = "resources"; 20 | static final String ELEMENT_DIMEN = "dimen"; 21 | static final String PROPERTY_NAME = "name"; 22 | 23 | public ArrayList getData() { 24 | return list; 25 | } 26 | 27 | @Override 28 | public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 29 | tempElement = qName; 30 | if (qName != null && qName.trim().length() > 0) { 31 | if (qName.equals(ELEMENT_RESOURCE)) { 32 | //创建集合 33 | list = new ArrayList<>(); 34 | } else if (qName.equals(ELEMENT_DIMEN)) { 35 | //创建对象 36 | dimenBean = new DimenItem(); 37 | if (attributes != null && attributes.getLength() > 0) { 38 | dimenBean.name = attributes.getValue(PROPERTY_NAME); 39 | } 40 | } 41 | } 42 | } 43 | 44 | @Override 45 | public void endElement(String uri, String localName, String qName) throws SAXException { 46 | if (qName != null && qName.trim().length() > 0) { 47 | if (qName.equals(ELEMENT_DIMEN)) { 48 | //dimen结束标签,添加对象到集合 49 | if (list != null) { 50 | list.add(dimenBean); 51 | dimenBean = null; 52 | } 53 | } 54 | } 55 | } 56 | 57 | @Override 58 | public void characters(char[] ch, int start, int length) throws SAXException { 59 | if (tempElement != null && tempElement.trim().equals(ELEMENT_DIMEN)) { 60 | if (dimenBean != null) { 61 | String temp = new String(ch, start, length); 62 | if (temp.trim().length() > 0) { 63 | temp = temp.trim(); 64 | /** 65 | * 感谢网友提醒,发现偶现的bug,同一处的文本会回调多次 66 | */ 67 | if (dimenBean.value == null || dimenBean.value.trim().length() == 0) { 68 | dimenBean.value = temp; 69 | } else { 70 | //内容累加 71 | dimenBean.value += temp; 72 | } 73 | } 74 | } 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /app/src/main/java/com/duke/phonescreenmatch_test/dp/Tools.java: -------------------------------------------------------------------------------- 1 | package com.duke.phonescreenmatch_test.dp; 2 | 3 | import java.io.File; 4 | import java.text.DecimalFormat; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.HashSet; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | /** 12 | * 算法工具类 13 | * 14 | * @UpdateTime: 2017-09-29 09:55 15 | */ 16 | public class Tools { 17 | 18 | /** 19 | * 乘以系数 20 | * 21 | * @param isFontMatch 字体是否也适配(是否与dp尺寸一样等比缩放) 22 | * @param sourceValue 原字符串 @dimen/dp_xxx 或 xxxdp 23 | * @param multiple 屏幕宽度dp基于360dp宽度的系数比值 24 | * @return 乘以系数后的缩放值字符串,且带单位 25 | */ 26 | public static String countValue(boolean isFontMatch, String sourceValue, double multiple) { 27 | if (sourceValue == null || "".equals(sourceValue.trim())) { 28 | //无效值,不执行计算 29 | return "errorValue"; 30 | } 31 | //去除值两端空格,包括引用值 32 | sourceValue = sourceValue.trim(); 33 | // @dimen/dp_xxx 34 | // @dimen/sp_xxx 35 | if (sourceValue.startsWith("@dimen/")) { 36 | //引用值,不执行计算 37 | return sourceValue; 38 | } 39 | //替换非引用值的单位dip为dp 40 | if (sourceValue.endsWith("dip")) { 41 | //我只确保最后的dip替换成dp,你非要写成39dipdip这种恶心的值,我也管不了 42 | sourceValue = sourceValue.replaceAll("dip", "dp"); 43 | } 44 | // xxpx 45 | // xxpt 46 | // ... 47 | if (!sourceValue.endsWith("dp") && !sourceValue.endsWith("sp")) { 48 | //非dp或sp数据,不执行计算 49 | return sourceValue; 50 | } 51 | if (sourceValue.endsWith("sp")) { 52 | if (!isFontMatch) { 53 | //如果为false,不执行计算 54 | return sourceValue; 55 | } 56 | } 57 | if (sourceValue.length() < 3) { 58 | //只剩下单位dp或sp,不执行计算 59 | return sourceValue; 60 | } 61 | int length = sourceValue.length(); 62 | String endValue = sourceValue.substring(length - 2, length);//单位dp或sp 63 | String startValue = sourceValue.substring(0, length - 2);//数值 64 | endValue = endValue.trim(); 65 | startValue = startValue.trim(); 66 | if ("".equals(endValue) || "".equals(startValue)) { 67 | return sourceValue; 68 | } 69 | //乘以系数 70 | double temp = 0; 71 | try { 72 | temp = Double.parseDouble(startValue) * multiple; 73 | } catch (Exception e) { 74 | return sourceValue; 75 | } 76 | //数据格式化对象 77 | DecimalFormat df = new DecimalFormat("0.0000"); 78 | return df.format(temp) + endValue; 79 | } 80 | 81 | /** 82 | * 把set集合数据转成字符串,并有序的返回 83 | * 84 | * @param set 85 | * @return 86 | */ 87 | public static String getOrderedString(HashSet set) { 88 | if (set == null || set.size() <= 0) { 89 | return ""; 90 | } 91 | ArrayList list = new ArrayList<>(); 92 | list.addAll(set); 93 | Object[] arr = list.toArray(); 94 | Arrays.sort(arr); 95 | StringBuilder stringBuffer = new StringBuilder(); 96 | for (Object anArr : arr) { 97 | stringBuffer.append(cutLastZero(Double.parseDouble(anArr.toString()))).append(", "); 98 | } 99 | String result = stringBuffer.toString(); 100 | if (result.endsWith(", ")) { 101 | result = result.substring(0, result.length() - 2); 102 | } 103 | return result; 104 | } 105 | 106 | /** 107 | * 去除浮点型后面多余的0 108 | * 109 | * @param value 110 | * @return 111 | */ 112 | public static String cutLastZero(double value) { 113 | if (value <= 0) { 114 | return "0"; 115 | } 116 | String sourceValue = String.valueOf(value); 117 | String result = ""; 118 | if (sourceValue.contains(".")) {//带小数 119 | // 去除后面的0 120 | while (sourceValue.charAt(sourceValue.length() - 1) == '0') { 121 | sourceValue = sourceValue.substring(0, sourceValue.length() - 1); 122 | } 123 | //删除最后的点 124 | if (sourceValue.endsWith(".")) { 125 | sourceValue = sourceValue.substring(0, sourceValue.length() - 1); 126 | } 127 | result = sourceValue; 128 | } 129 | return result; 130 | } 131 | 132 | /** 133 | * 递归删除目录 134 | * 135 | * @param file 待删除的文件或目录 136 | */ 137 | public static void deleteFile(File file) { 138 | if (file == null || !file.exists()) { 139 | return; 140 | } 141 | if (file.isDirectory()) { 142 | File[] files = file.listFiles(); 143 | if (files != null && files.length > 0) { 144 | for (int i = 0; i < files.length; i++) { 145 | // 递归删除 146 | deleteFile(files[i]); 147 | } 148 | } 149 | try { 150 | // 删除当前空目录 151 | file.delete(); 152 | } catch (Exception e) { 153 | e.printStackTrace(); 154 | } 155 | } else { 156 | // 是文件 157 | try { 158 | // 删除当前文件 159 | file.delete(); 160 | } catch (Exception e) { 161 | e.printStackTrace(); 162 | } 163 | } 164 | } 165 | 166 | /** 167 | * 判断当前文件目录名是否为 values-wXXXdp 格式,即以前的旧文件目录 168 | * 169 | * @param path ..../res/values-wXXXdp 170 | * @param isUseNewFolder 是否使用新的目录格式 values-swXXXdp 171 | * @return 是否是指定格式的目录 172 | */ 173 | public static boolean isOldFolder(String path, boolean isUseNewFolder) { 174 | if (path == null || path.trim().length() == 0) { 175 | return false; 176 | } 177 | 178 | String regEx = ""; 179 | if (isUseNewFolder) { 180 | //即删除旧的目录 values-wXXXdp 181 | regEx = "^values-w[0-9]+dp$"; 182 | } else { 183 | //删除新的目录格式 values-swXXXdp 184 | regEx = "^values-sw[0-9]+dp$"; 185 | } 186 | Pattern pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE); 187 | Matcher matcher = pattern.matcher(path); 188 | return matcher.find(); 189 | } 190 | } -------------------------------------------------------------------------------- /app/src/main/java/com/duke/phonescreenmatch_test/dp/XmlIO.java: -------------------------------------------------------------------------------- 1 | package com.duke.phonescreenmatch_test.dp; 2 | 3 | import org.xml.sax.helpers.AttributesImpl; 4 | 5 | import javax.xml.parsers.SAXParser; 6 | import javax.xml.parsers.SAXParserFactory; 7 | import javax.xml.transform.OutputKeys; 8 | import javax.xml.transform.Transformer; 9 | import javax.xml.transform.sax.SAXTransformerFactory; 10 | import javax.xml.transform.sax.TransformerHandler; 11 | import javax.xml.transform.stream.StreamResult; 12 | import java.io.File; 13 | import java.io.FileInputStream; 14 | import java.io.InputStream; 15 | import java.util.ArrayList; 16 | 17 | /** 18 | * dimens处理 19 | * 20 | * @UpdateTime: 2017-09-29 09:55 21 | */ 22 | public class XmlIO { 23 | 24 | /** 25 | * 解析dimens文件 26 | * 27 | * @param baseDimenFilePath 源dimens文件路径 28 | */ 29 | public static ArrayList readDimenFile(String baseDimenFilePath) { 30 | ArrayList list = null; 31 | try { 32 | SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); 33 | SAXParser saxparser = saxParserFactory.newSAXParser(); 34 | InputStream inputStream = new FileInputStream(baseDimenFilePath); 35 | SAXReadHandler saxReadHandler = new SAXReadHandler(); 36 | saxparser.parse(inputStream, saxReadHandler); 37 | list = saxReadHandler.getData(); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | return list; 42 | } 43 | 44 | /** 45 | * 生成dimens文件 46 | * 47 | * @param isFontMatch 字体是否也适配(是否与dp尺寸一样等比缩放) 48 | * @param list 源dimens数据 49 | * @param multiple 对应新文件需要乘以的系数 50 | * @param outPutFile 目标文件输出目录 51 | */ 52 | public static void createDestinationDimens(boolean isFontMatch, ArrayList list, double multiple, String outPutFile) { 53 | try { 54 | File targetFile = new File(outPutFile); 55 | if (targetFile.exists()) { 56 | try { 57 | targetFile.delete(); 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | //创建SAXTransformerFactory实例 63 | SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); 64 | //创建TransformerHandler实例 65 | TransformerHandler handler = saxTransformerFactory.newTransformerHandler(); 66 | //创建Transformer实例 67 | Transformer transformer = handler.getTransformer(); 68 | //是否自动添加额外的空白 69 | transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 70 | //设置字符编码 71 | transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 72 | //添加xml版本,默认也是1.0 73 | transformer.setOutputProperty(OutputKeys.VERSION, "1.0"); 74 | //保存xml路径 75 | StreamResult result = new StreamResult(targetFile); 76 | handler.setResult(result); 77 | //创建属性Attribute对象 78 | AttributesImpl attributes = new AttributesImpl(); 79 | attributes.clear(); 80 | //开始xml 81 | handler.startDocument(); 82 | //换行 83 | handler.characters("\n".toCharArray(), 0, "\n".length()); 84 | //写入根节点resources 85 | handler.startElement("", "", SAXReadHandler.ELEMENT_RESOURCE, attributes); 86 | //集合大小 87 | int size = list.size(); 88 | for (int i = 0; i < size; i++) { 89 | DimenItem dimenBean = list.get(i); 90 | //乘以系数,加上后缀 91 | String targetValue = Tools.countValue(isFontMatch, dimenBean.value, multiple); 92 | attributes.clear(); 93 | attributes.addAttribute("", "", SAXReadHandler.PROPERTY_NAME, "", dimenBean.name); 94 | 95 | //新dimen之前,换行、缩进 96 | handler.characters("\n".toCharArray(), 0, "\n".length()); 97 | handler.characters("\t".toCharArray(), 0, "\t".length()); 98 | 99 | //开始标签对输出 100 | handler.startElement("", "", SAXReadHandler.ELEMENT_DIMEN, attributes); 101 | handler.characters(targetValue.toCharArray(), 0, targetValue.length()); 102 | handler.endElement("", "", SAXReadHandler.ELEMENT_DIMEN); 103 | } 104 | handler.endElement("", "", SAXReadHandler.ELEMENT_RESOURCE); 105 | handler.endDocument(); 106 | System.out.println(">>>>> " + outPutFile + " 文件生成完成!"); 107 | } catch (Exception e) { 108 | System.out.println("DK WARNING: " + outPutFile + " 文件生成失败!"); 109 | e.printStackTrace(); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/com/duke/phonescreenmatch_test/px/GenerateValueFiles.java: -------------------------------------------------------------------------------- 1 | package com.duke.phonescreenmatch_test.px; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileOutputStream; 6 | import java.io.PrintWriter; 7 | import java.util.HashSet; 8 | import java.util.Iterator; 9 | 10 | /** 11 | * @Author: duke 12 | * @DateTime: 2016-08-24 14:31 13 | * @Description: hongyang的px适配,1280x720为基准 14 | */ 15 | public class GenerateValueFiles { 16 | private int baseW = 720; 17 | private int baseH = 1280; 18 | private String dirStr = "./res"; 19 | private final static String XDIMEN = "{1}px\n"; 20 | private final static String YDIMEN = "{1}px\n"; 21 | /** 22 | * {0}-HEIGHT 23 | * {1}-WIDTH 24 | */ 25 | private final static String FOLDER_NAME = "values-{0}x{1}"; 26 | private HashSet dataSet;//装的是"width,height"字符串 27 | private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,888;600,1024;720,1184;720,1196;720,1280;768,1024;768,1280;800,1280;1080,1812;1080,1920;1440,2560;"; 28 | private String supportStr = SUPPORT_DIMESION; 29 | 30 | public static void main(String[] args) { 31 | System.out.println("开始运行..."); 32 | //基准宽高 33 | int baseW = -1; 34 | int baseH = -1; 35 | String addition = ""; 36 | try { 37 | if (args.length == 1) { 38 | addition = args[0]; 39 | } else if (args.length == 2) { 40 | baseW = Integer.parseInt(args[0]); 41 | baseH = Integer.parseInt(args[1]); 42 | } else if (args.length >= 3) { 43 | baseW = Integer.parseInt(args[0]); 44 | baseH = Integer.parseInt(args[1]); 45 | addition = args[2]; 46 | } else { 47 | System.out.println("没有发现输入参数..."); 48 | } 49 | } catch (NumberFormatException e) { 50 | System.err.println("right input params : java -jar xxx.jar baseW baseH w,h;w,h;...;w,h;"); 51 | e.printStackTrace(); 52 | System.exit(-1); 53 | } 54 | new GenerateValueFiles(baseW, baseH, addition).generate(); 55 | } 56 | 57 | /** 58 | * 构造函数 59 | * 60 | * @param baseX 基准width 61 | * @param baseY 基准height 62 | * @param supportStr 需要适配的屏幕px尺寸 63 | */ 64 | public GenerateValueFiles(int baseX, int baseY, String supportStr) { 65 | if (baseX > 0) 66 | this.baseW = baseX; 67 | if (baseY > 0) 68 | this.baseH = baseY; 69 | String test = this.baseW + "," + this.baseH + ";"; 70 | System.out.println("基准尺寸:" + test); 71 | if (!this.supportStr.contains(test)) { 72 | this.supportStr += test; 73 | } 74 | //拼接和去重屏幕px尺寸参数 75 | validateInput(supportStr); 76 | File dir = new File(dirStr); 77 | if (!dir.exists()) { 78 | dir.mkdirs(); 79 | } 80 | } 81 | 82 | /** 83 | * @param temp w,h;...;w,h; 84 | * @return 85 | */ 86 | private void validateInput(String temp) { 87 | if (temp != null && temp.trim().length() > 0) 88 | this.supportStr += temp; 89 | if (dataSet == null) 90 | dataSet = new HashSet<>(); 91 | String[] tempArr = supportStr.split(";"); 92 | for (int i = 0; i < tempArr.length; i++) { 93 | if (tempArr[i] != null && tempArr[i].trim().length() > 0) { 94 | dataSet.add(tempArr[i]); 95 | } 96 | } 97 | System.out.println("待适配的屏幕px参数:" + dataSet.toString()); 98 | } 99 | 100 | public void generate() { 101 | Iterator iterator = dataSet.iterator(); 102 | while (iterator.hasNext()) { 103 | String whStr = iterator.next(); 104 | String[] wh = whStr.split(","); 105 | generateXmlFile(Integer.parseInt(wh[0]), Integer.parseInt(wh[1])); 106 | } 107 | System.out.println("OK ALL OVER,全部生成完毕!"); 108 | } 109 | 110 | private void generateXmlFile(int w, int h) { 111 | System.out.println("开始生成 " + String.valueOf(w + "x" + h) + "对应的dimens.xml文件"); 112 | //文件部分dimens_x.xml 113 | StringBuffer sbForWidth = new StringBuffer(); 114 | sbForWidth.append("\n"); 115 | sbForWidth.append("\n"); 116 | float coefficientW = w * 1.0f / baseW; 117 | for (int i = 1; i < baseW; i++) { 118 | sbForWidth.append("\t"); 119 | sbForWidth.append(XDIMEN.replace("{0}", String.valueOf(i)).replace("{1}", String.valueOf(change(coefficientW * i)))); 120 | } 121 | //最后一个不参与计算,保证为整数 122 | sbForWidth.append("\t"); 123 | sbForWidth.append(XDIMEN.replace("{0}", String.valueOf(baseW)).replace("{1}", String.valueOf(w))); 124 | sbForWidth.append(""); 125 | 126 | //文件部分dimens_y.xml 127 | StringBuffer sbForHeight = new StringBuffer(); 128 | sbForHeight.append("\n"); 129 | sbForHeight.append("\n"); 130 | float coefficientH = h * 1.0f / baseH; 131 | for (int i = 1; i < baseH; i++) { 132 | sbForHeight.append("\t"); 133 | sbForHeight.append(YDIMEN.replace("{0}", String.valueOf(i)).replace("{1}", String.valueOf(change(coefficientH * i)))); 134 | } 135 | //最后一个不参与计算,保证为整数 136 | sbForHeight.append("\t"); 137 | sbForHeight.append(YDIMEN.replace("{0}", String.valueOf(baseH)).replace("{1}", String.valueOf(h))); 138 | sbForHeight.append(""); 139 | 140 | //生成文件路径 Height x Width 141 | File fileDir = new File(dirStr + File.separator + FOLDER_NAME.replace("{0}", String.valueOf(h)).replace("{1}", String.valueOf(w))); 142 | fileDir.mkdir(); 143 | File dimensXFile = new File(fileDir.getAbsolutePath(), "dimens_x.xml"); 144 | if (dimensXFile.exists()) { 145 | dimensXFile.delete(); 146 | System.out.println("旧文件 \"dimens_x.xml\" 删除成功!"); 147 | } 148 | File dimensYFile = new File(fileDir.getAbsolutePath(), "dimens_y.xml"); 149 | if (dimensYFile.exists()) { 150 | dimensYFile.delete(); 151 | System.out.println("旧文件 \"dimens_y.xml\" 删除成功!"); 152 | } 153 | try { 154 | //写dimens_x.xml 155 | PrintWriter pw = new PrintWriter(new FileOutputStream(dimensXFile)); 156 | pw.print(sbForWidth.toString()); 157 | pw.close(); 158 | //写dimens_y.xml 159 | pw = new PrintWriter(new FileOutputStream(dimensYFile)); 160 | pw.print(sbForHeight.toString()); 161 | pw.close(); 162 | System.out.println("文件 dimens_m.xml 生成完毕!"); 163 | } catch (FileNotFoundException e) { 164 | System.out.println("文件 dimens_m.xml 生成失败!"); 165 | e.printStackTrace(); 166 | } 167 | } 168 | 169 | //保留2位小数 170 | public static float change(float a) { 171 | int temp = (int) (a * 100); 172 | return temp / 100f; 173 | } 174 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 |