├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── vip │ │ └── ruoyun │ │ └── screenlayout │ │ ├── App.kt │ │ ├── Helper.kt │ │ └── MainActivity.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── art ├── 15572467899577.jpg ├── 15572468488661.jpg └── screen_helper_logo.png ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── release └── vip │ └── ruoyun │ └── plugin │ └── screen-plugin │ ├── maven-metadata.xml │ ├── maven-metadata.xml.md5 │ └── maven-metadata.xml.sha1 ├── screen-helper ├── .gitignore ├── build.gradle ├── jcenter.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── vip │ └── ruoyun │ └── screen │ └── ScreenHelper.java ├── screen-plugin ├── .gitignore ├── build.gradle ├── jcenter.gradle └── src │ └── main │ ├── groovy │ └── vip │ │ └── ruoyun │ │ └── screen │ │ ├── DimenTools.groovy │ │ ├── LogM.groovy │ │ ├── ScreenExt.groovy │ │ └── ScreenPlugin.groovy │ └── resources │ └── META-INF │ └── gradle-plugins │ └── vip.ruoyun.screen.properties └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | .idea 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # alt text 2 | 3 | android 屏幕适配的两种终结方式 4 | - Smallest Width 适配 5 | - DisplayMetrics.densityDpi 属性修改 6 | 7 | 完美兼容 AndroidX 和 Android 库 ^_^ ,欢迎使用~~ 8 | 9 | ## 原理讲解,必看 10 | 11 | [屏幕原理](https://blog.ruoyun.vip/post/android%E5%B1%8F%E5%B9%95%E9%80%82%E9%85%8D-%E5%BF%85%E5%A4%87%E7%9F%A5%E8%AF%86/) 12 | 13 | [适配原理](https://blog.ruoyun.vip/post/android%E5%B1%8F%E5%B9%95%E9%80%82%E9%85%8D-%E7%BB%88%E7%BB%93%E8%80%85/) 14 | 15 | --- 16 | 17 | ## 第一种适配方式 - Smallest Width 方式 18 | 插件版本: 19 | [ ![Download](https://api.bintray.com/packages/bugyun/maven/screen-plugin/images/download.svg?version=1.0.1) ](https://bintray.com/bugyun/maven/screen-plugin/1.0.1/link) 20 | 21 | 使用方法 22 | 23 | 在项目的根 build.gradle 中添加 24 | 25 | ```java 26 | buildscript { 27 | repositories { 28 | google() 29 | jcenter() 30 | } 31 | dependencies { 32 | classpath 'com.android.tools.build:gradle:3.5.0-alpha13' 33 | // 在此处添加 34 | classpath 'vip.ruoyun.plugin:screen-plugin:1.0.1' 35 | } 36 | } 37 | allprojects { 38 | repositories { 39 | google() 40 | jcenter() 41 | } 42 | } 43 | ``` 44 | 45 | 在要使用插件的的子项目的 build.gradle 中添加 46 | 47 | ```java 48 | apply plugin: 'vip.ruoyun.screen' 49 | 50 | screen { 51 | smallestWidths 320, 360, 384, 392, 400, 410, 411, 432, 480 //生成的目标屏幕宽度的适配文件 52 | designSmallestWidth 375 //苹果设计稿750 × 1334 屏幕宽度为 375 53 | decimalFormat "#.#" //设置保留的小数 ( #.## 保留2位) ( #.# 保留1位) 54 | log false //是否打印日志 55 | auto false //是否每次 build 项目的时候自动生成 values-sw[]dp 文件 56 | } 57 | ``` 58 | 59 | 如果 auto 设置为 true ,则每次 build 项目的时候自动生成 values-sw[]dp 文件 60 | 61 | 如果 auto 设置为 false,则可以通过命令行,来生成文件. 62 | ``` 63 | ./gradlew dimensCovert 64 | ``` 65 | 也可以在 gradle命令的 窗口中 点击 dimensCovert 的 task. 66 | 67 | ![](https://github.com/bugyun/ScreenHelper/blob/master/art/15572467899577.jpg?raw=true) 68 | 69 | 自动生成的sw 文件 70 | 71 | ![](https://github.com/bugyun/ScreenHelper/blob/master/art/15572468488661.jpg?raw=true) 72 | 73 | 生成规则:只会生成 dp 后缀的属性值,根据 values 目录下的 dimens.xml,生成具体的文件。 74 | values 目录下的 dimens.xml 75 | ```xml 76 | 77 | 78 | 20dp 79 | 20sp 80 | 81 | ``` 82 | 生成的目标文件,values-sw320dp 目录下的 dimens.xml 文件 83 | ```xml 84 | 85 | 86 | 17.1dp 87 | 88 | ``` 89 | 90 | --- 91 | 92 | ## 第二种适配方式 - DisplayMetrics.densityDpi 属性修改 93 | 插件版本: 94 | [ ![Download](https://api.bintray.com/packages/bugyun/maven/screen-helper/images/download.svg?version=1.0.2) ](https://bintray.com/bugyun/maven/screen-helper/1.0.2/link) 95 | 96 | 在项目的根 build.gradle 中添加 jcenter 仓库 97 | ```java 98 | buildscript { 99 | repositories { 100 | google() 101 | jcenter() 102 | } 103 | ... 104 | } 105 | 106 | allprojects { 107 | repositories { 108 | google() 109 | jcenter() 110 | } 111 | } 112 | ``` 113 | 然后在子项目中的 build.gradle 文件中添加 114 | ```java 115 | dependencies { 116 | implementation 'vip.ruoyun.helper:screen-helper:1.0.2' 117 | } 118 | ``` 119 | 120 | 使用,在每个Activity 重写getResources()方法。 121 | ```java 122 | public class MainActivity extends AppCompatActivity { 123 | @Override 124 | public Resources getResources() { 125 | return ScreenHelper.applyAdapt(super.getResources(), 450f, ScreenHelper.WIDTH_DP); 126 | } 127 | } 128 | ``` 129 | 130 | 如果是悬浮窗适配,因为 inflate 用到的 context 是 application 级别的,所以需要在自定义的 Application 中重写 getResource。 131 | 132 | ```java 133 | public class App extends Application { 134 | @Override 135 | public Resources getResources() { 136 | return ScreenHelper.applyAdapt(super.getResources(), 450f, ScreenHelper.WIDTH_DP); 137 | } 138 | } 139 | ``` 140 | 141 | #### 类型 142 | - ScreenHelper.WIDTH_DP 以 dp 来适配,在 xml 中使用 dp 单位 143 | - ScreenHelper.WIDTH_PT 以 pt 来适配,在 xml 中使用 pt 单位 144 | - ScreenHelper.HEIGHT_PT 以 pt 来适配,在 xml 中使用 pt 单位 145 | 146 | 147 | #### 版本变化 148 | - 1.0.2 :优化传递 ScreenMode 的参数传递,去除不必要的 log 149 | - 1.0.1 :优化 Resources.getSystem() 变量获取,由于此方法是 synchronized ,如果频繁调用会影响性能 150 | - 1.0.0 :正式发版 151 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | apply plugin: 'vip.ruoyun.screen' 8 | 9 | screen { 10 | smallestWidths 320, 360, 384, 392, 400, 410, 411, 432, 480 11 | designSmallestWidth 375 //苹果设计稿750 × 1334 326ppi 计算公式 : px / (DPI / 160) = dp 结果为:368dp 12 | decimalFormat "#.#" //设置保留的小数 ( #.## 保留2位) ( #.# 保留1位) 13 | log true 14 | auto false 15 | } 16 | 17 | android { 18 | compileSdkVersion 28 19 | defaultConfig { 20 | applicationId "vip.ruoyun.screenlayout" 21 | minSdkVersion 14 22 | targetSdkVersion 28 23 | versionCode 1 24 | versionName "1.0" 25 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 26 | } 27 | buildTypes { 28 | release { 29 | minifyEnabled false 30 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 31 | } 32 | } 33 | } 34 | 35 | dependencies { 36 | implementation fileTree(dir: 'libs', include: ['*.jar']) 37 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 38 | implementation 'com.android.support:appcompat-v7:28.0.0' 39 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 40 | testImplementation 'junit:junit:4.12' 41 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 42 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 43 | // implementation project(path: ':screen-helper') 44 | implementation 'vip.ruoyun.helper:screen-helper:1.0.2' 45 | 46 | } 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /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/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/vip/ruoyun/screenlayout/App.kt: -------------------------------------------------------------------------------- 1 | package vip.ruoyun.screenlayout 2 | 3 | import android.app.Application 4 | import android.content.res.Resources 5 | 6 | /** 7 | * Created by ruoyun on 2019-05-08. 8 | * Author:若云 9 | * Mail:zyhdvlp@gmail.com 10 | * Depiction: 11 | */ 12 | 13 | class App : Application() { 14 | 15 | override fun getResources(): Resources { 16 | return Helper.apply(super.getResources()) 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /app/src/main/java/vip/ruoyun/screenlayout/Helper.kt: -------------------------------------------------------------------------------- 1 | package vip.ruoyun.screenlayout 2 | 3 | import android.content.res.Resources 4 | import vip.ruoyun.screen.ScreenHelper 5 | 6 | /** 7 | * Created by ruoyun on 2019-05-08. 8 | * Author:若云 9 | * Mail:zyhdvlp@gmail.com 10 | * Depiction:帮助类 11 | */ 12 | 13 | class Helper { 14 | 15 | companion object { 16 | @JvmField 17 | var isOpenScreen: Boolean = true 18 | 19 | @JvmStatic 20 | fun apply(resources: Resources): Resources { 21 | if (isOpenScreen) { 22 | return ScreenHelper.applyAdapt(resources, 480f, ScreenHelper.WIDTH_DP) 23 | } else { 24 | return ScreenHelper.closeAdapt(resources) 25 | } 26 | } 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /app/src/main/java/vip/ruoyun/screenlayout/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package vip.ruoyun.screenlayout 2 | 3 | import android.content.res.Resources 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | 7 | class MainActivity : AppCompatActivity() { 8 | 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | setContentView(R.layout.activity_main) 12 | 13 | } 14 | 15 | override fun getResources(): Resources { 16 | return Helper.apply(super.getResources()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 16 | 21 | 22 | 27 | 28 | 29 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20dp 4 | 20sp 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ScreenLayout 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /art/15572467899577.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/art/15572467899577.jpg -------------------------------------------------------------------------------- /art/15572468488661.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/art/15572468488661.jpg -------------------------------------------------------------------------------- /art/screen_helper_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/art/screen_helper_logo.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.31' 5 | repositories { 6 | // maven { url uri('./release') }//本地仓库,测试使用 7 | google() 8 | jcenter() 9 | // maven { url "https://dl.bintray.com/bugyun/maven" } 10 | } 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.4.1' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | 15 | classpath 'vip.ruoyun.plugin:screen-plugin:1.0.1' 16 | classpath 'com.novoda:bintray-release:0.9.1' 17 | } 18 | } 19 | 20 | allprojects { 21 | repositories { 22 | // maven { url uri('./release') }//本地仓库,测试使用 23 | google() 24 | jcenter() 25 | // maven { url "https://dl.bintray.com/bugyun/maven" } 26 | } 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # Kotlin code style for this project: "official" or "obsolete": 15 | kotlin.code.style=official 16 | # Disables R8 for Android Library modules only. 17 | #android.enableR8.libraries=false 18 | # Disables R8 for all modules. 19 | #android.enableR8=false 20 | #android.debug.obsoleteApi=true 21 | 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugyun/ScreenHelper/633553882a36a81d1feb021c8f51005a646e02b3/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun May 05 21:23:01 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /release/vip/ruoyun/plugin/screen-plugin/maven-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | vip.ruoyun.plugin 4 | screen-plugin 5 | 6 | 1.0.1 7 | 8 | 1.0 9 | 1.1 10 | 1.0.0 11 | 1.0.1 12 | 13 | 20191106065845 14 | 15 | 16 | -------------------------------------------------------------------------------- /release/vip/ruoyun/plugin/screen-plugin/maven-metadata.xml.md5: -------------------------------------------------------------------------------- 1 | 6c59d365981c0ea936101406991eed07 -------------------------------------------------------------------------------- /release/vip/ruoyun/plugin/screen-plugin/maven-metadata.xml.sha1: -------------------------------------------------------------------------------- 1 | 0c5288a928f19e5a0509d256a225f4682c51f366 -------------------------------------------------------------------------------- /screen-helper/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /screen-helper/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | //apply from: 'jcenter.gradle'//上传 jcenter 的插件 3 | 4 | android { 5 | compileSdkVersion 28 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation 'com.android.support:support-annotations:28.0.0' 24 | } -------------------------------------------------------------------------------- /screen-helper/jcenter.gradle: -------------------------------------------------------------------------------- 1 | //上传 jcenter 的插件 2 | apply plugin: 'com.novoda.bintray-release' // 新增 3 | 4 | /** 5 | * 参考 6 | * 'com.android.support.test.espresso:espresso-core:3.0.2' 7 | * group: 'com.android.support.test.espresso', name: 'espresso-core', version: '3.0.2' 8 | */ 9 | 10 | // 新增 11 | publish { 12 | userOrg = 'bugyun' //bintray.com用户名 13 | groupId = 'vip.ruoyun.helper' //jcenter group 14 | artifactId = 'screen-helper' //项目名称 name 15 | publishVersion = '1.0.2'//版本号 version 16 | desc = 'android 屏幕适配帮助类'//描述 17 | website = 'https://github.com/bugyun/ScreenHelper' // github 网址 18 | } 19 | 20 | // ./gradlew clean build bintrayUpload -PbintrayUser=bintray.user -PbintrayKey=bintray.apikey -PdryRun=false -------------------------------------------------------------------------------- /screen-helper/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 | -------------------------------------------------------------------------------- /screen-helper/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /screen-helper/src/main/java/vip/ruoyun/screen/ScreenHelper.java: -------------------------------------------------------------------------------- 1 | package vip.ruoyun.screen; 2 | 3 | import android.content.Context; 4 | import android.content.res.Configuration; 5 | import android.content.res.Resources; 6 | import android.support.annotation.IntDef; 7 | import android.util.DisplayMetrics; 8 | 9 | import java.lang.annotation.Retention; 10 | import java.lang.annotation.RetentionPolicy; 11 | import java.lang.reflect.Field; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class ScreenHelper { 16 | 17 | public static final int WIDTH_DP = 0x25; 18 | public static final int WIDTH_PT = 0x35; 19 | public static final int HEIGHT_PT = 0x45; 20 | 21 | @IntDef({WIDTH_DP, WIDTH_PT, HEIGHT_PT}) 22 | @Retention(RetentionPolicy.CLASS) 23 | @interface ScreenMode { 24 | } 25 | 26 | private ScreenHelper() { 27 | } 28 | 29 | private static List sMetricsFields; 30 | private static DisplayMetrics systemDm; 31 | 32 | public static Resources applyAdapt(final Resources resources, float size, @ScreenMode int screenMode) { 33 | DisplayMetrics activityDm = resources.getDisplayMetrics(); 34 | if (null == systemDm) { 35 | systemDm = Resources.getSystem().getDisplayMetrics(); 36 | } 37 | change(screenMode, resources, activityDm, systemDm, size); 38 | //兼容其他手机 39 | if (sMetricsFields == null) { 40 | sMetricsFields = new ArrayList<>(); 41 | Class resCls = resources.getClass(); 42 | // Log.e("ScreenHelper", "resCls.getSimpleName: " + resCls.getSimpleName()); 43 | Field[] declaredFields = resCls.getDeclaredFields(); 44 | // Log.e("ScreenHelper", "declaredFields.length: " + declaredFields.length); 45 | while (declaredFields.length > 0) { 46 | for (Field field : declaredFields) { 47 | if (field.getType().isAssignableFrom(DisplayMetrics.class)) { 48 | // Log.e("ScreenHelper", "field.getName: " + field.getName()); 49 | field.setAccessible(true); 50 | DisplayMetrics tmpDm = getMetricsFromField(resources, field); 51 | if (tmpDm != null) { 52 | // Log.e("ScreenHelper", "tmpDm: " + tmpDm.toString()); 53 | sMetricsFields.add(field); 54 | change(screenMode, resources, tmpDm, systemDm, size); 55 | } 56 | } 57 | } 58 | resCls = resCls.getSuperclass(); 59 | if (resCls != null) { 60 | declaredFields = resCls.getDeclaredFields(); 61 | } else { 62 | break; 63 | } 64 | } 65 | } else { 66 | for (Field metricsField : sMetricsFields) { 67 | try { 68 | DisplayMetrics dm = (DisplayMetrics) metricsField.get(resources); 69 | if (dm != null) change(screenMode, resources, dm, systemDm, size); 70 | } catch (Exception e) { 71 | // Log.e("ScreenHelper", "applyMetricsFields: " + e); 72 | } 73 | } 74 | } 75 | return resources; 76 | } 77 | 78 | 79 | private static void change(@ScreenMode int screenMode, final Resources resources, DisplayMetrics activityDm, DisplayMetrics systemDm, float size) { 80 | switch (screenMode) { 81 | case WIDTH_DP: 82 | adaptWidthPixels(resources, activityDm, systemDm, size); 83 | break; 84 | case HEIGHT_PT: 85 | adaptHeightXdpi(resources, size, systemDm); 86 | break; 87 | case WIDTH_PT: 88 | adaptWidthXdpi(resources, size, systemDm); 89 | break; 90 | } 91 | } 92 | 93 | private static void adaptWidthPixels(Resources resources, DisplayMetrics activityDm, DisplayMetrics systemDm, float designWidthPixels) { 94 | //确保设备在横屏和竖屏的显示大小,确保 dp 的大小值 95 | if (resources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { 96 | //横屏以屏幕的宽度来适配,确保 dp 的大小值 97 | activityDm.density = activityDm.widthPixels * 1.0f / designWidthPixels; 98 | } else { 99 | //竖屏以屏幕的高度来适配 100 | activityDm.density = activityDm.heightPixels * 1.0f / designWidthPixels; 101 | } 102 | //确保字体的显示大小 103 | activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.density); 104 | //确保设置的 dpi 105 | activityDm.densityDpi = (int) (160 * activityDm.density); 106 | } 107 | 108 | /** 109 | * Adapt for the horizontal screen, and call it in [android.app.Activity.getResources]. 110 | */ 111 | private static void adaptWidthXdpi(Resources resources, float designWidth, DisplayMetrics systemDm) { 112 | resources.getDisplayMetrics().xdpi = (systemDm.widthPixels * 72f) / designWidth; 113 | } 114 | 115 | /** 116 | * Adapt for the vertical screen, and call it in [android.app.Activity.getResources]. 117 | */ 118 | private static void adaptHeightXdpi(Resources resources, float designHeight, DisplayMetrics systemDm) { 119 | resources.getDisplayMetrics().xdpi = (systemDm.heightPixels * 72f) / designHeight; 120 | } 121 | 122 | /** 123 | * @param resources The resources. 124 | * @return the resource 125 | */ 126 | public static Resources closeAdapt(Resources resources) { 127 | DisplayMetrics activityDm = resources.getDisplayMetrics(); 128 | if (null == systemDm) { 129 | systemDm = Resources.getSystem().getDisplayMetrics(); 130 | } 131 | resetResources(activityDm, systemDm); 132 | //兼容其他手机 133 | if (sMetricsFields == null) { 134 | sMetricsFields = new ArrayList<>(); 135 | Class resCls = resources.getClass(); 136 | Field[] declaredFields = resCls.getDeclaredFields(); 137 | while (declaredFields.length > 0) { 138 | for (Field field : declaredFields) { 139 | if (field.getType().isAssignableFrom(DisplayMetrics.class)) { 140 | field.setAccessible(true); 141 | DisplayMetrics tmpDm = getMetricsFromField(resources, field); 142 | if (tmpDm != null) { 143 | sMetricsFields.add(field); 144 | resetResources(tmpDm, systemDm); 145 | } 146 | } 147 | } 148 | resCls = resCls.getSuperclass(); 149 | if (resCls != null) { 150 | declaredFields = resCls.getDeclaredFields(); 151 | } else { 152 | break; 153 | } 154 | } 155 | } else { 156 | for (Field metricsField : sMetricsFields) { 157 | try { 158 | DisplayMetrics dm = (DisplayMetrics) metricsField.get(resources); 159 | if (dm != null) resetResources(dm, systemDm); 160 | } catch (Exception e) { 161 | // Log.e("ScreenHelper", "applyMetricsFields: " + e); 162 | } 163 | } 164 | } 165 | return resources; 166 | } 167 | 168 | private static void resetResources(DisplayMetrics activityDm, DisplayMetrics systemDm) { 169 | // resources.getDisplayMetrics().xdpi = Resources.getSystem().getDisplayMetrics().density * 72f; 170 | activityDm.xdpi = systemDm.xdpi; 171 | activityDm.density = systemDm.density; 172 | activityDm.scaledDensity = systemDm.scaledDensity; //确保字体的显示大小 173 | activityDm.densityDpi = systemDm.densityDpi;//确保设置的 dpi 174 | } 175 | 176 | /** 177 | * Value of pt/dp to value of px. 178 | * 179 | * @param value The value of pt. 180 | * @return value of px 181 | */ 182 | public static int value2px(Context context, float value, int screenMode) { 183 | DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 184 | switch (screenMode) { 185 | case WIDTH_DP: 186 | default: 187 | return (int) (value * metrics.density); 188 | case HEIGHT_PT: 189 | case WIDTH_PT: 190 | return (int) (value * metrics.xdpi / 72f + 0.5); 191 | } 192 | } 193 | 194 | /** 195 | * Value of px to value of pt/dp. 196 | * 197 | * @param pxValue The value of px. 198 | * @return value of pt 199 | */ 200 | public static int px2Value(Context context, float pxValue, @ScreenMode int screenMode) { 201 | DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 202 | switch (screenMode) { 203 | case WIDTH_DP: 204 | default: 205 | return (int) (pxValue / metrics.density); 206 | case HEIGHT_PT: 207 | case WIDTH_PT: 208 | return (int) (pxValue * 72 / metrics.xdpi + 0.5); 209 | } 210 | } 211 | 212 | private static DisplayMetrics getMetricsFromField(final Resources resources, final Field field) { 213 | try { 214 | return (DisplayMetrics) field.get(resources); 215 | } catch (Exception e) { 216 | // Log.e("ScreenHelper", "getMetricsFromField: " + e); 217 | return null; 218 | } 219 | } 220 | 221 | 222 | } 223 | -------------------------------------------------------------------------------- /screen-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /screen-plugin/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'groovy' 2 | apply plugin: 'maven'//添加maven plugin, 用于发布我们的jar 3 | //apply from: 'jcenter.gradle'//上传 jcenter 的插件 4 | 5 | dependencies { 6 | implementation gradleApi() 7 | implementation localGroovy() 8 | implementation group: 'org.dom4j', name: 'dom4j', version: '2.1.1' 9 | implementation group: 'jaxen', name: 'jaxen', version: '1.2.0' 10 | implementation 'com.android.tools.build:gradle:3.0.0'//兼容低版本 3.5.1 11 | // implementation 'com.android.tools.build:builder:3.0.0'//兼容低版本 3.5.1 12 | // implementation 'com.android.tools.build:gradle-api:3.0.0'//兼容低版本 3.5.1 13 | } 14 | 15 | repositories { 16 | mavenCentral() 17 | } 18 | 19 | //设置maven deployer 20 | uploadArchives { 21 | repositories { 22 | mavenDeployer { 23 | //设置插件的GAV参数 24 | pom.groupId = 'vip.ruoyun.plugin' 25 | pom.artifactId = 'screen-plugin' 26 | pom.version = '1.0.1' 27 | //文件发布到下面目录 28 | repository(url: uri('../release')) 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /screen-plugin/jcenter.gradle: -------------------------------------------------------------------------------- 1 | //上传 jcenter 的插件 2 | apply plugin: 'com.novoda.bintray-release' // 新增 3 | 4 | /** 5 | * 参考 6 | * 'com.android.support.test.espresso:espresso-core:3.0.2' 7 | * group: 'com.android.support.test.espresso', name: 'espresso-core', version: '3.0.2' 8 | */ 9 | 10 | // 新增 11 | publish { 12 | userOrg = 'bugyun' //bintray.com用户名 13 | groupId = 'vip.ruoyun.plugin' //group 14 | artifactId = 'screen-plugin' //项目名称 name 15 | publishVersion = '1.0.1'//版本号 version 16 | desc = 'android 屏幕适配sw帮助类'//描述 17 | website = 'https://github.com/bugyun/ScreenHelper' // 网址,github 地址 18 | } 19 | 20 | // ./gradlew clean build bintrayUpload -PbintrayUser=bintray.user -PbintrayKey=bintray.apikey -PdryRun=false -------------------------------------------------------------------------------- /screen-plugin/src/main/groovy/vip/ruoyun/screen/DimenTools.groovy: -------------------------------------------------------------------------------- 1 | package vip.ruoyun.screen 2 | 3 | import com.android.utils.FileUtils 4 | import org.dom4j.Document 5 | import org.dom4j.DocumentException 6 | import org.dom4j.DocumentHelper 7 | import org.dom4j.Element 8 | import org.dom4j.io.SAXReader 9 | import org.dom4j.io.XMLWriter 10 | 11 | import java.text.DecimalFormat 12 | 13 | /** 14 | * 15 | * 16 | * 7.361963190184049dp 17 | * 18 | */ 19 | class DimenTools { 20 | 21 | private ArrayList dimenNameList = new ArrayList<>() 22 | private ArrayList dimenTextList = new ArrayList<>() 23 | 24 | private ScreenExt screenExt 25 | private String sourcePath 26 | 27 | DimenTools(ScreenExt screenExt, String sourcePath) { 28 | this.screenExt = screenExt 29 | this.sourcePath = sourcePath 30 | } 31 | 32 | //流程 33 | void dimensCovert() { 34 | long beginTime = System.currentTimeMillis() 35 | LogM.log("-------ScreenHelper plugin 插件开始-------") 36 | LogM.log("===ScreenHelper plugin 清除文件开始===") 37 | clear()//1.清除之前的文件 38 | LogM.log("===ScreenHelper plugin 清除文件结束===") 39 | LogM.log("===ScreenHelper plugin 读取dimens文件开始===") 40 | read()//2.读取dimens文件 41 | LogM.log("===ScreenHelper plugin 读取dimens文件结束===") 42 | LogM.log("===ScreenHelper plugin 写入配置开始===") 43 | write()//3.创建文件,写入配置 44 | LogM.log("===ScreenHelper plugin 写入配置结束===") 45 | LogM.log("-------ScreenHelper plugin 插件结束,花费" + (System.currentTimeMillis() - beginTime) + "ms-------") 46 | } 47 | /** 48 | * 清除之前的文件 49 | */ 50 | private void clear() { 51 | try { 52 | //找到文件res 下 values-sw 的文件 53 | File resFile = new File(sourcePath + "/src/main/res") 54 | LogM.log(resFile.toString()) 55 | resFile.listFiles(new FilenameFilter() { 56 | @Override 57 | boolean accept(File dir, String name) { 58 | //自定义过滤规则 59 | return name.startsWith("values-sw") 60 | } 61 | }).each { file -> 62 | LogM.log(file.name) 63 | FileUtils.deletePath(file) 64 | } 65 | } catch (IOException e) { 66 | LogM.log(e.getMessage()) 67 | e.printStackTrace() 68 | } 69 | } 70 | 71 | /** 72 | * 读取文件 73 | */ 74 | private void read() { 75 | try { 76 | File file = new File(sourcePath + "/src/main/res/values/" + screenExt.dimensFileName + ".xml") 77 | if (!file.exists()) { 78 | LogM.log("文件不存在") 79 | return 80 | } 81 | SAXReader saxReader = new SAXReader() 82 | Document document = saxReader.read(file) 83 | Element root = document.getRootElement()// 获取根元素 84 | List childList = root.elements("dimen")// dimen 获取特定名称的子元素 85 | for (Element element : childList) { 86 | LogM.log("attributeValue::" + element.attributeValue("name") + " getText::" + element.getText()) 87 | dimenNameList.add(element.attributeValue("name")) 88 | dimenTextList.add(element.getText()) 89 | } 90 | } catch (DocumentException e) { 91 | LogM.log(e.getMessage()) 92 | e.printStackTrace() 93 | } 94 | } 95 | 96 | /** 97 | * 写入文件 98 | */ 99 | private void write() { 100 | for (Integer path : screenExt.smallestWidths) { 101 | String outPutFile = sourcePath + "/src/main/res/values-sw" + path + "dp/dimens.xml" 102 | // LogM.log(outPutFile) 103 | writeSingleFile(outPutFile, path) 104 | } 105 | } 106 | /** 107 | * 1920 * 1080 480 dpi的设备 108 | * 计算公式 : px / (DPI / 160) = dp 109 | * 计算过程 : 1080 / (480 / 160) = 360 110 | * smallestWidth 最小宽度 的值是 360 dp 111 | * @param fileName 112 | * @param size 113 | */ 114 | private void writeSingleFile(String fileName, int size) { 115 | Document document = DocumentHelper.createDocument() 116 | Element rootElement = document.addElement("resources") //创建跟节点 resources 117 | DecimalFormat decimalFormat = new DecimalFormat(screenExt.decimalFormat) //格式化小数点位数,四舍五入 118 | for (int i = 0; i < dimenNameList.size(); i++) { 119 | String text = dimenTextList.get(i) 120 | if (text.endsWith("dp")) { 121 | Element dimen = rootElement.addElement("dimen") 122 | dimen.addAttribute("name", dimenNameList.get(i)) 123 | float textNum = text.substring(0, text.length() - 2) as float 124 | def dimensNum = ((float) size / screenExt.designSmallestWidth) * textNum 125 | dimen.setText(decimalFormat.format(dimensNum) + "dp") 126 | } 127 | } 128 | try { 129 | File fileP = new File(fileName) 130 | if (!fileP.getParentFile().exists()) { 131 | fileP.getParentFile().mkdirs() 132 | } 133 | FileWriter fileWriter = new FileWriter(fileP)// 134 | XMLWriter xmlWriter = new XMLWriter(fileWriter) 135 | xmlWriter.write(document) 136 | xmlWriter.close() 137 | } catch (Exception e) { 138 | LogM.log(e.getMessage()) 139 | e.printStackTrace() 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /screen-plugin/src/main/groovy/vip/ruoyun/screen/LogM.groovy: -------------------------------------------------------------------------------- 1 | package vip.ruoyun.screen 2 | 3 | class LogM { 4 | /** 5 | * 打印日志 6 | * 7 | * @param log 8 | */ 9 | public static void log(Object log) { 10 | if (ScreenPlugin.isDebug) { 11 | println(log) 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /screen-plugin/src/main/groovy/vip/ruoyun/screen/ScreenExt.groovy: -------------------------------------------------------------------------------- 1 | package vip.ruoyun.screen 2 | 3 | /** 4 | * Created by ruoyun on 2018/6/21. 5 | * Author:若云 6 | * Mail:zyhdvlp@gmail.com 7 | * Depiction: 8 | * ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12 9 | * 10 | * 384,392,400,410,411,432,480,533,592,600,640,662,720,768,800,811,820,960,961,1024,1280,1365 11 | * 12 | */ 13 | class ScreenExt { 14 | 15 | String dimensFileName = "dimens" 16 | 17 | /** 18 | * 设计稿的 dpi 或 ppi 19 | * 设计原型图为 720*1080 320ppi 或 320dpi 20 | * 设计图 1080*1920 420dpi 或 420ppi 21 | * 苹果设计稿750 × 1334 326ppi android :720 × 1080 320ppi 22 | * 适配Android 3.2以上 大部分手机的sw值集中在 300-460之间 23 | * 24 | * 1920 * 1080 480 dpi的设备 25 | * 计算公式 : px / (DPI / 160) = dp 26 | * 计算过程 : 1080 / (480 / 160) = 360 27 | * smallestWidth 最小宽度 的值是 360 dp 28 | * 29 | * 1929 * 1080 420dip 的设备 30 | * 计算公式 : px / (DPI / 160) = dp 31 | * 计算过程 : 1080 / (420 / 160) = 411 32 | * smallestWidth 最小宽度 的值是 411 dp 33 | */ 34 | int designSmallestWidth = 375 //设计稿最小宽度 35 | 36 | /** 37 | * 小数点位数,默认一位小数,四舍五入 38 | */ 39 | String decimalFormat = "#.#" 40 | 41 | boolean auto = false 42 | 43 | boolean log = false 44 | 45 | Set smallestWidths = new HashSet<>() 46 | 47 | def dimensFileName(String dimensFileName) { 48 | this.dimensFileName = dimensFileName 49 | } 50 | 51 | def decimalFormat(String decimalFormat) { 52 | this.decimalFormat = decimalFormat 53 | } 54 | 55 | def designSmallestWidth(int designSmallestWidth) { 56 | this.designSmallestWidth = designSmallestWidth 57 | } 58 | 59 | def smallestWidths(Integer... sw) { 60 | this.smallestWidths.addAll(sw) 61 | } 62 | 63 | def auto(boolean auto) { 64 | this.auto = auto 65 | } 66 | 67 | def log(boolean log) { 68 | this.log = log 69 | } 70 | 71 | 72 | } -------------------------------------------------------------------------------- /screen-plugin/src/main/groovy/vip/ruoyun/screen/ScreenPlugin.groovy: -------------------------------------------------------------------------------- 1 | package vip.ruoyun.screen 2 | 3 | import org.gradle.api.Plugin 4 | import org.gradle.api.Project 5 | 6 | /** 7 | * Created by ruoyun on 2018/6/21. 8 | * Author:若云 9 | * Mail:zyhdvlp@gmail.com 10 | * Depiction: 11 | */ 12 | class ScreenPlugin implements Plugin { 13 | private static final String EXTENSION_NAME = "screen" 14 | protected static boolean isDebug = true 15 | 16 | @Override 17 | void apply(Project project) { 18 | project.extensions.create(EXTENSION_NAME, ScreenExt) 19 | project.task("dimensCovert") { 20 | group 'ruoyun' 21 | doLast { 22 | ScreenExt ext = project.extensions.getByName(EXTENSION_NAME) as ScreenExt 23 | def dimenTools = new DimenTools(ext, project.getBuildFile().getParent()) 24 | dimenTools.dimensCovert() 25 | } 26 | } 27 | 28 | project.afterEvaluate { 29 | def screenExt = project.extensions.screen 30 | isDebug = screenExt.log 31 | if (screenExt.auto) { 32 | LogM.log(':dimensCovert') 33 | def dimenTools = new DimenTools(screenExt, project.getBuildFile().getParent()) 34 | dimenTools.dimensCovert() 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /screen-plugin/src/main/resources/META-INF/gradle-plugins/vip.ruoyun.screen.properties: -------------------------------------------------------------------------------- 1 | implementation-class=vip.ruoyun.screen.ScreenPlugin -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':screen-plugin', ':screen-helper' 2 | rootProject.name = 'ScreenLayout' 3 | --------------------------------------------------------------------------------