├── .gitignore
├── README.md
├── README_zh.md
├── Sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── cn
│ │ └── gavinliu
│ │ └── android_scalelayout
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── cn
│ │ └── gavinliu
│ │ └── android_scalelayout
│ │ ├── DemoActivity.java
│ │ ├── DemoListActivity.java
│ │ ├── MainActivity.java
│ │ └── MainApplication.java
│ └── res
│ ├── layout
│ ├── activity_demo.xml
│ ├── activity_demo_list.xml
│ ├── activity_main.xml
│ └── item_demo_list.xml
│ ├── menu
│ └── menu_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── ScaleLayout
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── cn
│ │ └── gavinliu
│ │ └── android
│ │ └── lib
│ │ └── scale
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── cn
│ │ └── gavinliu
│ │ └── android
│ │ └── lib
│ │ └── scale
│ │ ├── ScaleFrameLayout.java
│ │ ├── ScaleLinearLayout.java
│ │ ├── ScaleRelativeLayout.java
│ │ ├── config
│ │ └── ScaleConfig.java
│ │ └── helper
│ │ └── ScaleLayoutHelper.java
│ └── res
│ └── values
│ ├── attrs.xml
│ └── strings.xml
├── build.gradle
├── screenhot.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | #Android generated
2 | bin
3 | gen
4 | gen*
5 |
6 | #Eclipse
7 | .project
8 | .classpath
9 | .settings
10 |
11 | #IntelliJ IDEA
12 | .idea
13 | *.iml
14 | *.ipr
15 | *.iws
16 | out
17 |
18 | #Maven
19 | target
20 | release.properties
21 | pom.xml.*
22 |
23 | #Ant
24 | build.xml
25 | local.properties
26 | proguard.cfg
27 |
28 | #Gradle
29 | .gradle
30 | build
31 |
32 | #OSX
33 | .DS_Store
34 |
35 | #Personal Files
36 | signing.
37 |
38 |
39 | # Built application files
40 | *.apk
41 | *.ap_
42 |
43 | # Files for the Dalvik VM
44 | *.dex
45 |
46 | # Java class files
47 | *.class
48 |
49 | # Generated files
50 | bin/
51 | gen/
52 |
53 | # Gradle files
54 | .gradle/
55 | build/
56 |
57 | # Local configuration file (sdk path, etc)
58 | local.properties
59 |
60 | # Proguard folder generated by Eclipse
61 | proguard/
62 |
63 | # Log Files
64 | *.log
65 |
66 | gradle.properties
67 | gradle/
68 | gradlew
69 | gradlew.bat
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android-ScaleLayout
2 |
3 | A Simple & Convenience MultiScreen-Support-Library for Android
4 |
5 | ## The essence is percent scaling.
6 |
7 | ### different from ``android-percent-support-lib``
8 |
9 | 1. **More reliable**
10 | ``android-percent-support-lib`` The percentage of the parent and child views.
11 | ``Android-ScaleLayout`` The percentage of the design and devices screens.
12 |
13 | 2. **More convenience**
14 | ``android-percent-support-lib`` need to calculate percent.
15 | ``Android-ScaleLayout`` directly write the design size on ``layout.xml``.
16 |
17 |
18 | ## How to look?
19 |
20 | 
21 |
22 |
23 | ## Principle
24 |
25 | ```java
26 | float realPixel = percent * designPixel
27 | ```
28 |
29 | ### Pix Mode
30 |
31 | ```java
32 | float realPixel = percent * designPixel
33 |
34 | float percent = mScreenWidth / designScreenWidth
35 |
36 | float designPixel = res.getDimensionPixelSize()
37 | ```
38 | ```java
39 | float realPixel = mScreenWidth * res.getDimensionPixelSize() / designScreenWidth
40 | ```
41 |
42 | ### DP Mode
43 | ```java
44 | float realPixel = percent * designPixel
45 |
46 | float percent = mScreenWidth / designScreenWidth
47 | float designPixel = designDP * designDensity // dp to pixel
48 |
49 | float designDP = res.getDimensionPixelSize() / mDensity
50 | ```
51 | ```java
52 | float realPixel = (mScreenWidth * designDensity * getPixelSize()) / (designScreenWidth * mDensity)
53 | ```
54 |
55 | ## Usage
56 |
57 | ### 0. dependencies
58 |
59 | ```
60 | dependencies {
61 | compile 'cn.gavinliu.android.lib:ScaleLayout:1.0.4'
62 | }
63 | ```
64 |
65 | ### 1. Initialize
66 |
67 | ```java
68 | public class MyApplication extends Application {
69 |
70 | @Override
71 | public void onCreate() {
72 | ScaleConfig.create(this,
73 | 1080, // Design Width
74 | 1920, // Design Height
75 | 3, // Design Density
76 | 3, // Design FontScale
77 | ScaleConfig.DIMENS_UNIT_DP);
78 | }
79 | }
80 | ```
81 |
82 | > ``TypedValue.COMPLEX_UNIT_SP`` is Android FontSize unit, the ``fontscale``:
83 | > float fontScale = ctx.getResources().getDisplayMetrics().scaledDensity;
84 |
85 | ### 2. Scale***Layout
86 |
87 | Only need to replace ``FrameLayout`` ``LinearLayout`` ``RelativeLayout`` to ``ScaleFrameLayout`` ``ScaleLinearLayout`` ``ScaleRelativeLayout``.
88 |
89 | ### 3. Scale by width or height
90 |
91 | Width is default, you can also changed using attr.
92 |
93 | ```xml
94 |
95 |
96 |
97 |
98 | ```
99 | ```xml
100 | app:layout_scale_by="width"
101 | ```
102 |
103 | ### Support Attrs
104 |
105 | ```xml
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | ```
128 |
129 | ## License
130 |
131 | MIT
132 |
--------------------------------------------------------------------------------
/README_zh.md:
--------------------------------------------------------------------------------
1 | # Android-ScaleLayout
2 |
3 | 一个简单的,方便的多屏适配的Android库
4 |
5 | ## 本质就是百分比缩放
6 |
7 | ### 和 android-percent-support-lib 的不同
8 |
9 | 1. **更科学**
10 | ``android-percent-support-lib`` 是父控件和子控件的百分比关系
11 | ``Android-ScaleLayout`` 是设计界面和设备界面的百分比关系
12 |
13 | 2. **更方便**
14 | ``android-percent-support-lib`` 需要把设计尺寸算成百分比
15 | ``Android-ScaleLayout`` 直接把设计尺寸填入``layou.xml``即可
16 |
17 |
18 | ## How to look?
19 |
20 | 
21 |
22 |
23 | ## 原理
24 |
25 | ```java
26 | float realPixel = percent * designPixel
27 | ```
28 |
29 | ### Pix Mode
30 |
31 | ```java
32 | float realPixel = percent * designPixel
33 |
34 | float percent = mScreenWidth / designScreenWidth
35 |
36 | float designPixel = res.getDimensionPixelSize()
37 | ```
38 | ```java
39 | float realPixel = mScreenWidth * res.getDimensionPixelSize() / designScreenWidth
40 | ```
41 |
42 | ### DP Mode
43 | ```java
44 | float realPixel = percent * designPixel
45 |
46 | float percent = mScreenWidth / designScreenWidth
47 | float designPixel = designDP * designDensity // dp to pixel
48 |
49 | float designDP = res.getDimensionPixelSize() / mDensity
50 | ```
51 | ```java
52 | float realPixel = (mScreenWidth * designDensity * getPixelSize()) / (designScreenWidth * mDensity)
53 | ```
54 |
55 | ## 使用
56 |
57 | ### 0. 依赖
58 |
59 | ```
60 | dependencies {
61 | compile 'cn.gavinliu.android.lib:ScaleLayout:1.0.4'
62 | }
63 | ```
64 |
65 | ### 1. 初始化
66 |
67 | ```java
68 | public class MyApplication extends Application {
69 |
70 | @Override
71 | public void onCreate() {
72 | ScaleConfig.create(this,
73 | 1080, // Design Width
74 | 1920, // Design Height
75 | 3, // Design Density
76 | 3, // Design FontScale
77 | ScaleConfig.DIMENS_UNIT_DP);
78 | }
79 | }
80 | ```
81 |
82 | > Android 文字大小的单位是 ``sp``,字体的缩放方式需要 FontScale:
83 | > float fontScale = ctx.getResources().getDisplayMetrics().scaledDensity;
84 |
85 | ### 2. Scale***Layout
86 |
87 | 只需要把 ``FrameLayout`` ``LinearLayout`` ``RelativeLayout`` 替换成 ``ScaleFrameLayout`` ``ScaleLinearLayout`` ``ScaleRelativeLayout``.
88 |
89 | ### 3. Scale by width or height
90 |
91 | 默认是 width,当然你可以用属性修改。
92 |
93 | ```xml
94 |
95 |
96 |
97 |
98 | ```
99 | ```xml
100 | app:layout_scale_by="width"
101 | ```
102 |
103 | ### 支持的属性
104 |
105 | ```xml
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | ```
128 |
129 | ## License
130 |
131 | MIT
132 |
--------------------------------------------------------------------------------
/Sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "24.0.1"
6 |
7 | defaultConfig {
8 | applicationId "cn.gavinliu.android_scalelayout"
9 | minSdkVersion 9
10 | targetSdkVersion 24
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | // compile project(':ScaleLayout')
24 | compile 'cn.gavinliu.android.lib:ScaleLayout:1.0.4'
25 |
26 | compile 'com.android.support:appcompat-v7:24.2.0'
27 | }
28 |
--------------------------------------------------------------------------------
/Sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/gavin/Develop/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/Sample/src/androidTest/java/cn/gavinliu/android_scalelayout/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android_scalelayout;
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 | }
--------------------------------------------------------------------------------
/Sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Sample/src/main/java/cn/gavinliu/android_scalelayout/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android_scalelayout;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | /**
8 | * Created by Gavin on 2016/11/20.
9 | */
10 |
11 | public class DemoActivity extends AppCompatActivity {
12 |
13 | @Override
14 | protected void onCreate(@Nullable Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_demo);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Sample/src/main/java/cn/gavinliu/android_scalelayout/DemoListActivity.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android_scalelayout;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.BaseAdapter;
12 | import android.widget.ListView;
13 |
14 | /**
15 | * Created by Gavin on 2016/11/20.
16 | */
17 |
18 | public class DemoListActivity extends AppCompatActivity {
19 |
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_demo_list);
24 |
25 | ListView listView = (ListView) findViewById(R.id.list);
26 | listView.setAdapter(new Adapter(getApplicationContext()));
27 | }
28 |
29 | @NonNull
30 | @Override
31 | public LayoutInflater getLayoutInflater() {
32 | return super.getLayoutInflater();
33 | }
34 |
35 | private static class Adapter extends BaseAdapter {
36 |
37 | private Context ctx;
38 |
39 | private Adapter(Context ctx) {
40 | this.ctx = ctx;
41 | }
42 |
43 | @Override
44 | public int getCount() {
45 | return 20;
46 | }
47 |
48 | @Override
49 | public Object getItem(int position) {
50 | return null;
51 | }
52 |
53 | @Override
54 | public long getItemId(int position) {
55 | return position;
56 | }
57 |
58 | @Override
59 | public View getView(int position, View convertView, ViewGroup parent) {
60 | if (convertView == null) {
61 | convertView = LayoutInflater.from(ctx).inflate(R.layout.item_demo_list, parent, false);
62 | }
63 | return convertView;
64 | }
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/Sample/src/main/java/cn/gavinliu/android_scalelayout/MainActivity.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android_scalelayout;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 | public class MainActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_main);
14 | }
15 |
16 | public void demo(View view) {
17 | Intent intent = new Intent(this, DemoActivity.class);
18 | startActivity(intent);
19 | }
20 |
21 | public void demoList(View view) {
22 | Intent intent = new Intent(this, DemoListActivity.class);
23 | startActivity(intent);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/Sample/src/main/java/cn/gavinliu/android_scalelayout/MainApplication.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android_scalelayout;
2 |
3 | import android.app.Application;
4 |
5 | import cn.gavinliu.android.lib.scale.config.ScaleConfig;
6 |
7 | /**
8 | * Created by Gavin on 16-11-10.
9 | */
10 |
11 | public class MainApplication extends Application {
12 |
13 | @Override
14 | public void onCreate() {
15 | super.onCreate();
16 | ScaleConfig.create(this,
17 | 1080, // Design Width
18 | 1920, // Design Height
19 | 3, // Design Density
20 | 3, // Design FontScale
21 | ScaleConfig.DIMENS_UNIT_DP);
22 | ScaleConfig.getInstance().setDebug(true);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Sample/src/main/res/layout/activity_demo.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
26 |
27 |
37 |
38 |
39 |
40 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Sample/src/main/res/layout/activity_demo_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/Sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
14 |
15 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Sample/src/main/res/layout/item_demo_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
24 |
25 |
--------------------------------------------------------------------------------
/Sample/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/Sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavinliu/Android-ScaleLayout/a62b7c269ac808322d0aebca3be6a76db0c81a43/Sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavinliu/Android-ScaleLayout/a62b7c269ac808322d0aebca3be6a76db0c81a43/Sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavinliu/Android-ScaleLayout/a62b7c269ac808322d0aebca3be6a76db0c81a43/Sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavinliu/Android-ScaleLayout/a62b7c269ac808322d0aebca3be6a76db0c81a43/Sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/Sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Android-ScaleLayout
3 |
4 | Hello world!
5 | Settings
6 |
7 |
--------------------------------------------------------------------------------
/Sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ScaleLayout/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/ScaleLayout/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "24.0.1"
6 |
7 | defaultConfig {
8 | minSdkVersion 9
9 | targetSdkVersion 24
10 | versionCode 5
11 | versionName "1.0.4"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile 'com.android.support:support-v4:24.2.0'
23 | }
24 |
25 | apply plugin: 'com.github.dcendents.android-maven'
26 | apply plugin: 'com.jfrog.bintray'
27 |
28 | def siteUrl = 'https://github.com/gavinliu/Android-ScaleLayout' // 项目的主页
29 | def gitUrl = 'https://github.com/gavinliu/Android-ScaleLayout.git' // Git仓库的url
30 |
31 | version = "1.0.4"
32 | group = "cn.gavinliu.android.lib"
33 |
34 | install {
35 | repositories.mavenInstaller {
36 | pom {
37 | project {
38 | packaging 'aar'
39 |
40 | //添加项目描述
41 | name 'ScaleLayout: A MultiScreen-Support-Library for Android'
42 | url siteUrl
43 |
44 | //设置开源证书信息
45 | licenses {
46 | license {
47 | name 'The MIT License (MIT)'
48 | url 'http://mit-license.org/'
49 | }
50 | }
51 | //添加开发者信息
52 | developers {
53 | developer {
54 | id 'gavin6liu'
55 | name 'Gavin.Liu'
56 | email 'gavin6liu@gmail.com'
57 | }
58 | }
59 |
60 | scm {
61 | connection gitUrl
62 | developerConnection gitUrl
63 | url siteUrl
64 | }
65 | }
66 | }
67 | }
68 | }
69 |
70 | task sourcesJar(type: Jar) {
71 | from android.sourceSets.main.java.srcDirs
72 | classifier = 'sources'
73 | }
74 |
75 | task javadoc(type: Javadoc) {
76 | source = android.sourceSets.main.java.srcDirs
77 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
78 | }
79 |
80 | task javadocJar(type: Jar, dependsOn: javadoc) {
81 | classifier = 'javadoc'
82 | from javadoc.destinationDir
83 | }
84 |
85 | artifacts {
86 | archives javadocJar
87 | archives sourcesJar
88 | }
89 |
90 | Properties properties = new Properties()
91 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
92 |
93 | bintray {
94 | user = properties.getProperty("bintray.user")
95 | key = properties.getProperty("bintray.apikey")
96 |
97 | configurations = ['archives']
98 |
99 | pkg {
100 | repo = "maven"//上传的中央仓库名称
101 | name = "ScaleLayout"//上传的项目的名字
102 | websiteUrl = siteUrl
103 | vcsUrl = gitUrl
104 | licenses = ["MIT"]
105 | publish = true //是否发布
106 | }
107 | }
--------------------------------------------------------------------------------
/ScaleLayout/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/gavin/Develop/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/ScaleLayout/src/androidTest/java/cn/gavinliu/android/lib/scale/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android.lib.scale;
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 | }
--------------------------------------------------------------------------------
/ScaleLayout/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/ScaleFrameLayout.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android.lib.scale;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.util.AttributeSet;
6 | import android.widget.FrameLayout;
7 |
8 | import cn.gavinliu.android.lib.scale.helper.ScaleLayoutHelper;
9 |
10 | /**
11 | * Created by GavinLiu on 2015-08-10
12 | */
13 | public class ScaleFrameLayout extends FrameLayout {
14 |
15 | private ScaleLayoutHelper mHelper;
16 |
17 | public ScaleFrameLayout(Context context) {
18 | this(context, null);
19 | }
20 |
21 | public ScaleFrameLayout(Context context, AttributeSet attrs) {
22 | this(context, attrs, 0);
23 | }
24 |
25 | public ScaleFrameLayout(Context context, AttributeSet attrs, int defStyle) {
26 | super(context, attrs, defStyle);
27 | if (!isInEditMode()) {
28 | mHelper = ScaleLayoutHelper.create(this, attrs);
29 | }
30 | }
31 |
32 | @Override
33 | protected LayoutParams generateDefaultLayoutParams() {
34 | return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
35 | }
36 |
37 | @Override
38 | public LayoutParams generateLayoutParams(AttributeSet attrs) {
39 | return new LayoutParams(this.getContext(), attrs, isInEditMode());
40 | }
41 |
42 | @Override
43 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
44 | if (!isInEditMode()) {
45 | this.mHelper.adjustHost(widthMeasureSpec, heightMeasureSpec);
46 | this.mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
47 | }
48 |
49 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
50 | // if (this.mHelper.handleMeasuredStateTooSmall()) {
51 | // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
52 | // }
53 | }
54 |
55 | @Override
56 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
57 | super.onLayout(changed, left, top, right, bottom);
58 | // this.mHelper.restoreOriginalParams();
59 | }
60 |
61 | public static class LayoutParams extends FrameLayout.LayoutParams implements ScaleLayoutHelper.ScaleLayoutParams {
62 | private ScaleLayoutHelper.ScaleLayoutInfo mPercentLayoutInfo;
63 |
64 | public LayoutParams(Context c, AttributeSet attrs) {
65 | super(c, attrs);
66 | this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
67 | }
68 |
69 | private LayoutParams(Context c, AttributeSet attrs, boolean isInEditMode) {
70 | super(c, attrs);
71 | if (!isInEditMode) {
72 | this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
73 | }
74 | }
75 |
76 | public LayoutParams(int width, int height) {
77 | super(width, height);
78 | }
79 |
80 | public LayoutParams(android.view.ViewGroup.LayoutParams source) {
81 | super(source);
82 | }
83 |
84 | public LayoutParams(MarginLayoutParams source) {
85 | super(source);
86 | }
87 |
88 | @Override
89 | public ScaleLayoutHelper.ScaleLayoutInfo getScaleLayoutInfo() {
90 | return this.mPercentLayoutInfo;
91 | }
92 |
93 | @Override
94 | protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
95 | ScaleLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
96 | }
97 |
98 | @Override
99 | public void setMargins(int left, int top, int right, int bottom) {
100 | super.setMargins(left, top, right, bottom);
101 | if (mPercentLayoutInfo != null) {
102 | mPercentLayoutInfo.setMargins(left, top, right, bottom);
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/ScaleLinearLayout.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android.lib.scale;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.os.Build;
7 | import android.util.AttributeSet;
8 | import android.widget.LinearLayout;
9 |
10 | import cn.gavinliu.android.lib.scale.helper.ScaleLayoutHelper;
11 |
12 | /**
13 | * Created by Gavin on 16-9-20.
14 | */
15 | public class ScaleLinearLayout extends LinearLayout {
16 |
17 | private ScaleLayoutHelper mHelper;
18 |
19 | public ScaleLinearLayout(Context context) {
20 | this(context, null);
21 | }
22 |
23 | public ScaleLinearLayout(Context context, AttributeSet attrs) {
24 | this(context, attrs, 0);
25 | }
26 |
27 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
28 | public ScaleLinearLayout(Context context, AttributeSet attrs, int defStyle) {
29 | super(context, attrs, defStyle);
30 | if (!isInEditMode()) {
31 | mHelper = ScaleLayoutHelper.create(this, attrs);
32 | }
33 | }
34 |
35 | @Override
36 | protected LayoutParams generateDefaultLayoutParams() {
37 | return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
38 | }
39 |
40 | @Override
41 | public LayoutParams generateLayoutParams(AttributeSet attrs) {
42 | return new LayoutParams(this.getContext(), attrs, isInEditMode());
43 | }
44 |
45 | @Override
46 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
47 | if (!isInEditMode()) {
48 | this.mHelper.adjustHost(widthMeasureSpec, heightMeasureSpec);
49 | this.mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
50 | }
51 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
52 | // if (this.mHelper.handleMeasuredStateTooSmall()) {
53 | // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
54 | // }
55 | }
56 |
57 | @Override
58 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
59 | super.onLayout(changed, left, top, right, bottom);
60 | // this.mHelper.restoreOriginalParams();
61 | }
62 |
63 | public static class LayoutParams extends LinearLayout.LayoutParams implements ScaleLayoutHelper.ScaleLayoutParams {
64 | private ScaleLayoutHelper.ScaleLayoutInfo mPercentLayoutInfo;
65 |
66 | public LayoutParams(Context c, AttributeSet attrs) {
67 | super(c, attrs);
68 | this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
69 | }
70 |
71 | private LayoutParams(Context c, AttributeSet attrs, boolean isInEditMode) {
72 | super(c, attrs);
73 | if (!isInEditMode) {
74 | this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
75 | }
76 | }
77 |
78 | public LayoutParams(int width, int height) {
79 | super(width, height);
80 | }
81 |
82 | public LayoutParams(android.view.ViewGroup.LayoutParams source) {
83 | super(source);
84 | }
85 |
86 | public LayoutParams(MarginLayoutParams source) {
87 | super(source);
88 | }
89 |
90 | @Override
91 | public ScaleLayoutHelper.ScaleLayoutInfo getScaleLayoutInfo() {
92 | return this.mPercentLayoutInfo;
93 | }
94 |
95 | @Override
96 | protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
97 | ScaleLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
98 | }
99 |
100 | @Override
101 | public void setMargins(int left, int top, int right, int bottom) {
102 | super.setMargins(left, top, right, bottom);
103 | if (mPercentLayoutInfo != null) {
104 | mPercentLayoutInfo.setMargins(left, top, right, bottom);
105 | }
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/ScaleRelativeLayout.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android.lib.scale;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.util.AttributeSet;
6 | import android.widget.RelativeLayout;
7 |
8 | import cn.gavinliu.android.lib.scale.helper.ScaleLayoutHelper;
9 |
10 | /**
11 | * Created by GavinLiu on 2015-08-10
12 | */
13 | public class ScaleRelativeLayout extends RelativeLayout {
14 |
15 | private ScaleLayoutHelper mHelper;
16 |
17 | public ScaleRelativeLayout(Context context) {
18 | this(context, null);
19 | }
20 |
21 | public ScaleRelativeLayout(Context context, AttributeSet attrs) {
22 | this(context, attrs, 0);
23 | }
24 |
25 | public ScaleRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
26 | super(context, attrs, defStyle);
27 | if (!isInEditMode()) {
28 | mHelper = ScaleLayoutHelper.create(this, attrs);
29 | }
30 | }
31 |
32 | @Override
33 | protected LayoutParams generateDefaultLayoutParams() {
34 | return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
35 | }
36 |
37 | @Override
38 | public LayoutParams generateLayoutParams(AttributeSet attrs) {
39 | return new LayoutParams(this.getContext(), attrs, isInEditMode());
40 | }
41 |
42 | @Override
43 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
44 | if (!isInEditMode()) {
45 | this.mHelper.adjustHost(widthMeasureSpec, heightMeasureSpec);
46 | this.mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
47 | }
48 |
49 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
50 | // if (this.mHelper.handleMeasuredStateTooSmall()) {
51 | // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
52 | // }
53 | }
54 |
55 | @Override
56 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
57 | super.onLayout(changed, left, top, right, bottom);
58 | // this.mHelper.restoreOriginalParams();
59 | }
60 |
61 | public static class LayoutParams extends android.widget.RelativeLayout.LayoutParams implements ScaleLayoutHelper.ScaleLayoutParams {
62 | private ScaleLayoutHelper.ScaleLayoutInfo mPercentLayoutInfo;
63 |
64 | public LayoutParams(Context c, AttributeSet attrs) {
65 | super(c, attrs);
66 | this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
67 | }
68 |
69 | private LayoutParams(Context c, AttributeSet attrs, boolean isInEditMode) {
70 | super(c, attrs);
71 | if (!isInEditMode) {
72 | this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
73 | }
74 | }
75 |
76 | public LayoutParams(int width, int height) {
77 | super(width, height);
78 | }
79 |
80 | public LayoutParams(android.view.ViewGroup.LayoutParams source) {
81 | super(source);
82 | }
83 |
84 | public LayoutParams(MarginLayoutParams source) {
85 | super(source);
86 | }
87 |
88 | @Override
89 | public ScaleLayoutHelper.ScaleLayoutInfo getScaleLayoutInfo() {
90 | return this.mPercentLayoutInfo;
91 | }
92 |
93 | @Override
94 | protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
95 | ScaleLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
96 | }
97 |
98 | @Override
99 | public void setMargins(int left, int top, int right, int bottom) {
100 | super.setMargins(left, top, right, bottom);
101 | if (mPercentLayoutInfo != null) {
102 | mPercentLayoutInfo.setMargins(left, top, right, bottom);
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/config/ScaleConfig.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android.lib.scale.config;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Created by Gavin on 16-9-20.
7 | */
8 | public class ScaleConfig {
9 |
10 | private int mDesignWidth;
11 | private int mDesignHeight;
12 | private float mDesignDensity;
13 |
14 | private int mScreenWidth;
15 | private int mScreenHeight;
16 | private float mScreenDensity;
17 |
18 | private float mDesignFontScale;
19 | private float mScreenFontScale;
20 |
21 | private int mDimensionUnit;
22 |
23 | public static final int DIMENS_UNIT_DP = 0;
24 | public static final int DIMENS_UNIT_PIX = 1;
25 |
26 | private boolean mDebug;
27 |
28 | private static ScaleConfig mInstance;
29 |
30 | /**
31 | * @param ctx Context
32 | * @param designWidth Design Width (Pixel)
33 | * @param designHeight Design Height (Pixel)
34 | * @param designDensity Design Density
35 | * @param designFontScale Design FontScale (getDisplayMetrics().scaledDensity)
36 | * @param dimensionUnit DIMENS_UNIT_DP or DIMENS_UNIT_PIX
37 | * @return Single instance
38 | */
39 | public static ScaleConfig create(Context ctx, int designWidth, int designHeight, float designDensity, float designFontScale, int dimensionUnit) {
40 | if (mInstance == null) {
41 | mInstance = new ScaleConfig(ctx, designWidth, designHeight, designDensity, designFontScale, dimensionUnit);
42 | }
43 |
44 | return mInstance;
45 | }
46 |
47 | public static ScaleConfig getInstance() {
48 | if (mInstance == null)
49 | throw new IllegalArgumentException("You must call ScaleConfig.create first");
50 |
51 | return mInstance;
52 | }
53 |
54 | private ScaleConfig(Context ctx) {
55 | final int width = ctx.getResources().getDisplayMetrics().widthPixels;
56 | final int height = ctx.getResources().getDisplayMetrics().heightPixels;
57 | final float density = ctx.getResources().getDisplayMetrics().density;
58 | final float fontScale = ctx.getResources().getDisplayMetrics().scaledDensity;
59 |
60 | mScreenWidth = width;
61 | mScreenHeight = height;
62 | mScreenDensity = density;
63 | mScreenFontScale = fontScale;
64 | }
65 |
66 | private ScaleConfig(Context ctx, int designWidth, int designHeight, float designDensity, float designFontScale, int dimensionUnit) {
67 | this(ctx);
68 | mDesignWidth = designWidth;
69 | mDesignHeight = designHeight;
70 | mDesignDensity = designDensity;
71 | mDesignFontScale = designFontScale;
72 | mDimensionUnit = dimensionUnit;
73 | }
74 |
75 | public boolean isDebug() {
76 | return mDebug;
77 | }
78 |
79 | public void setDebug(boolean debug) {
80 | mDebug = debug;
81 | }
82 |
83 | public boolean isDimensUnitByDp() {
84 | return mDimensionUnit == DIMENS_UNIT_DP;
85 | }
86 |
87 | public int getDesignWidth() {
88 | return mDesignWidth;
89 | }
90 |
91 | public int getDesignHeight() {
92 | return mDesignHeight;
93 | }
94 |
95 | public float getDesignDensity() {
96 | return mDesignDensity;
97 | }
98 |
99 | public float getScreenDensity() {
100 | return mScreenDensity;
101 | }
102 |
103 | public float getDesignFontScale() {
104 | return mDesignFontScale;
105 | }
106 |
107 | public float getScreenFontScale() {
108 | return mScreenFontScale;
109 | }
110 |
111 | public int getScreenWidth() {
112 | return mScreenWidth;
113 | }
114 |
115 | public int getScreenHeight() {
116 | return mScreenHeight;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/helper/ScaleLayoutHelper.java:
--------------------------------------------------------------------------------
1 | package cn.gavinliu.android.lib.scale.helper;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.support.v4.view.MarginLayoutParamsCompat;
6 | import android.support.v4.view.ViewCompat;
7 | import android.util.AttributeSet;
8 | import android.util.Log;
9 | import android.util.TypedValue;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.TextView;
13 |
14 | import cn.gavinliu.android.lib.scale.R;
15 | import cn.gavinliu.android.lib.scale.config.ScaleConfig;
16 |
17 | /**
18 | * Created by GavinLiu on 2015-08-10
19 | */
20 | public class ScaleLayoutHelper {
21 |
22 | private static final String TAG = "ScaleLayoutHelper";
23 |
24 | private final ViewGroup mHost;
25 | private final ScaleLayoutInfo mHostLayoutInfo;
26 |
27 | public interface ScaleLayoutParams {
28 | ScaleLayoutInfo getScaleLayoutInfo();
29 | }
30 |
31 | public ScaleLayoutHelper(ViewGroup host, ScaleLayoutInfo layoutInfo) {
32 | this.mHost = host;
33 | this.mHostLayoutInfo = layoutInfo;
34 | }
35 |
36 | public static ScaleLayoutHelper create(ViewGroup view, AttributeSet attrs) {
37 | return new ScaleLayoutHelper(view, getScaleLayoutInfo(view.getContext(), attrs));
38 | }
39 |
40 | public void adjustChildren(int widthMeasureSpec, int heightMeasureSpec) {
41 | int i = 0;
42 | for (int N = this.mHost.getChildCount(); i < N; ++i) {
43 | View view = this.mHost.getChildAt(i);
44 | ViewGroup.LayoutParams params = view.getLayoutParams();
45 |
46 | if (params instanceof ScaleLayoutParams) {
47 | ScaleLayoutInfo info = ((ScaleLayoutParams) params).getScaleLayoutInfo();
48 | if (ScaleConfig.getInstance().isDebug()) {
49 | Log.d(TAG, "adjustChildren using " + info + " " + view);
50 | }
51 | if (info != null && mHostLayoutInfo != null) {
52 | if (params instanceof ViewGroup.MarginLayoutParams) {
53 | info.fillMarginLayoutParams(view, (ViewGroup.MarginLayoutParams) params);
54 | } else {
55 | info.fillLayoutParams(view, params);
56 | }
57 |
58 | info.fillView(view);
59 | }
60 | }
61 | }
62 | }
63 |
64 | public void adjustHost(int widthMeasureSpec, int heightMeasureSpec) {
65 | if (mHostLayoutInfo != null) {
66 | ViewGroup.LayoutParams params = mHost.getLayoutParams();
67 | if (params instanceof ViewGroup.MarginLayoutParams) {
68 | mHostLayoutInfo.fillMarginLayoutParams(mHost, (ViewGroup.MarginLayoutParams) params);
69 | } else {
70 | mHostLayoutInfo.fillLayoutParams(mHost, params);
71 | }
72 | }
73 | }
74 |
75 | public void restoreOriginalParams() {
76 | int i = 0;
77 |
78 | for (int N = this.mHost.getChildCount(); i < N; ++i) {
79 | View view = this.mHost.getChildAt(i);
80 | ViewGroup.LayoutParams params = view.getLayoutParams();
81 |
82 | if (params instanceof ScaleLayoutParams) {
83 | ScaleLayoutInfo info = ((ScaleLayoutParams) params).getScaleLayoutInfo();
84 | if (ScaleConfig.getInstance().isDebug()) {
85 | Log.d(TAG, "restoreOriginalParams using " + info);
86 | }
87 |
88 | if (info != null) {
89 | if (params instanceof ViewGroup.MarginLayoutParams) {
90 | info.restoreMarginLayoutParams((ViewGroup.MarginLayoutParams) params);
91 | } else {
92 | info.restoreLayoutParams(params);
93 | }
94 | }
95 | }
96 | }
97 |
98 | }
99 |
100 | public static void fetchWidthAndHeight(ViewGroup.LayoutParams params, TypedArray array, int widthAttr, int heightAttr) {
101 | params.width = array.getLayoutDimension(widthAttr, 0);
102 | params.height = array.getLayoutDimension(heightAttr, 0);
103 | }
104 |
105 | public static ScaleLayoutInfo getScaleLayoutInfo(Context context, AttributeSet attrs) {
106 | ScaleLayoutInfo info = new ScaleLayoutInfo(context);
107 |
108 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ScaleLayout);
109 |
110 | int value = array.getInt(R.styleable.ScaleLayout_layout_scale_by, 0);
111 | if (value != 0) {
112 | info.scaleBy = value;
113 | }
114 |
115 | try {
116 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_width, 0);
117 | if (value != 0) {
118 | info.width = value;
119 | }
120 | } catch (Exception e) {
121 | }
122 |
123 | try {
124 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_height, 0);
125 | if (value != 0) {
126 | info.height = value;
127 | }
128 | } catch (Exception e) {
129 | }
130 |
131 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_margin, 0);
132 | if (value != 0) {
133 | info.leftMargin = value;
134 | info.topMargin = value;
135 | info.rightMargin = value;
136 | info.bottomMargin = value;
137 | }
138 |
139 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginLeft, 0);
140 | if (value != 0) {
141 | info.leftMargin = value;
142 | }
143 |
144 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginTop, 0);
145 | if (value != 0) {
146 | info.topMargin = value;
147 | }
148 |
149 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginRight, 0);
150 | if (value != 0) {
151 | info.rightMargin = value;
152 | }
153 |
154 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginBottom, 0);
155 | if (value != 0) {
156 | info.bottomMargin = value;
157 | }
158 |
159 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginStart, 0);
160 | if (value != 0) {
161 | info.startMargin = value;
162 | }
163 |
164 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginEnd, 0);
165 | if (value != 0) {
166 | info.endMargin = value;
167 | }
168 |
169 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_padding, 0);
170 | if (value != 0) {
171 | info.leftPadding = value;
172 | info.topPadding = value;
173 | info.rightPadding = value;
174 | info.bottomPadding = value;
175 | }
176 |
177 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_paddingLeft, 0);
178 | if (value != 0) {
179 | info.leftPadding = value;
180 | }
181 |
182 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_paddingTop, 0);
183 | if (value != 0) {
184 | info.topPadding = value;
185 | }
186 |
187 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_paddingRight, 0);
188 | if (value != 0) {
189 | info.rightPadding = value;
190 | }
191 |
192 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_paddingBottom, 0);
193 | if (value != 0) {
194 | info.bottomPadding = value;
195 | }
196 |
197 | value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_textSize, 0);
198 | if (value != 0) {
199 | info.textSize = value;
200 | }
201 |
202 | array.recycle();
203 |
204 | if (ScaleConfig.getInstance().isDebug()) {
205 | Log.d(TAG, "constructed: " + info);
206 | }
207 | return info;
208 | }
209 |
210 | public boolean handleMeasuredStateTooSmall() {
211 | boolean needsSecondMeasure = false;
212 | int i = 0;
213 |
214 | for (int N = this.mHost.getChildCount(); i < N; ++i) {
215 | View view = this.mHost.getChildAt(i);
216 | ViewGroup.LayoutParams params = view.getLayoutParams();
217 |
218 | if (params instanceof ScaleLayoutParams) {
219 | ScaleLayoutInfo info = ((ScaleLayoutParams) params).getScaleLayoutInfo();
220 | if (info != null) {
221 | if (shouldHandleMeasuredWidthTooSmall(view, info)) {
222 | needsSecondMeasure = true;
223 | params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
224 | }
225 |
226 | if (shouldHandleMeasuredHeightTooSmall(view, info)) {
227 | needsSecondMeasure = true;
228 | params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
229 | }
230 | }
231 | }
232 | }
233 |
234 | if (ScaleConfig.getInstance().isDebug()) {
235 | Log.d(TAG, "should trigger second measure pass: " + needsSecondMeasure);
236 | }
237 |
238 | return needsSecondMeasure;
239 | }
240 |
241 | private static boolean shouldHandleMeasuredWidthTooSmall(View view, ScaleLayoutInfo info) {
242 | int state = ViewCompat.getMeasuredWidthAndState(view) & ViewCompat.MEASURED_STATE_MASK;
243 | return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.width >= 0.0F && info.mPreservedParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
244 | }
245 |
246 | private static boolean shouldHandleMeasuredHeightTooSmall(View view, ScaleLayoutInfo info) {
247 | int state = ViewCompat.getMeasuredHeightAndState(view) & ViewCompat.MEASURED_STATE_MASK;
248 | return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.height >= 0.0F && info.mPreservedParams.height == ViewGroup.LayoutParams.WRAP_CONTENT;
249 | }
250 |
251 | public static class ScaleLayoutInfo {
252 | private int designWidth;
253 | private int designHeight;
254 |
255 | private int screenW;
256 | private int screenH;
257 |
258 | public int width = 0;
259 | public int height = 0;
260 |
261 | private int scaleBy = ScaleByWidth;
262 | private static final int ScaleByWidth = 0;
263 | private static final int ScaleByHeight = 1;
264 |
265 | private int leftMargin;
266 | private int topMargin;
267 | private int rightMargin;
268 | private int bottomMargin;
269 | private int startMargin;
270 | private int endMargin;
271 |
272 | private int leftPadding;
273 | private int topPadding;
274 | private int rightPadding;
275 | private int bottomPadding;
276 |
277 | private int textSize;
278 |
279 | final ViewGroup.MarginLayoutParams mPreservedParams = new ViewGroup.MarginLayoutParams(0, 0);
280 |
281 | public ScaleLayoutInfo(Context ctx) {
282 | designWidth = ScaleConfig.getInstance().getDesignWidth();
283 | designHeight = ScaleConfig.getInstance().getDesignHeight();
284 |
285 | screenW = ctx.getResources().getDisplayMetrics().widthPixels;
286 | screenH = ctx.getResources().getDisplayMetrics().heightPixels;
287 | }
288 |
289 | public void fillLayoutParams(View view, ViewGroup.LayoutParams params) {
290 | this.mPreservedParams.width = params.width;
291 | this.mPreservedParams.height = params.height;
292 |
293 | if (this.width > 0.0) {
294 | params.width = getRealPixelSize(this.width);
295 | }
296 |
297 | if (this.height > 0.0) {
298 | params.height = getRealPixelSize(this.height);
299 | }
300 |
301 | int paddingL = 0, paddingT = 0, paddingR = 0, paddingB = 0;
302 |
303 | if (this.leftPadding > 0.0) {
304 | paddingL = getRealPixelSize(this.leftPadding);
305 | }
306 |
307 | if (this.topPadding > 0.0) {
308 | paddingT = getRealPixelSize(this.topPadding);
309 | }
310 |
311 | if (this.rightPadding > 0.0) {
312 | paddingR = getRealPixelSize(this.rightPadding);
313 | }
314 |
315 | if (this.bottomPadding > 0.0) {
316 | paddingB = getRealPixelSize(this.bottomPadding);
317 | }
318 |
319 | view.setPadding(paddingL, paddingT, paddingR, paddingB);
320 | }
321 |
322 | public void fillMarginLayoutParams(View view, ViewGroup.MarginLayoutParams params) {
323 | this.fillLayoutParams(view, params);
324 | this.mPreservedParams.leftMargin = params.leftMargin;
325 | this.mPreservedParams.topMargin = params.topMargin;
326 | this.mPreservedParams.rightMargin = params.rightMargin;
327 | this.mPreservedParams.bottomMargin = params.bottomMargin;
328 | MarginLayoutParamsCompat.setMarginStart(this.mPreservedParams, MarginLayoutParamsCompat.getMarginStart(params));
329 | MarginLayoutParamsCompat.setMarginEnd(this.mPreservedParams, MarginLayoutParamsCompat.getMarginEnd(params));
330 |
331 | if (this.leftMargin > 0.0F) {
332 | params.leftMargin = getRealPixelSize(this.leftMargin);
333 | }
334 |
335 | if (this.topMargin > 0.0F) {
336 | params.topMargin = getRealPixelSize(this.topMargin);
337 | }
338 |
339 | if (this.rightMargin > 0.0F) {
340 | params.rightMargin = getRealPixelSize(this.rightMargin);
341 | }
342 |
343 | if (this.bottomMargin > 0.0F) {
344 | params.bottomMargin = getRealPixelSize(this.bottomMargin);
345 | }
346 |
347 | if (this.startMargin > 0.0F) {
348 | MarginLayoutParamsCompat.setMarginStart(params, getRealPixelSize(this.startMargin));
349 | }
350 |
351 | if (this.endMargin > 0.0F) {
352 | MarginLayoutParamsCompat.setMarginEnd(params, getRealPixelSize(this.endMargin));
353 | }
354 |
355 | }
356 |
357 | public void fillView(View view) {
358 | if (view instanceof TextView) {
359 | if (this.textSize > 0) {
360 | int newTextSize = getRealFontSize(this.textSize);
361 | ((TextView) view).setTextSize(TypedValue.COMPLEX_UNIT_PX, newTextSize);
362 | }
363 | }
364 | }
365 |
366 | public void restoreMarginLayoutParams(ViewGroup.MarginLayoutParams params) {
367 | this.restoreLayoutParams(params);
368 | params.leftMargin = this.mPreservedParams.leftMargin;
369 | params.topMargin = this.mPreservedParams.topMargin;
370 | params.rightMargin = this.mPreservedParams.rightMargin;
371 | params.bottomMargin = this.mPreservedParams.bottomMargin;
372 | MarginLayoutParamsCompat.setMarginStart(params, MarginLayoutParamsCompat.getMarginStart(this.mPreservedParams));
373 | MarginLayoutParamsCompat.setMarginEnd(params, MarginLayoutParamsCompat.getMarginEnd(this.mPreservedParams));
374 | }
375 |
376 | public void restoreLayoutParams(ViewGroup.LayoutParams params) {
377 | params.width = this.mPreservedParams.width;
378 | params.height = this.mPreservedParams.height;
379 | }
380 |
381 | public void setMargins(int left, int top, int right, int bottom) {
382 | leftPadding = left;
383 | topPadding = top;
384 | rightPadding = right;
385 | bottomPadding = bottom;
386 | }
387 |
388 | private int getRealFontSize(int pix) {
389 | int screen, design;
390 | switch (scaleBy) {
391 | case ScaleByHeight:
392 | screen = screenH;
393 | design = designHeight;
394 | break;
395 | default:
396 | screen = screenW;
397 | design = designWidth;
398 | break;
399 | }
400 |
401 | return getRealPixelSizeBySP(pix, screen, design);
402 | }
403 |
404 | private int getRealPixelSize(int pix) {
405 | int screen, design;
406 | switch (scaleBy) {
407 | case ScaleByHeight:
408 | screen = screenH;
409 | design = designHeight;
410 | break;
411 | default:
412 | screen = screenW;
413 | design = designWidth;
414 | break;
415 | }
416 |
417 | if (ScaleConfig.getInstance().isDimensUnitByDp()) {
418 | return getRealPixelSizeByDp(pix, screen, design);
419 | } else {
420 | return getRealPixelSizeByPix(pix, screen, design);
421 | }
422 | }
423 |
424 | private int getRealPixelSizeByPix(int pix, int screen, int design) {
425 | int result;
426 |
427 | int res = pix * screen;
428 |
429 | if (res % design == 0) {
430 | result = res / design;
431 | } else {
432 | result = res / design + 1;
433 | }
434 |
435 | if (ScaleConfig.getInstance().isDebug())
436 | Log.i(TAG, "pix:" + pix + ",result:" + result);
437 | return result;
438 | }
439 |
440 | private int getRealPixelSizeByDp(int pix, int screen, int design) {
441 | float density = ScaleConfig.getInstance().getScreenDensity();
442 | float designDensity = ScaleConfig.getInstance().getDesignDensity();
443 |
444 | int designDp = convertPix2Dp(density, pix);
445 | int designPix = convertDp2Pix(designDensity, designDp);
446 |
447 | int result;
448 |
449 | int res = designPix * screen;
450 |
451 | if (res % design == 0) {
452 | result = res / design;
453 | } else {
454 | result = res / design + 1;
455 | }
456 |
457 | if (ScaleConfig.getInstance().isDebug())
458 | Log.i(TAG, "pix:" + pix + ",dp:" + designDp + ",result:" + result);
459 | return result;
460 | }
461 |
462 | private int getRealPixelSizeBySP(int pix, int screen, int design) {
463 | float density = ScaleConfig.getInstance().getScreenFontScale();
464 | float designDensity = ScaleConfig.getInstance().getDesignFontScale();
465 |
466 | int designDp = convertPix2Sp(density, pix);
467 | int designPix = convertSp2Pix(designDensity, designDp);
468 |
469 | int result;
470 |
471 | int res = designPix * screen;
472 |
473 | if (res % design == 0) {
474 | result = res / design;
475 | } else {
476 | result = res / design + 1;
477 | }
478 |
479 | if (ScaleConfig.getInstance().isDebug())
480 | Log.i(TAG, "pix:" + pix + ",sp:" + designDp + ",result:" + result);
481 | return result;
482 | }
483 |
484 | private static int convertPix2Dp(float density, int px) {
485 | return (int) (px / density + 0.5f);
486 | }
487 |
488 | private static int convertDp2Pix(float density, int dip) {
489 | return (int) (dip * density + 0.5f);
490 | }
491 |
492 | private static int convertPix2Sp(float fontScale, float pxValue) {
493 | return (int) (pxValue / fontScale + 0.5f);
494 | }
495 |
496 | private static int convertSp2Pix(float fontScale, float spValue) {
497 | return (int) (spValue * fontScale + 0.5f);
498 | }
499 | }
500 |
501 | }
502 |
--------------------------------------------------------------------------------
/ScaleLayout/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/ScaleLayout/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ScaleLayout
3 |
4 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.2'
9 |
10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
11 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.2'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | jcenter()
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
27 |
--------------------------------------------------------------------------------
/screenhot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavinliu/Android-ScaleLayout/a62b7c269ac808322d0aebca3be6a76db0c81a43/screenhot.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':Sample', ':ScaleLayout'
2 |
--------------------------------------------------------------------------------