Repository: gavinliu/Android-ScaleLayout
Branch: master
Commit: a62b7c269ac8
Files: 35
Total size: 53.5 KB
Directory structure:
gitextract_w1ffappy/
├── .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
│ ├── values/
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── values-w820dp/
│ └── dimens.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
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
#Android generated
bin
gen
gen*
#Eclipse
.project
.classpath
.settings
#IntelliJ IDEA
.idea
*.iml
*.ipr
*.iws
out
#Maven
target
release.properties
pom.xml.*
#Ant
build.xml
local.properties
proguard.cfg
#Gradle
.gradle
build
#OSX
.DS_Store
#Personal Files
signing.
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
gradle.properties
gradle/
gradlew
gradlew.bat
================================================
FILE: README.md
================================================
# Android-ScaleLayout
A Simple & Convenience MultiScreen-Support-Library for Android
## The essence is percent scaling.
### different from ``android-percent-support-lib``
1. **More reliable**
``android-percent-support-lib`` The percentage of the parent and child views.
``Android-ScaleLayout`` The percentage of the design and devices screens.
2. **More convenience**
``android-percent-support-lib`` need to calculate percent.
``Android-ScaleLayout`` directly write the design size on ``layout.xml``.
## How to look?

## Principle
```java
float realPixel = percent * designPixel
```
### Pix Mode
```java
float realPixel = percent * designPixel
float percent = mScreenWidth / designScreenWidth
float designPixel = res.getDimensionPixelSize()
```
```java
float realPixel = mScreenWidth * res.getDimensionPixelSize() / designScreenWidth
```
### DP Mode
```java
float realPixel = percent * designPixel
float percent = mScreenWidth / designScreenWidth
float designPixel = designDP * designDensity // dp to pixel
float designDP = res.getDimensionPixelSize() / mDensity
```
```java
float realPixel = (mScreenWidth * designDensity * getPixelSize()) / (designScreenWidth * mDensity)
```
## Usage
### 0. dependencies
```
dependencies {
compile 'cn.gavinliu.android.lib:ScaleLayout:1.0.4'
}
```
### 1. Initialize
```java
public class MyApplication extends Application {
@Override
public void onCreate() {
ScaleConfig.create(this,
1080, // Design Width
1920, // Design Height
3, // Design Density
3, // Design FontScale
ScaleConfig.DIMENS_UNIT_DP);
}
}
```
> ``TypedValue.COMPLEX_UNIT_SP`` is Android FontSize unit, the ``fontscale``:
> float fontScale = ctx.getResources().getDisplayMetrics().scaledDensity;
### 2. Scale***Layout
Only need to replace ``FrameLayout`` ``LinearLayout`` ``RelativeLayout`` to ``ScaleFrameLayout`` ``ScaleLinearLayout`` ``ScaleRelativeLayout``.
### 3. Scale by width or height
Width is default, you can also changed using attr.
```xml
```
```xml
app:layout_scale_by="width"
```
### Support Attrs
```xml
```
## License
MIT
================================================
FILE: README_zh.md
================================================
# Android-ScaleLayout
一个简单的,方便的多屏适配的Android库
## 本质就是百分比缩放
### 和 android-percent-support-lib 的不同
1. **更科学**
``android-percent-support-lib`` 是父控件和子控件的百分比关系
``Android-ScaleLayout`` 是设计界面和设备界面的百分比关系
2. **更方便**
``android-percent-support-lib`` 需要把设计尺寸算成百分比
``Android-ScaleLayout`` 直接把设计尺寸填入``layou.xml``即可
## How to look?

## 原理
```java
float realPixel = percent * designPixel
```
### Pix Mode
```java
float realPixel = percent * designPixel
float percent = mScreenWidth / designScreenWidth
float designPixel = res.getDimensionPixelSize()
```
```java
float realPixel = mScreenWidth * res.getDimensionPixelSize() / designScreenWidth
```
### DP Mode
```java
float realPixel = percent * designPixel
float percent = mScreenWidth / designScreenWidth
float designPixel = designDP * designDensity // dp to pixel
float designDP = res.getDimensionPixelSize() / mDensity
```
```java
float realPixel = (mScreenWidth * designDensity * getPixelSize()) / (designScreenWidth * mDensity)
```
## 使用
### 0. 依赖
```
dependencies {
compile 'cn.gavinliu.android.lib:ScaleLayout:1.0.4'
}
```
### 1. 初始化
```java
public class MyApplication extends Application {
@Override
public void onCreate() {
ScaleConfig.create(this,
1080, // Design Width
1920, // Design Height
3, // Design Density
3, // Design FontScale
ScaleConfig.DIMENS_UNIT_DP);
}
}
```
> Android 文字大小的单位是 ``sp``,字体的缩放方式需要 FontScale:
> float fontScale = ctx.getResources().getDisplayMetrics().scaledDensity;
### 2. Scale***Layout
只需要把 ``FrameLayout`` ``LinearLayout`` ``RelativeLayout`` 替换成 ``ScaleFrameLayout`` ``ScaleLinearLayout`` ``ScaleRelativeLayout``.
### 3. Scale by width or height
默认是 width,当然你可以用属性修改。
```xml
```
```xml
app:layout_scale_by="width"
```
### 支持的属性
```xml
```
## License
MIT
================================================
FILE: Sample/.gitignore
================================================
/build
================================================
FILE: Sample/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "cn.gavinliu.android_scalelayout"
minSdkVersion 9
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles 'proguard-rules.pro'
}
}
}
dependencies {
// compile project(':ScaleLayout')
compile 'cn.gavinliu.android.lib:ScaleLayout:1.0.4'
compile 'com.android.support:appcompat-v7:24.2.0'
}
================================================
FILE: Sample/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/gavin/Develop/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: Sample/src/androidTest/java/cn/gavinliu/android_scalelayout/ApplicationTest.java
================================================
package cn.gavinliu.android_scalelayout;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* Testing Fundamentals
*/
public class ApplicationTest extends ApplicationTestCase {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: Sample/src/main/AndroidManifest.xml
================================================
================================================
FILE: Sample/src/main/java/cn/gavinliu/android_scalelayout/DemoActivity.java
================================================
package cn.gavinliu.android_scalelayout;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
/**
* Created by Gavin on 2016/11/20.
*/
public class DemoActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
}
}
================================================
FILE: Sample/src/main/java/cn/gavinliu/android_scalelayout/DemoListActivity.java
================================================
package cn.gavinliu.android_scalelayout;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
/**
* Created by Gavin on 2016/11/20.
*/
public class DemoListActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo_list);
ListView listView = (ListView) findViewById(R.id.list);
listView.setAdapter(new Adapter(getApplicationContext()));
}
@NonNull
@Override
public LayoutInflater getLayoutInflater() {
return super.getLayoutInflater();
}
private static class Adapter extends BaseAdapter {
private Context ctx;
private Adapter(Context ctx) {
this.ctx = ctx;
}
@Override
public int getCount() {
return 20;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(ctx).inflate(R.layout.item_demo_list, parent, false);
}
return convertView;
}
}
}
================================================
FILE: Sample/src/main/java/cn/gavinliu/android_scalelayout/MainActivity.java
================================================
package cn.gavinliu.android_scalelayout;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void demo(View view) {
Intent intent = new Intent(this, DemoActivity.class);
startActivity(intent);
}
public void demoList(View view) {
Intent intent = new Intent(this, DemoListActivity.class);
startActivity(intent);
}
}
================================================
FILE: Sample/src/main/java/cn/gavinliu/android_scalelayout/MainApplication.java
================================================
package cn.gavinliu.android_scalelayout;
import android.app.Application;
import cn.gavinliu.android.lib.scale.config.ScaleConfig;
/**
* Created by Gavin on 16-11-10.
*/
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ScaleConfig.create(this,
1080, // Design Width
1920, // Design Height
3, // Design Density
3, // Design FontScale
ScaleConfig.DIMENS_UNIT_DP);
ScaleConfig.getInstance().setDebug(true);
}
}
================================================
FILE: Sample/src/main/res/layout/activity_demo.xml
================================================
================================================
FILE: Sample/src/main/res/layout/activity_demo_list.xml
================================================
================================================
FILE: Sample/src/main/res/layout/activity_main.xml
================================================
================================================
FILE: Sample/src/main/res/layout/item_demo_list.xml
================================================
================================================
FILE: Sample/src/main/res/menu/menu_main.xml
================================================
================================================
FILE: Sample/src/main/res/values/dimens.xml
================================================
================================================
FILE: Sample/src/main/res/values/strings.xml
================================================
Android-ScaleLayout
Hello world!
Settings
================================================
FILE: Sample/src/main/res/values/styles.xml
================================================
================================================
FILE: Sample/src/main/res/values-w820dp/dimens.xml
================================================
64dp
================================================
FILE: ScaleLayout/.gitignore
================================================
/build
================================================
FILE: ScaleLayout/build.gradle
================================================
apply plugin: 'com.android.library'
android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
minSdkVersion 9
targetSdkVersion 24
versionCode 5
versionName "1.0.4"
}
buildTypes {
release {
minifyEnabled false
proguardFiles 'proguard-rules.pro'
}
}
}
dependencies {
compile 'com.android.support:support-v4:24.2.0'
}
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
def siteUrl = 'https://github.com/gavinliu/Android-ScaleLayout' // 项目的主页
def gitUrl = 'https://github.com/gavinliu/Android-ScaleLayout.git' // Git仓库的url
version = "1.0.4"
group = "cn.gavinliu.android.lib"
install {
repositories.mavenInstaller {
pom {
project {
packaging 'aar'
//添加项目描述
name 'ScaleLayout: A MultiScreen-Support-Library for Android'
url siteUrl
//设置开源证书信息
licenses {
license {
name 'The MIT License (MIT)'
url 'http://mit-license.org/'
}
}
//添加开发者信息
developers {
developer {
id 'gavin6liu'
name 'Gavin.Liu'
email 'gavin6liu@gmail.com'
}
}
scm {
connection gitUrl
developerConnection gitUrl
url siteUrl
}
}
}
}
}
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives javadocJar
archives sourcesJar
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
bintray {
user = properties.getProperty("bintray.user")
key = properties.getProperty("bintray.apikey")
configurations = ['archives']
pkg {
repo = "maven"//上传的中央仓库名称
name = "ScaleLayout"//上传的项目的名字
websiteUrl = siteUrl
vcsUrl = gitUrl
licenses = ["MIT"]
publish = true //是否发布
}
}
================================================
FILE: ScaleLayout/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/gavin/Develop/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: ScaleLayout/src/androidTest/java/cn/gavinliu/android/lib/scale/ApplicationTest.java
================================================
package cn.gavinliu.android.lib.scale;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* Testing Fundamentals
*/
public class ApplicationTest extends ApplicationTestCase {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: ScaleLayout/src/main/AndroidManifest.xml
================================================
================================================
FILE: ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/ScaleFrameLayout.java
================================================
package cn.gavinliu.android.lib.scale;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import cn.gavinliu.android.lib.scale.helper.ScaleLayoutHelper;
/**
* Created by GavinLiu on 2015-08-10
*/
public class ScaleFrameLayout extends FrameLayout {
private ScaleLayoutHelper mHelper;
public ScaleFrameLayout(Context context) {
this(context, null);
}
public ScaleFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScaleFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (!isInEditMode()) {
mHelper = ScaleLayoutHelper.create(this, attrs);
}
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(this.getContext(), attrs, isInEditMode());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!isInEditMode()) {
this.mHelper.adjustHost(widthMeasureSpec, heightMeasureSpec);
this.mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// if (this.mHelper.handleMeasuredStateTooSmall()) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// }
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// this.mHelper.restoreOriginalParams();
}
public static class LayoutParams extends FrameLayout.LayoutParams implements ScaleLayoutHelper.ScaleLayoutParams {
private ScaleLayoutHelper.ScaleLayoutInfo mPercentLayoutInfo;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
}
private LayoutParams(Context c, AttributeSet attrs, boolean isInEditMode) {
super(c, attrs);
if (!isInEditMode) {
this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
}
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(android.view.ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
@Override
public ScaleLayoutHelper.ScaleLayoutInfo getScaleLayoutInfo() {
return this.mPercentLayoutInfo;
}
@Override
protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
ScaleLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
}
@Override
public void setMargins(int left, int top, int right, int bottom) {
super.setMargins(left, top, right, bottom);
if (mPercentLayoutInfo != null) {
mPercentLayoutInfo.setMargins(left, top, right, bottom);
}
}
}
}
================================================
FILE: ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/ScaleLinearLayout.java
================================================
package cn.gavinliu.android.lib.scale;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import cn.gavinliu.android.lib.scale.helper.ScaleLayoutHelper;
/**
* Created by Gavin on 16-9-20.
*/
public class ScaleLinearLayout extends LinearLayout {
private ScaleLayoutHelper mHelper;
public ScaleLinearLayout(Context context) {
this(context, null);
}
public ScaleLinearLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public ScaleLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (!isInEditMode()) {
mHelper = ScaleLayoutHelper.create(this, attrs);
}
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(this.getContext(), attrs, isInEditMode());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!isInEditMode()) {
this.mHelper.adjustHost(widthMeasureSpec, heightMeasureSpec);
this.mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// if (this.mHelper.handleMeasuredStateTooSmall()) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// }
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// this.mHelper.restoreOriginalParams();
}
public static class LayoutParams extends LinearLayout.LayoutParams implements ScaleLayoutHelper.ScaleLayoutParams {
private ScaleLayoutHelper.ScaleLayoutInfo mPercentLayoutInfo;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
}
private LayoutParams(Context c, AttributeSet attrs, boolean isInEditMode) {
super(c, attrs);
if (!isInEditMode) {
this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
}
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(android.view.ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
@Override
public ScaleLayoutHelper.ScaleLayoutInfo getScaleLayoutInfo() {
return this.mPercentLayoutInfo;
}
@Override
protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
ScaleLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
}
@Override
public void setMargins(int left, int top, int right, int bottom) {
super.setMargins(left, top, right, bottom);
if (mPercentLayoutInfo != null) {
mPercentLayoutInfo.setMargins(left, top, right, bottom);
}
}
}
}
================================================
FILE: ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/ScaleRelativeLayout.java
================================================
package cn.gavinliu.android.lib.scale;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import cn.gavinliu.android.lib.scale.helper.ScaleLayoutHelper;
/**
* Created by GavinLiu on 2015-08-10
*/
public class ScaleRelativeLayout extends RelativeLayout {
private ScaleLayoutHelper mHelper;
public ScaleRelativeLayout(Context context) {
this(context, null);
}
public ScaleRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScaleRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (!isInEditMode()) {
mHelper = ScaleLayoutHelper.create(this, attrs);
}
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(this.getContext(), attrs, isInEditMode());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!isInEditMode()) {
this.mHelper.adjustHost(widthMeasureSpec, heightMeasureSpec);
this.mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// if (this.mHelper.handleMeasuredStateTooSmall()) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// }
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// this.mHelper.restoreOriginalParams();
}
public static class LayoutParams extends android.widget.RelativeLayout.LayoutParams implements ScaleLayoutHelper.ScaleLayoutParams {
private ScaleLayoutHelper.ScaleLayoutInfo mPercentLayoutInfo;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
}
private LayoutParams(Context c, AttributeSet attrs, boolean isInEditMode) {
super(c, attrs);
if (!isInEditMode) {
this.mPercentLayoutInfo = ScaleLayoutHelper.getScaleLayoutInfo(c, attrs);
}
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(android.view.ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
@Override
public ScaleLayoutHelper.ScaleLayoutInfo getScaleLayoutInfo() {
return this.mPercentLayoutInfo;
}
@Override
protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
ScaleLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
}
@Override
public void setMargins(int left, int top, int right, int bottom) {
super.setMargins(left, top, right, bottom);
if (mPercentLayoutInfo != null) {
mPercentLayoutInfo.setMargins(left, top, right, bottom);
}
}
}
}
================================================
FILE: ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/config/ScaleConfig.java
================================================
package cn.gavinliu.android.lib.scale.config;
import android.content.Context;
/**
* Created by Gavin on 16-9-20.
*/
public class ScaleConfig {
private int mDesignWidth;
private int mDesignHeight;
private float mDesignDensity;
private int mScreenWidth;
private int mScreenHeight;
private float mScreenDensity;
private float mDesignFontScale;
private float mScreenFontScale;
private int mDimensionUnit;
public static final int DIMENS_UNIT_DP = 0;
public static final int DIMENS_UNIT_PIX = 1;
private boolean mDebug;
private static ScaleConfig mInstance;
/**
* @param ctx Context
* @param designWidth Design Width (Pixel)
* @param designHeight Design Height (Pixel)
* @param designDensity Design Density
* @param designFontScale Design FontScale (getDisplayMetrics().scaledDensity)
* @param dimensionUnit DIMENS_UNIT_DP or DIMENS_UNIT_PIX
* @return Single instance
*/
public static ScaleConfig create(Context ctx, int designWidth, int designHeight, float designDensity, float designFontScale, int dimensionUnit) {
if (mInstance == null) {
mInstance = new ScaleConfig(ctx, designWidth, designHeight, designDensity, designFontScale, dimensionUnit);
}
return mInstance;
}
public static ScaleConfig getInstance() {
if (mInstance == null)
throw new IllegalArgumentException("You must call ScaleConfig.create first");
return mInstance;
}
private ScaleConfig(Context ctx) {
final int width = ctx.getResources().getDisplayMetrics().widthPixels;
final int height = ctx.getResources().getDisplayMetrics().heightPixels;
final float density = ctx.getResources().getDisplayMetrics().density;
final float fontScale = ctx.getResources().getDisplayMetrics().scaledDensity;
mScreenWidth = width;
mScreenHeight = height;
mScreenDensity = density;
mScreenFontScale = fontScale;
}
private ScaleConfig(Context ctx, int designWidth, int designHeight, float designDensity, float designFontScale, int dimensionUnit) {
this(ctx);
mDesignWidth = designWidth;
mDesignHeight = designHeight;
mDesignDensity = designDensity;
mDesignFontScale = designFontScale;
mDimensionUnit = dimensionUnit;
}
public boolean isDebug() {
return mDebug;
}
public void setDebug(boolean debug) {
mDebug = debug;
}
public boolean isDimensUnitByDp() {
return mDimensionUnit == DIMENS_UNIT_DP;
}
public int getDesignWidth() {
return mDesignWidth;
}
public int getDesignHeight() {
return mDesignHeight;
}
public float getDesignDensity() {
return mDesignDensity;
}
public float getScreenDensity() {
return mScreenDensity;
}
public float getDesignFontScale() {
return mDesignFontScale;
}
public float getScreenFontScale() {
return mScreenFontScale;
}
public int getScreenWidth() {
return mScreenWidth;
}
public int getScreenHeight() {
return mScreenHeight;
}
}
================================================
FILE: ScaleLayout/src/main/java/cn/gavinliu/android/lib/scale/helper/ScaleLayoutHelper.java
================================================
package cn.gavinliu.android.lib.scale.helper;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.MarginLayoutParamsCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import cn.gavinliu.android.lib.scale.R;
import cn.gavinliu.android.lib.scale.config.ScaleConfig;
/**
* Created by GavinLiu on 2015-08-10
*/
public class ScaleLayoutHelper {
private static final String TAG = "ScaleLayoutHelper";
private final ViewGroup mHost;
private final ScaleLayoutInfo mHostLayoutInfo;
public interface ScaleLayoutParams {
ScaleLayoutInfo getScaleLayoutInfo();
}
public ScaleLayoutHelper(ViewGroup host, ScaleLayoutInfo layoutInfo) {
this.mHost = host;
this.mHostLayoutInfo = layoutInfo;
}
public static ScaleLayoutHelper create(ViewGroup view, AttributeSet attrs) {
return new ScaleLayoutHelper(view, getScaleLayoutInfo(view.getContext(), attrs));
}
public void adjustChildren(int widthMeasureSpec, int heightMeasureSpec) {
int i = 0;
for (int N = this.mHost.getChildCount(); i < N; ++i) {
View view = this.mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params instanceof ScaleLayoutParams) {
ScaleLayoutInfo info = ((ScaleLayoutParams) params).getScaleLayoutInfo();
if (ScaleConfig.getInstance().isDebug()) {
Log.d(TAG, "adjustChildren using " + info + " " + view);
}
if (info != null && mHostLayoutInfo != null) {
if (params instanceof ViewGroup.MarginLayoutParams) {
info.fillMarginLayoutParams(view, (ViewGroup.MarginLayoutParams) params);
} else {
info.fillLayoutParams(view, params);
}
info.fillView(view);
}
}
}
}
public void adjustHost(int widthMeasureSpec, int heightMeasureSpec) {
if (mHostLayoutInfo != null) {
ViewGroup.LayoutParams params = mHost.getLayoutParams();
if (params instanceof ViewGroup.MarginLayoutParams) {
mHostLayoutInfo.fillMarginLayoutParams(mHost, (ViewGroup.MarginLayoutParams) params);
} else {
mHostLayoutInfo.fillLayoutParams(mHost, params);
}
}
}
public void restoreOriginalParams() {
int i = 0;
for (int N = this.mHost.getChildCount(); i < N; ++i) {
View view = this.mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params instanceof ScaleLayoutParams) {
ScaleLayoutInfo info = ((ScaleLayoutParams) params).getScaleLayoutInfo();
if (ScaleConfig.getInstance().isDebug()) {
Log.d(TAG, "restoreOriginalParams using " + info);
}
if (info != null) {
if (params instanceof ViewGroup.MarginLayoutParams) {
info.restoreMarginLayoutParams((ViewGroup.MarginLayoutParams) params);
} else {
info.restoreLayoutParams(params);
}
}
}
}
}
public static void fetchWidthAndHeight(ViewGroup.LayoutParams params, TypedArray array, int widthAttr, int heightAttr) {
params.width = array.getLayoutDimension(widthAttr, 0);
params.height = array.getLayoutDimension(heightAttr, 0);
}
public static ScaleLayoutInfo getScaleLayoutInfo(Context context, AttributeSet attrs) {
ScaleLayoutInfo info = new ScaleLayoutInfo(context);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ScaleLayout);
int value = array.getInt(R.styleable.ScaleLayout_layout_scale_by, 0);
if (value != 0) {
info.scaleBy = value;
}
try {
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_width, 0);
if (value != 0) {
info.width = value;
}
} catch (Exception e) {
}
try {
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_height, 0);
if (value != 0) {
info.height = value;
}
} catch (Exception e) {
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_margin, 0);
if (value != 0) {
info.leftMargin = value;
info.topMargin = value;
info.rightMargin = value;
info.bottomMargin = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginLeft, 0);
if (value != 0) {
info.leftMargin = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginTop, 0);
if (value != 0) {
info.topMargin = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginRight, 0);
if (value != 0) {
info.rightMargin = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginBottom, 0);
if (value != 0) {
info.bottomMargin = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginStart, 0);
if (value != 0) {
info.startMargin = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_layout_marginEnd, 0);
if (value != 0) {
info.endMargin = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_padding, 0);
if (value != 0) {
info.leftPadding = value;
info.topPadding = value;
info.rightPadding = value;
info.bottomPadding = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_paddingLeft, 0);
if (value != 0) {
info.leftPadding = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_paddingTop, 0);
if (value != 0) {
info.topPadding = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_paddingRight, 0);
if (value != 0) {
info.rightPadding = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_paddingBottom, 0);
if (value != 0) {
info.bottomPadding = value;
}
value = array.getDimensionPixelSize(R.styleable.ScaleLayout_android_textSize, 0);
if (value != 0) {
info.textSize = value;
}
array.recycle();
if (ScaleConfig.getInstance().isDebug()) {
Log.d(TAG, "constructed: " + info);
}
return info;
}
public boolean handleMeasuredStateTooSmall() {
boolean needsSecondMeasure = false;
int i = 0;
for (int N = this.mHost.getChildCount(); i < N; ++i) {
View view = this.mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params instanceof ScaleLayoutParams) {
ScaleLayoutInfo info = ((ScaleLayoutParams) params).getScaleLayoutInfo();
if (info != null) {
if (shouldHandleMeasuredWidthTooSmall(view, info)) {
needsSecondMeasure = true;
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
if (shouldHandleMeasuredHeightTooSmall(view, info)) {
needsSecondMeasure = true;
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
}
}
}
}
if (ScaleConfig.getInstance().isDebug()) {
Log.d(TAG, "should trigger second measure pass: " + needsSecondMeasure);
}
return needsSecondMeasure;
}
private static boolean shouldHandleMeasuredWidthTooSmall(View view, ScaleLayoutInfo info) {
int state = ViewCompat.getMeasuredWidthAndState(view) & ViewCompat.MEASURED_STATE_MASK;
return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.width >= 0.0F && info.mPreservedParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
}
private static boolean shouldHandleMeasuredHeightTooSmall(View view, ScaleLayoutInfo info) {
int state = ViewCompat.getMeasuredHeightAndState(view) & ViewCompat.MEASURED_STATE_MASK;
return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.height >= 0.0F && info.mPreservedParams.height == ViewGroup.LayoutParams.WRAP_CONTENT;
}
public static class ScaleLayoutInfo {
private int designWidth;
private int designHeight;
private int screenW;
private int screenH;
public int width = 0;
public int height = 0;
private int scaleBy = ScaleByWidth;
private static final int ScaleByWidth = 0;
private static final int ScaleByHeight = 1;
private int leftMargin;
private int topMargin;
private int rightMargin;
private int bottomMargin;
private int startMargin;
private int endMargin;
private int leftPadding;
private int topPadding;
private int rightPadding;
private int bottomPadding;
private int textSize;
final ViewGroup.MarginLayoutParams mPreservedParams = new ViewGroup.MarginLayoutParams(0, 0);
public ScaleLayoutInfo(Context ctx) {
designWidth = ScaleConfig.getInstance().getDesignWidth();
designHeight = ScaleConfig.getInstance().getDesignHeight();
screenW = ctx.getResources().getDisplayMetrics().widthPixels;
screenH = ctx.getResources().getDisplayMetrics().heightPixels;
}
public void fillLayoutParams(View view, ViewGroup.LayoutParams params) {
this.mPreservedParams.width = params.width;
this.mPreservedParams.height = params.height;
if (this.width > 0.0) {
params.width = getRealPixelSize(this.width);
}
if (this.height > 0.0) {
params.height = getRealPixelSize(this.height);
}
int paddingL = 0, paddingT = 0, paddingR = 0, paddingB = 0;
if (this.leftPadding > 0.0) {
paddingL = getRealPixelSize(this.leftPadding);
}
if (this.topPadding > 0.0) {
paddingT = getRealPixelSize(this.topPadding);
}
if (this.rightPadding > 0.0) {
paddingR = getRealPixelSize(this.rightPadding);
}
if (this.bottomPadding > 0.0) {
paddingB = getRealPixelSize(this.bottomPadding);
}
view.setPadding(paddingL, paddingT, paddingR, paddingB);
}
public void fillMarginLayoutParams(View view, ViewGroup.MarginLayoutParams params) {
this.fillLayoutParams(view, params);
this.mPreservedParams.leftMargin = params.leftMargin;
this.mPreservedParams.topMargin = params.topMargin;
this.mPreservedParams.rightMargin = params.rightMargin;
this.mPreservedParams.bottomMargin = params.bottomMargin;
MarginLayoutParamsCompat.setMarginStart(this.mPreservedParams, MarginLayoutParamsCompat.getMarginStart(params));
MarginLayoutParamsCompat.setMarginEnd(this.mPreservedParams, MarginLayoutParamsCompat.getMarginEnd(params));
if (this.leftMargin > 0.0F) {
params.leftMargin = getRealPixelSize(this.leftMargin);
}
if (this.topMargin > 0.0F) {
params.topMargin = getRealPixelSize(this.topMargin);
}
if (this.rightMargin > 0.0F) {
params.rightMargin = getRealPixelSize(this.rightMargin);
}
if (this.bottomMargin > 0.0F) {
params.bottomMargin = getRealPixelSize(this.bottomMargin);
}
if (this.startMargin > 0.0F) {
MarginLayoutParamsCompat.setMarginStart(params, getRealPixelSize(this.startMargin));
}
if (this.endMargin > 0.0F) {
MarginLayoutParamsCompat.setMarginEnd(params, getRealPixelSize(this.endMargin));
}
}
public void fillView(View view) {
if (view instanceof TextView) {
if (this.textSize > 0) {
int newTextSize = getRealFontSize(this.textSize);
((TextView) view).setTextSize(TypedValue.COMPLEX_UNIT_PX, newTextSize);
}
}
}
public void restoreMarginLayoutParams(ViewGroup.MarginLayoutParams params) {
this.restoreLayoutParams(params);
params.leftMargin = this.mPreservedParams.leftMargin;
params.topMargin = this.mPreservedParams.topMargin;
params.rightMargin = this.mPreservedParams.rightMargin;
params.bottomMargin = this.mPreservedParams.bottomMargin;
MarginLayoutParamsCompat.setMarginStart(params, MarginLayoutParamsCompat.getMarginStart(this.mPreservedParams));
MarginLayoutParamsCompat.setMarginEnd(params, MarginLayoutParamsCompat.getMarginEnd(this.mPreservedParams));
}
public void restoreLayoutParams(ViewGroup.LayoutParams params) {
params.width = this.mPreservedParams.width;
params.height = this.mPreservedParams.height;
}
public void setMargins(int left, int top, int right, int bottom) {
leftPadding = left;
topPadding = top;
rightPadding = right;
bottomPadding = bottom;
}
private int getRealFontSize(int pix) {
int screen, design;
switch (scaleBy) {
case ScaleByHeight:
screen = screenH;
design = designHeight;
break;
default:
screen = screenW;
design = designWidth;
break;
}
return getRealPixelSizeBySP(pix, screen, design);
}
private int getRealPixelSize(int pix) {
int screen, design;
switch (scaleBy) {
case ScaleByHeight:
screen = screenH;
design = designHeight;
break;
default:
screen = screenW;
design = designWidth;
break;
}
if (ScaleConfig.getInstance().isDimensUnitByDp()) {
return getRealPixelSizeByDp(pix, screen, design);
} else {
return getRealPixelSizeByPix(pix, screen, design);
}
}
private int getRealPixelSizeByPix(int pix, int screen, int design) {
int result;
int res = pix * screen;
if (res % design == 0) {
result = res / design;
} else {
result = res / design + 1;
}
if (ScaleConfig.getInstance().isDebug())
Log.i(TAG, "pix:" + pix + ",result:" + result);
return result;
}
private int getRealPixelSizeByDp(int pix, int screen, int design) {
float density = ScaleConfig.getInstance().getScreenDensity();
float designDensity = ScaleConfig.getInstance().getDesignDensity();
int designDp = convertPix2Dp(density, pix);
int designPix = convertDp2Pix(designDensity, designDp);
int result;
int res = designPix * screen;
if (res % design == 0) {
result = res / design;
} else {
result = res / design + 1;
}
if (ScaleConfig.getInstance().isDebug())
Log.i(TAG, "pix:" + pix + ",dp:" + designDp + ",result:" + result);
return result;
}
private int getRealPixelSizeBySP(int pix, int screen, int design) {
float density = ScaleConfig.getInstance().getScreenFontScale();
float designDensity = ScaleConfig.getInstance().getDesignFontScale();
int designDp = convertPix2Sp(density, pix);
int designPix = convertSp2Pix(designDensity, designDp);
int result;
int res = designPix * screen;
if (res % design == 0) {
result = res / design;
} else {
result = res / design + 1;
}
if (ScaleConfig.getInstance().isDebug())
Log.i(TAG, "pix:" + pix + ",sp:" + designDp + ",result:" + result);
return result;
}
private static int convertPix2Dp(float density, int px) {
return (int) (px / density + 0.5f);
}
private static int convertDp2Pix(float density, int dip) {
return (int) (dip * density + 0.5f);
}
private static int convertPix2Sp(float fontScale, float pxValue) {
return (int) (pxValue / fontScale + 0.5f);
}
private static int convertSp2Pix(float fontScale, float spValue) {
return (int) (spValue * fontScale + 0.5f);
}
}
}
================================================
FILE: ScaleLayout/src/main/res/values/attrs.xml
================================================
================================================
FILE: ScaleLayout/src/main/res/values/strings.xml
================================================
ScaleLayout
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: settings.gradle
================================================
include ':Sample', ':ScaleLayout'