前言:从开始接触rn到现在终于能写出点东西了,的确得为自己好好地点个赞 ,不管咋样,学习还是得继续啊,废话少说了,在rn中我们也需要对屏幕进行适配,但是rn中的适配貌似比Android原生容易很多(不得佩服facebook那些大神哈,对android原生控件封装的太屌!)。
http://blog.csdn.net/vv_bug/article/details/54958200
我们先看看rn中的屏幕适配(作为一个android程序员去做rn确实比iOS程序员考虑的东西多一点点哈,嘻嘻~~):
结合android的一些适配经验,我在rn中也封装了一个工具类
ScreenUtils.js:
/**
* 屏幕工具类
* ui设计基准,iphone 6
* width:750
* height:1334
*/
var ReactNative = require('react-native');
var Dimensions = require('Dimensions');
export var screenW = Dimensions.get('window').width;
export var screenH = Dimensions.get('window').height;
var fontScale = ReactNative.PixelRatio.getFontScale();
export var pixelRatio = ReactNative.PixelRatio.get();
const r2=2;
const w2 = 750/r2;``
const h2 = 1334/r2;
/**
* 设置text为sp
* @param size sp
* @returns {Number} dp
*/
export const DEFAULT_DENSITY=2;
export function setSpText(size:Number) {
var scaleWidth = screenW / w2;
var scaleHeight = screenH / h2;
var scale = Math.min(scaleWidth, scaleHeight);
size = Math.round((size * scale + 0.5) * pixelRatio / fontScale);
return size;
}
/**
* 屏幕适配,缩放size
* @param size
* @returns {Number}
* @constructor
*/
export function scaleSize(size:Number) {
var scaleWidth = screenW / w2;
var scaleHeight = screenH / h2;
var scale = Math.min(scaleWidth, scaleHeight);
size = Math.round((size * scale + 0.5));
return size/DEFAULT_DENSITY;
}
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
搞过rn的童鞋知道,rn中直接写宽高都是dp的,所以我们要以一个美工设计的ui基准来计算我们的宽高,数学不好哈,不过大概是这样的:
我们先定义好ui的设计基准:
/**
* 屏幕工具类
* ui设计基准,iphone 6
* width:750
* height:1334
*/
var ReactNative = require('react-native');
var Dimensions = require('Dimensions');
export var screenW = Dimensions.get('window').width;
export var screenH = Dimensions.get('window').height;
var fontScale = ReactNative.PixelRatio.getFontScale();
export var pixelRatio = ReactNative.PixelRatio.get();
const r2=2;
const w2 = 750/r2;``
const h2 = 1334/r2;
/**
* 设置text为sp
* @param size sp
* @returns {Number} dp
*/
export const DEFAULT_DENSITY=2;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
然后获取到我们自己手机的屏幕宽高,生成一个百分比,然后算出在iphone6上的100px,在我们手机上是多少px,最后转换成dp设置在在我们布局的style中:
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
justifyContent: 'space-between',
flexDirection: 'row',
paddingTop: ScreenUtils.scaleSize(22),
paddingBottom: ScreenUtils.scaleSize(22),
paddingRight: ScreenUtils.scaleSize(12),
paddingLeft: ScreenUtils.scaleSize(12),
alignItems: 'center'
},
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
好啦~!!,rn上的适配就完啦,是不是soeasy呢???
但是在android原生中,我们写布局大多数都是在xml中写的,所以我们在写布局的时候,压根就不知道我要运行在什么手机上,所以android官方建议我们使用dp啊,然后建很多layout文件啊,很多value文件啊,是的!我个人也是比较推崇官方的做法的,效率高,清晰明了,好啦!!除了android官方说的那种方法,我们是否也可以像rn一样运行后再重新算出百分比,然后再布局呢?答案是肯定的,因为rn就是一个例子,它也是对原生控件封装过的,所以才能用js轻易控制,在此之前鸿洋大神也对百分比布局做了封装,也对齐做了很详细的解析了,先贴上大神的博客链接:
[http://blog.csdn.net/lmj623565791/article/details/46767825](http://blog.csdn.net/lmj623565791/article/details/46767825
好啦!我们今天要做的也就是在百分比布局的基础上简单封装下,然后使得其能够像rn一样,直接写上美工标的px就能完美适配大部分手机了。
先上张运行好的效果图(效果还是很不错的!):
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context="com.example.leo.textdemo.MainActivity">
<com.yasin.px_percent_layout.PercentLinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_widthPercent="10%w"
app:layout_heightPercent="10%h"
android:text="10%w,10%h"
android:background="#ff0000"
android:textColor="#fff"
/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_widthPercent="20%sw"
app:layout_heightPercent="20%sh"
android:text="屏幕宽的20%sw,屏幕高的20%sh"
android:background="#ffff00"
android:textColor="#ff00"
/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_widthPercent="200px"
app:layout_heightPercent="200px"
android:text="iphone6为基准的宽:200px,高:200px"
android:background="#0000ff"
android:textColor="#fff"
/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_widthPercent="375px"
app:layout_heightPercent="375px"
android:text="iphone6为基准的宽:370px,高:370px,textsize为28px"
android:background="#00ff00"
app:layout_textSizePercent="28px"
android:textColor="#ff00"
/>
com.yasin.px_percent_layout.PercentLinearLayout>
RelativeLayout>
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
先走一遍百分比布,看它到底是咋实现适配的(以下是来自鸿洋大神封装过后的代码,我就直接拿走解析了,嘻嘻!!):
PercentLinearLayout.Java:
package com.yasin.px_percent_layout;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.ScrollView;
public class PercentLinearLayout extends LinearLayout {
private static final String TAG = "PercentLinearLayout";
private PercentLayoutHelper mPercentLayoutHelper;
public PercentLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mPercentLayoutHelper = new PercentLayoutHelper(this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int tmpHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int tmpWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
if (heightMode == MeasureSpec.UNSPECIFIED && getParent() != null && (getParent() instanceof ScrollView)) {
int baseHeight = 0;
Context context = getContext();
if (context instanceof Activity) {
Activity act = (Activity) context;
int measuredHeight = act.findViewById(android.R.id.content).getMeasuredHeight();
baseHeight = measuredHeight;
} else {
baseHeight = getScreenHeight();
}
tmpHeightMeasureSpec = MeasureSpec.makeMeasureSpec(baseHeight, heightMode);
}
mPercentLayoutHelper.adjustChildren(tmpWidthMeasureSpec, tmpHeightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mPercentLayoutHelper.handleMeasuredStateTooSmall()) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
private int getScreenHeight() {
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mPercentLayoutHelper.restoreOriginalParams();
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
public static class LayoutParams extends LinearLayout.LayoutParams
implements PercentLayoutHelper.PercentLayoutParams {
private PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
}
@Override
public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo() {
return mPercentLayoutInfo;
}
@Override
protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
PercentLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
}
}
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
代码不要太简单哈,就在构造方法中创建了一个mPercentLayoutHelper:
public PercentLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mPercentLayoutHelper = new PercentLayoutHelper(this);
}
我们待会再来说这个PercentLayoutHelper,
然后就是创建了一个自己的LayoutParams:
public static class LayoutParams extends LinearLayout.LayoutParams
implements PercentLayoutHelper.PercentLayoutParams {
private PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
}
@Override
public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo() {
return mPercentLayoutInfo;
}
@Override
protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
PercentLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
}
- 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
- 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
其中也咩有啥代码,创建了一个PercentLayoutInfo。
然后核心代码就是onMeasure方法里面了:
mPercentLayoutHelper.adjustChildren(tmpWidthMeasureSpec, tmpHeightMeasureSpec)
核心也就这一句。
终结下来就是:
1、先获取到我们在布局文件中定义的属性:
app:layout_widthPercent="10%w"
app:layout_heightPercent="10%h"
.......
2、然后把获取到的属性封装进一个叫PercentLayoutInfo的类中:
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
}
3、在onMeasure方法中根据传进的属性对子控件进行重置大小:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int tmpHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int tmpWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
if (heightMode == MeasureSpec.UNSPECIFIED && getParent() != null && (getParent() instanceof ScrollView)) {
int baseHeight = 0;
Context context = getContext();
if (context instanceof Activity) {
Activity act = (Activity) context;
int measuredHeight = act.findViewById(android.R.id.content).getMeasuredHeight();
baseHeight = measuredHeight;
} else {
baseHeight = getScreenHeight();
}
tmpHeightMeasureSpec = MeasureSpec.makeMeasureSpec(baseHeight, heightMode);
}
mPercentLayoutHelper.adjustChildren(tmpWidthMeasureSpec, tmpHeightMeasureSpec);
super.onMeasure(widthMeasureSpec, hei }
}
- 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
- 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
看完是不是觉得很简单呢? 是的,本来就不难哈,我们接着往下看:
先看看它是咋拿到我们在布局文件中写的属性的(怎么封装):
public static PercentLayoutInfo getPercentLayoutInfo(Context context,
AttributeSet attrs) {
PercentLayoutInfo info = null;
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PercentLayout_Layout);
info = setWidthAndHeightVal(array, info);
info = setMarginRelatedVal(array, info);
info = setTextSizeSupportVal(array, info);
info = setMinMaxWidthHeightRelatedVal(array, info);
info = setPaddingRelatedVal(array, info);
array.recycle();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "constructed: " + info);
}
return info;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
获取TypedArray数组中的数据(我们就只看setWidthAndHeightVal代码了):
private static PercentLayoutInfo setWidthAndHeightVal(TypedArray array, PercentLayoutInfo info) {
PercentLayoutInfo.PercentVal percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_widthPercent, true);
if (percentVal != null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent width: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.widthPercent = percentVal;
}
percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_heightPercent, false);
if (percentVal != null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent height: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.heightPercent = percentVal;
}
return info;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
获取到heightPercent跟widthPercent信息然后赋给info对象,没啥好看的,重点看看咋获取到的widthPercent信息:
private static PercentLayoutInfo.PercentVal getPercentVal(TypedArray array, int index, boolean baseWidth) {
String sizeStr = array.getString(index);
PercentLayoutInfo.PercentVal percentVal = getPercentVal(sizeStr, baseWidth);
return percentVal;
}
也没啥看的(继续往下走):
private static PercentLayoutInfo.PercentVal getPercentVal(String percentStr, boolean isOnWidth) {
//valid param
if (percentStr == null) {
return null
}
Pattern p = Pattern.compile(REGEX_PERCENT)
Matcher matcher = p.matcher(percentStr)
if (TextUtils.isEmpty(percentStr) ||
(!matcher.matches() && !(percentStr.toLowerCase().endsWith("px")))) {
throw new RuntimeException("the value of layout_xxxPercent invalid! ==>" + percentStr)
}
String floatVal
String lastAlpha
float percent
int len = percentStr.length()
if (matcher.matches()) {
//extract the float value
floatVal = matcher.group(1)
lastAlpha = percentStr.substring(len - 1)
percent = Float.parseFloat(floatVal) / 100f
} else {
//extract the float value
floatVal = percentStr.substring(0, percentStr.indexOf("px"))
lastAlpha = percentStr.substring(len - 1)
percent = Float.parseFloat(floatVal)
}
PercentLayoutInfo.PercentVal percentVal = new PercentLayoutInfo.PercentVal()
percentVal.percent = percent
if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.SW)) {
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_SCREEN_WIDTH
} else if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.SH)) {
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_SCREEN_HEIGHT
} else if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.PERCENT)) {
if (isOnWidth) {
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_WIDTH
} else {
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_HEIGHT
}
} else if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.W)) {
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_WIDTH
} else if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.H)) {
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_HEIGHT
} else if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.PX)) {
percentVal.basemode = PercentLayoutInfo.BASEMODE.ABSOLUTE_PX
} else {
throw new IllegalArgumentException("the " + percentStr + " must be endWith [%|w|h|sw|sh]")
}
return percentVal
}
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
好啦,终于看到核心代码了,不做太多解释,相信都看得懂,简单来说就是获取到我们设置的值,然后判断我们设置的值属于哪种类型:
类型有:
private enum BASEMODE {
BASE_WIDTH, BASE_HEIGHT, BASE_SCREEN_WIDTH, BASE_SCREEN_HEIGHT, ABSOLUTE_PX;
/**
* width_parent
*/
public static final String PERCENT = "%";
/**
* width_parent
*/
public static final String W = "w";
/**
* height_parent
*/
public static final String H = "h";
/**
* width_screen
*/
public static final String SW = "sw";
/**
* height_screen
*/
public static final String SH = "sh";
/**
* absolute px
*/
public static final String PX = "px";
}
- 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
- 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
就是我们布局中写的:
app:layout_widthPercent="10%w"
app:layout_heightPercent="10%h"
app:layout_widthPercent="20%sw"
app:layout_heightPercent="20%sh"
app:layout_widthPercent="200px"
app:layout_heightPercent="200px"
小伙伴是不是看懂了呢? 比如20%sw,就是把20跟sw取出来,然后封装进类中。
好啦,我们已经拿到我们在布局中设置的属性了,然后我们就得根据我们设置的值重新赋给子控件了。
在onMeasure中我们找到adjustChildren方法:
public void adjustChildren(int widthMeasureSpec, int heightMeasureSpec) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "adjustChildren: " + mHost + " widthMeasureSpec: "
+ View.MeasureSpec.toString(widthMeasureSpec) + " heightMeasureSpec: "
+ View.MeasureSpec.toString(heightMeasureSpec));
}
int widthHint = View.MeasureSpec.getSize(widthMeasureSpec);
int heightHint = View.MeasureSpec.getSize(heightMeasureSpec);
if (Log.isLoggable(TAG, Log.DEBUG))
Log.d(TAG, "widthHint = " + widthHint + " , heightHint = " + heightHint);
for (int i = 0, N = mHost.getChildCount(); i < N; i++) {
View view = mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "should adjust " + view + " " + params);
}
if (params instanceof PercentLayoutParams) {
PercentLayoutInfo info =
((PercentLayoutParams) params).getPercentLayoutInfo();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "using " + info);
}
if (info != null) {
supportTextSize(widthHint, heightHint, view, info);
supportPadding(widthHint, heightHint, view, info);
supportMinOrMaxDimesion(widthHint, heightHint, view, info);
if (params instanceof ViewGroup.MarginLayoutParams) {
info.fillMarginLayoutParams((ViewGroup.MarginLayoutParams) params,
widthHint, heightHint);
} else {
info.fillLayoutParams(params, widthHint, heightHint);
}
}
}
}
}
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
遍历我们的子控件,然后根据我们上面获取到的info类,进行重新布局:
if (info != null) {
supportTextSize(widthHint, heightHint, view, info);
supportPadding(widthHint, heightHint, view, info);
supportMinOrMaxDimesion(widthHint, heightHint, view, info);
if (params instanceof ViewGroup.MarginLayoutParams) {
info.fillMarginLayoutParams((ViewGroup.MarginLayoutParams) params,
widthHint, heightHint);
} else {
info.fillLayoutParams(params, widthHint, heightHint);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
demo中我们看到了:
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_widthPercent="375px"
app:layout_heightPercent="375px"
android:text="iphone6为基准的宽:370px,高:370px,textsize为28px"
android:background="#00ff00"
app:layout_textSizePercent="28px"
android:textColor="#ff00"
/>
我们有设置一个app:layout_textSizePercent:
看到这我们找到一个方法,没错!也就是这里对textview设置的size大小的:
supportTextSize(widthHint, heightHint, view, info);
我们往下走:
private void supportTextSize(int widthHint, int heightHint, View view, PercentLayoutInfo info) {
PercentLayoutInfo.PercentVal textSizePercent = info.textSizePercent;
if (textSizePercent == null) return;
float textSize;
int base = getBaseByModeAndVal(widthHint, heightHint, textSizePercent.basemode);
if (textSizePercent.basemode == PercentLayoutInfo.BASEMODE.ABSOLUTE_PX) {
textSize = ViewUtils.scaleTextValue(mHost.getContext(), textSizePercent.percent);
} else {
textSize = (int) (base * textSizePercent.percent);
}
if (view instanceof TextView) {
((TextView) view).setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
这里如果我们是直接设置的px的话(如:app:layout_textSizePercent=”28px”),我们就需要根据ui基准,然后算出在我们手机上应该显示多少:
int base = getBaseByModeAndVal(widthHint, heightHint, textSizePercent.basemode)
if (textSizePercent.basemode == PercentLayoutInfo.BASEMODE.ABSOLUTE_PX) {
textSize = ViewUtils.scaleTextValue(mHost.getContext(), textSizePercent.percent)
} else {
textSize = (int) (base * textSizePercent.percent)
}
如果是直接设置的20%w,20%h,20%sh这样的值的话,我们就需要用父布局的宽、高、屏幕宽、高乘一个我们设置进去的百分比进行计算了:
textSize = (int) (base * textSizePercent.percent);
好啦!!!剩下的几个方法也都差不多,我就不一一讲了哈:
if (info != null) {
supportTextSize(widthHint, heightHint, view, info);
supportPadding(widthHint, heightHint, view, info);
supportMinOrMaxDimesion(widthHint, heightHint, view, info);
if (params instanceof ViewGroup.MarginLayoutParams) {
info.fillMarginLayoutParams((ViewGroup.MarginLayoutParams) params,
widthHint, heightHint);
} else {
info.fillLayoutParams(params, widthHint, heightHint);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
嗯嗯~! 我们的百分比跟px布局差不多就讲完啦~, 下面看看咋使用它哈:
如果要直接使用px布局的话(不用px布局可不需要做第一步与第二步):
1、在项目的manifest文件中定义好ui设计的基准(如iphone6):
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.leo.textdemo" >
<application
android:name=".BaseApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
>
<meta-data android:name="UI_WIDTH" android:value="750"/>
<meta-data android:name="UI_HEIGHT" android:value="1334"/>
<meta-data android:name="UI_DENSITY" android:value="2"/>
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
<activity android:name=".SimpleMenuActivtiy">
activity>
application>
manifest>
- 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
- 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
2、在app中的application文件中,初始化布局:
package com.example.leo.textdemo;
import android.app.Application;
import android.content.Context;
import com.yasin.px_percent_layout.utils.PxAppConfig;
/**
* Created by leo on 17/2/9.
*/
public class BaseApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
PxAppConfig.init(base);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
然后我们就可以在布局文件中用起来了:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context="com.example.leo.textdemo.MainActivity">
<com.yasin.px_percent_layout.PercentLinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_widthPercent="10%w"
app:layout_heightPercent="10%h"
android:text="10%w,10%h"
android:background="#ff0000"
android:textColor="#fff"
/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_widthPercent="20%sw"
app:layout_heightPercent="20%sh"
android:text="屏幕宽的20%sw,屏幕高的20%sh"
android:background="#ffff00"
android:textColor="#ff00"
/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_widthPercent="200px"
app:layout_heightPercent="200px"
android:text="iphone6为基准的宽:200px,高:200px"
android:background="#0000ff"
android:textColor="#fff"
/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_widthPercent="375px"
app:layout_heightPercent="375px"
android:text="iphone6为基准的宽:370px,高:370px,textsize为28px"
android:background="#00ff00"
app:layout_textSizePercent="28px"
android:textColor="#ff00"
/>
com.yasin.px_percent_layout.PercentLinearLayout>
RelativeLayout>
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
好啦!!!文章有点长哈,最后附上项目的Git链接:
https://github.com/913453448/PercentLayoutDemo