屏幕适配之百分比方案详解
来源:互联网 发布:软件测试干什么的 编辑:程序博客网 时间:2024/05/20 21:23
最近看到DrawerLayout
,support v4
中提供的类,想到对google
提供的这些支持库,自己一点都不熟悉,想着看看Google
提供的支持库都有什么内容。结果看着看着在最后忽然看到了Percent Support Library
。寻思怎么还百分比呢?仔细一看介绍,我擦,真是太有用了。
Percent Support Library
The Percent package provides APIs to support adding and managing percentage based dimensions in your app.
The Percent Support library adds support for the PercentLayoutHelper.PercentLayoutParams interface and various classes, such as PercentFrameLayout and PercentRelativeLayout.
After you download the Android Support Libraries, this library is located in the /extras/android/support/percent directory. For more information on how to set up your project, follow the instructions in Adding libraries with resources.
The Gradle build script dependency identifier for this library is as follows:
com.android.support:percent:23.3.0
看到了吗? 说提供了PercentFrameLayout
和PercentRelativeLayout
来支持百分比了。这样不就完美的解决了适配的问题嘛。啥也不说了,立马配置cradle
来瞧瞧。
Subclass of FrameLayout that supports percentage based dimensions and margins. You can specify dimension or a margin of child by using attributes with “Percent” suffix.
上代码:
<code
class
=
"language-xml hljs "
>
<imageview android:src=
"@mipmap/ic_launcher"
app:layout_heightpercent=
"50%"
app:layout_marginleftpercent=
"25%"
app:layout_margintoppercent=
"25%"
app:layout_widthpercent=
"50%"
>
</imageview></android.support.percent.percentframelayout></code>
效果如下:
完美.
支持的属性:
layout_widthPercent
layout_heightPercent
layout_marginPercent
layout_marginLeftPercent
layout_marginTZ喎�"/kf/ware/vc/" target="_blank" class="keylink">vcFBlcmNlbnQ8L2NvZGU+IDxjb2RlPmxheW91dF9tYXJnaW5SaWdodFBlcmNlbnQ8L2NvZGU+IDxjb2RlPmxheW91dF9tYXJnaW5Cb3R0b21QZXJjZW50PC9jb2RlPiA8Y29kZT5sYXlvdXRfbWFyZ2luU3RhcnRQZXJjZW50PC9jb2RlPiA8Y29kZT5sYXlvdXRfbWFyZ2luRW5kUGVyY2VudDwvY29kZT4gPGNvZGU+bGF5b3V0X2FzcGVjdFJhdGlvPC9jb2RlPg0KPGJsb2NrcXVvdGU+DQoJPHA+SXQgaXMgbm90IG5lY2Vzc2FyeSB0byBzcGVjaWZ5IGxheW91dF93aWR0aC9oZWlnaHQgaWYgeW91IHNwZWNpZnkgbGF5b3V0X3dpZHRoUGVyY2VudC4gSG93ZXZlciwgaWYgeW91IHdhbnQgdGhlIHZpZXcgdG8gYmUgYWJsZSB0byB0YWtlIHVwIG1vcmUgc3BhY2UgdGhhbiB3aGF0IHBlcmNlbnRhZ2UgdmFsdWUgcGVybWl0cywgeW91IGNhbiBhZGQgbGF5b3V0X3dpZHRoL2hlaWdodD0mcmRxdW87d3JhcF9jb250ZW50JnJkcXVvOy4gSW4gdGhhdCBjYXNlIGlmIHRoZSBwZXJjZW50YWdlIHNpemUgaXMgdG9vIHNtYWxsIGZvciB0aGUgVmlldyZyc3F1bztzIGNvbnRlbnQsIGl0IHdpbGwgYmUgcmVzaXplZCB1c2luZyB3cmFwX2NvbnRlbnQgcnVsZS48L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cD7I57n71ri2qMHLPGNvZGU+bGF5b3V0X3dpZHRoUGVyY2VudDwvY29kZT6+zbK708PWuLaoPGNvZGU+bGF5b3V0X3dpZHRoL2hlaWdodDwvY29kZT7K9NDUwcuhoyg8Y29kZT5TdHVkaW88L2NvZGU+v8nE3LvhzOHKvrTtzvOjrMno1sO69sLUvs26wymho8i7tvijrMjnufvE48/r0qq4wzxjb2RlPlZpZXc8L2NvZGU+xNy5u9W808OxyMno1sO1xLDZt9axyNa1uPy087XEv9W85Mqxo6zE47/J0tTWuLaoPGNvZGU+bGF5b3V0X3dpZGh0L2hlaWdodD0mbGRxdW87d3JhcF9jb250ZW50JnJkcXVvOzwvY29kZT6ho9Ta1eLW1sfpv/bPwqOsyOe5+8no1sO1xLDZt9axyNa11NrP1Mq+xNrI3cqxzKvQocqxo6y9q7vhyrnTwzxjb2RlPndyYXBfY29udGVudDwvY29kZT61xNa11tjQwrzGy+OhozwvcD4NCjxwPr7NysfV4rj20uLLvDrI57n71ri2qLXEsNm31rHIzKvQocXCz9TKvrK7v6q1xLuwo6zSsr/J0tS4+Mv81ri2qDxjb2RlPndyYXBfY29udGVudDwvY29kZT7K9NDUo6zV4tH5tbHP1Mq+sru/qrXEyrG68r7Nu+HKudPDPGNvZGU+d3JhcF9jb250ZW50PC9jb2RlPrXE1rWhozxiciAvPg0KyOfPwjo8L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;">
效果:
加入wrap_content
后一点效果也没有啊,还是显示不全啊,还没加wrap_content
一样,- -!
你也可以通过只设置width
或者height
和layout_aspectRatio
这种比例值的方式来让第另一个值自动计算。例如,如果你想要使用16:9
的比例,你可以使用:
<code
class
=
"language-xml hljs "
>android:layout_width=
"300dp"
app:layout_aspectRatio=
"178%"
</code>
这样将会在宽固定为300dp
的基础上以16:9(1.78:1)来计算高度。
PercentRelativeLayout
的使用都是一样的,这里就不贴了。
那它是怎么实现的呢?其实就是内部给通过属性换算,把本布局的宽高和百分比去计算每个view
的大小和位置。但是还有为什么上面设置的wrap_content
无效呢?是我理解错了吗?
带着这两个疑问我们来看下源码:
<code
class
=
"language-java hljs "
>
public
class
PercentFrameLayout
extends
FrameLayout {
private
final
PercentLayoutHelper mHelper =
new
PercentLayoutHelper(
this
);
public
PercentFrameLayout(Context context) {
super
(context);
}
public
PercentFrameLayout(Context context, AttributeSet attrs) {
super
(context, attrs);
}
public
PercentFrameLayout(Context context, AttributeSet attrs,
int
defStyleAttr) {
super
(context, attrs, defStyleAttr);
}
@Override
protected
LayoutParams generateDefaultLayoutParams() {
return
new
LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
@Override
public
LayoutParams generateLayoutParams(AttributeSet attrs) {
return
new
LayoutParams(getContext(), attrs);
}
@Override
protected
void
onMeasure(
int
widthMeasureSpec,
int
heightMeasureSpec) {
mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
super
.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 从名字上就能看出来下面就是处理如果指定百分比过小不足显示内容时,就去使用`wrap_content`的逻辑
if
(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);
mHelper.restoreOriginalParams();
}
public
static
class
LayoutParams
extends
FrameLayout.LayoutParams
implements
PercentLayoutHelper.PercentLayoutParams {
private
PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;
public
LayoutParams(Context c, AttributeSet attrs) {
super
(c, attrs);
// PercentLayoutInfo中去解析自定义属性的值
mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
}
public
LayoutParams(
int
width,
int
height) {
super
(width, height);
}
public
LayoutParams(
int
width,
int
height,
int
gravity) {
super
(width, height, gravity);
}
public
LayoutParams(ViewGroup.LayoutParams source) {
super
(source);
}
public
LayoutParams(MarginLayoutParams source) {
super
(source);
}
public
LayoutParams(FrameLayout.LayoutParams source) {
super
((MarginLayoutParams) source);
gravity = source.gravity;
}
public
LayoutParams(LayoutParams source) {
this
((FrameLayout.LayoutParams) source);
mPercentLayoutInfo = source.mPercentLayoutInfo;
}
@Override
public
PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo() {
if
(mPercentLayoutInfo ==
null
) {
mPercentLayoutInfo =
new
PercentLayoutHelper.PercentLayoutInfo();
}
return
mPercentLayoutInfo;
}
@Override
protected
void
setBaseAttributes(TypedArray a,
int
widthAttr,
int
heightAttr) {
PercentLayoutHelper.fetchWidthAndHeight(
this
, a, widthAttr, heightAttr);
}
}
}</code>
源码不长,主要是三个部分:
重写onMeasure
,根据百分比转换成对应的尺寸 重写onLayout
自定义LayoutParams
,在FrameLayout.LayoutParams
的基础上多实现了一个接口。包含了PercentLayoutHelper.PercentLayoutInfo
属性,而文档中对PercentLayoutInfo
的介绍是Container for information about percentage dimensions and margins. It acts as an extension for LayoutParams.
我们也先一步步的来分析,首先看下mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
:
<code
class
=
"language-java hljs "
>
/**
* Iterates over children and changes their width and height to one calculated from percentage
* values.
* @param widthMeasureSpec Width MeasureSpec of the parent ViewGroup.
* @param heightMeasureSpec Height MeasureSpec of the parent ViewGroup.
*/
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);
// mHost是由构造函数传递过来的,就是PercentFrameLayout自身。
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) {
// 通过PercentLayoutParams. getPercentLayoutInfo()方法得到PercentLayoutInfo,至于PercentLayoutInfo类在上面也说过了。
PercentLayoutInfo info =
((PercentLayoutParams) params).getPercentLayoutInfo();
if
(Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG,
"using "
+ info);
}
if
(info !=
null
) {
if
(params
instanceof
ViewGroup.MarginLayoutParams) {
// PercentFrameLayout.LayoutParams继承自FrameLayout.LayoutParams,而FrameLayout.LayoutParams又继承自ViewGroup.MarginLayoutParams
info.fillMarginLayoutParams(view, (ViewGroup.MarginLayoutParams) params,
widthHint, heightHint);
}
else
{
info.fillLayoutParams(params, widthHint, heightHint);
}
}
}
}
}</code>
所以上面代码的意思就是通过对每个子View
调用getLayoutParams
方法,然后从该LayoutParams
中获取到它的PercentLayoutInfo
属性,然后再调用PercentLayoutInfo.fillMarginLayoutParams()
方法。
那我们继续看一下PercentLayoutInfo.fillMarginLayoutParams()
方法的实现,该方法是根据百分比去设置尺寸和margin:
<code
class
=
"language-java hljs "
>
/**
* Fills {@code ViewGroup.MarginLayoutParams} dimensions and margins based on percentage
* values.
*/
public
void
fillMarginLayoutParams(View view, ViewGroup.MarginLayoutParams params,
int
widthHint,
int
heightHint) {
// 根据百分比值设置View的尺寸
fillLayoutParams(params, widthHint, heightHint);
// 从注释中就能知道,fillLayoutParams是计算尺寸,那下面这部分就是处理margin了
// mPreservedParams来记录原始的margin值
// Preserve the original margins, so we can restore them after the measure step.
mPreservedParams.leftMargin = params.leftMargin;
mPreservedParams.topMargin = params.topMargin;
mPreservedParams.rightMargin = params.rightMargin;
mPreservedParams.bottomMargin = params.bottomMargin;
MarginLayoutParamsCompat.setMarginStart(mPreservedParams,
MarginLayoutParamsCompat.getMarginStart(params));
MarginLayoutParamsCompat.setMarginEnd(mPreservedParams,
MarginLayoutParamsCompat.getMarginEnd(params));
if
(leftMarginPercent >=
0
) {
params.leftMargin = (
int
) (widthHint * leftMarginPercent);
}
if
(topMarginPercent >=
0
) {
params.topMargin = (
int
) (heightHint * topMarginPercent);
}
if
(rightMarginPercent >=
0
) {
params.rightMargin = (
int
) (widthHint * rightMarginPercent);
}
if
(bottomMarginPercent >=
0
) {
params.bottomMargin = (
int
) (heightHint * bottomMarginPercent);
}
boolean
shouldResolveLayoutDirection =
false
;
if
(startMarginPercent >=
0
) {
MarginLayoutParamsCompat.setMarginStart(params,
(
int
) (widthHint * startMarginPercent));
shouldResolveLayoutDirection =
true
;
}
if
(endMarginPercent >=
0
) {
MarginLayoutParamsCompat.setMarginEnd(params,
(
int
) (widthHint * endMarginPercent));
shouldResolveLayoutDirection =
true
;
}
if
(shouldResolveLayoutDirection && (view !=
null
)) {
// Force the resolve pass so that start / end margins are propagated to the
// matching left / right fields
MarginLayoutParamsCompat.resolveLayoutDirection(params,
ViewCompat.getLayoutDirection(view));
}
if
(Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG,
"after fillMarginLayoutParams: ("
+ params.width +
", "
+ params.height
+
")"
);
}
}</code>
再看一下PercentLayoutInfo.fillLayoutParams()
的实现,该方法是通过百分比设置View
的尺寸:
<code
class
=
"language-java hljs "
>
/**
* Fills {@code ViewGroup.LayoutParams} dimensions based on percentage values.
*/
public
void
fillLayoutParams(ViewGroup.LayoutParams params,
int
widthHint,
int
heightHint) {
// mPreservedParams来记录原始的宽高值
// Preserve the original layout params, so we can restore them after the measure step.
mPreservedParams.width = params.width;
mPreservedParams.height = params.height;
// We assume that width/height set to 0 means that value was unset. This might not
// necessarily be true, as the user might explicitly set it to 0. However, we use this
// information only for the aspect ratio. If the user set the aspect ratio attribute,
// it means they accept or soon discover that it will be disregarded.
final
boolean
widthNotSet =
(mPreservedParams.mIsWidthComputedFromAspectRatio
|| mPreservedParams.width ==
0
) && (widthPercent <
0
);
final
boolean
heightNotSet =
(mPreservedParams.mIsHeightComputedFromAspectRatio
|| mPreservedParams.height ==
0
) && (heightPercent <
0
);
// 如果指定了百分比属性,就用宽高值和百分比去算出具体的宽高
if
(widthPercent >=
0
) {
params.width = (
int
) (widthHint * widthPercent);
}
if
(heightPercent >=
0
) {
params.height = (
int
) (heightHint * heightPercent);
}
// 如果指定了宽高的比例值,就用比例值去算出宽高,从这里能看出`aspectRatio`的优先级比百分比要高。他可以覆盖百分比之前设置的值。
if
(aspectRatio >=
0
) {
if
(widthNotSet) {
params.width = (
int
) (params.height * aspectRatio);
// Keep track that we've filled the width based on the height and aspect ratio.
mPreservedParams.mIsWidthComputedFromAspectRatio =
true
;
}
if
(heightNotSet) {
params.height = (
int
) (params.width / aspectRatio);
// Keep track that we've filled the height based on the width and aspect ratio.
mPreservedParams.mIsHeightComputedFromAspectRatio =
true
;
}
}
if
(Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG,
"after fillLayoutParams: ("
+ params.width +
", "
+ params.height +
")"
);
}
}
</code>
到这里onMeasure
中通过百分比值设置宽高以及margin
的部分就看完了,那我们接着看一下关于百分比值过小时对wrap_content
的处理:
<code
class
=
"language-java hljs "
>
if
(mHelper.handleMeasuredStateTooSmall()) {
super
.onMeasure(widthMeasureSpec, heightMeasureSpec);
}</code>
看一下PercentLayoutHelper.handleMeasuredStateTooSmall()
方法的实现:
<code
class
=
"language-java hljs "
>
/**
* Iterates over children and checks if any of them would like to get more space than it
* received through the percentage dimension.
*
* If you are building a layout that supports percentage dimensions you are encouraged to take
* advantage of this method. The developer should be able to specify that a child should be
* remeasured by adding normal dimension attribute with {@code wrap_content} value. For example
* he might specify child's attributes as {@code app:layout_widthPercent="60%p"} and
* {@code android:layout_width="wrap_content"}. In this case if the child receives too little
* space, it will be remeasured with width set to {@code WRAP_CONTENT}.
*
* @return True if the measure phase needs to be rerun because one of the children would like
* to receive more space.
*/
public
boolean
handleMeasuredStateTooSmall() {
boolean
needsSecondMeasure =
false
;
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 handle measured state too small "
+ view +
" "
+ params);
}
if
(params
instanceof
PercentLayoutParams) {
PercentLayoutInfo info =
((PercentLayoutParams) params).getPercentLayoutInfo();
if
(info !=
null
) {
// shouldHandleMeasuredWidthTooSmall方法来进行判断
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
(Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG,
"should trigger second measure pass: "
+ needsSecondMeasure);
}
return
needsSecondMeasure;
}</code>
那继续看一下shouldHandleMeasuredWidthTooSmall()
方法:
<code
class
=
"language-java hljs "
>
private
static
boolean
shouldHandleMeasuredWidthTooSmall(View view, PercentLayoutInfo info) {
int
state = ViewCompat.getMeasuredWidthAndState(view) & ViewCompat.MEASURED_STATE_MASK;
return
state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.widthPercent >=
0
&&
info.mPreservedParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
}</code>
继续看ViewCompat.getMeasuredWidthAndState()
的源码:
<code
class
=
"language-java hljs "
>
public
static
int
getMeasuredWidthAndState(View view) {
return
IMPL.getMeasuredWidthAndState(view);
}</code>
继续往下看,这个IMPL
是什么呢?
<code
class
=
"language-java hljs "
>
static
final
ViewCompatImpl IMPL;
static
{
final
int
version = android.os.Build.VERSION.SDK_INT;
if
(version >=
23
) {
IMPL =
new
MarshmallowViewCompatImpl();
}
else
if
(version >=
21
) {
IMPL =
new
LollipopViewCompatImpl();
}
else
if
(version >=
19
) {
IMPL =
new
KitKatViewCompatImpl();
}
else
if
(version >=
17
) {
IMPL =
new
JbMr1ViewCompatImpl();
}
else
if
(version >=
16
) {
IMPL =
new
JBViewCompatImpl();
}
else
if
(version >=
15
) {
IMPL =
new
ICSMr1ViewCompatImpl();
}
else
if
(version >=
14
) {
IMPL =
new
ICSViewCompatImpl();
}
else
if
(version >=
11
) {
IMPL =
new
HCViewCompatImpl();
}
else
if
(version >=
9
) {
IMPL =
new
GBViewCompatImpl();
}
else
if
(version >=
7
) {
IMPL =
new
EclairMr1ViewCompatImpl();
}
else
{
IMPL =
new
BaseViewCompatImpl();
}
}</code>
继续看,IMPL.getMeasuredWidthAndState()
,方法其实最终就是使用的BaseViewCompatImpl.getMeasuredWidthAndState()
方法,接着看它的的源码:
<code
class
=
"language-java hljs "
>
@Override
public
int
getMeasuredWidthAndState(View view) {
return
view.getMeasuredWidth();
}</code>
最后就是调用了getMeasuredWidth()
方法。 没毛病- -!
onMeasure
的到这里就分析完了。
那接着来看一下onLayout
方法,onLayout
方法直接调用了PercentLayoutHelper.restoreOriginalParams
,:
<code
class
=
"language-java hljs "
>
/**
* Iterates over children and restores their original dimensions that were changed for
* percentage values. Calling this method only makes sense if you previously called
* {@link PercentLayoutHelper#adjustChildren(int, int)}.
*/
public
void
restoreOriginalParams() {
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 restore "
+ 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
) {
if
(params
instanceof
ViewGroup.MarginLayoutParams) {
info.restoreMarginLayoutParams((ViewGroup.MarginLayoutParams) params);
}
else
{
info.restoreLayoutParams(params);
}
}
}
}
}</code>
调用了PercentLayoutInfo.restoreMarginLayoutParams()
方法,我们看下它的源码:
<code
class
=
"language-java hljs "
>
/**
* Restores original dimensions and margins after they were changed for percentage based
* values. Calling this method only makes sense if you previously called
* {@link PercentLayoutHelper.PercentLayoutInfo#fillMarginLayoutParams}.
*/
public
void
restoreMarginLayoutParams(ViewGroup.MarginLayoutParams params) {
restoreLayoutParams(params);
// mPreservedParams的值在之前ad
params.leftMargin = mPreservedParams.leftMargin;
params.topMargin = mPreservedParams.topMargin;
params.rightMargin = mPreservedParams.rightMargin;
params.bottomMargin = mPreservedParams.bottomMargin;
MarginLayoutParamsCompat.setMarginStart(params,
MarginLayoutParamsCompat.getMarginStart(mPreservedParams));
MarginLayoutParamsCompat.setMarginEnd(params,
MarginLayoutParamsCompat.getMarginEnd(mPreservedParams));
}
</code>
意思是说,再他们被以百分比为基础的数据更改之后恢复成原始的尺寸和margin。
然后继续看一下restoreLayoutParams()
:
<code
class
=
"language-java hljs "
>
/**
* Restores original dimensions after they were changed for percentage based values. Calling
* this method only makes sense if you previously called
* {@link PercentLayoutHelper.PercentLayoutInfo#fillLayoutParams}.
*/
public
void
restoreLayoutParams(ViewGroup.LayoutParams params) {
if
(!mPreservedParams.mIsWidthComputedFromAspectRatio) {
// Only restore the width if we didn't compute it based on the height and
// aspect ratio in the fill pass.
params.width = mPreservedParams.width;
}
if
(!mPreservedParams.mIsHeightComputedFromAspectRatio) {
// Only restore the height if we didn't compute it based on the width and
// aspect ratio in the fill pass.
params.height = mPreservedParams.height;
}
// Reset the tracking flags.
mPreservedParams.mIsWidthComputedFromAspectRatio =
false
;
mPreservedParams.mIsHeightComputedFromAspectRatio =
false
;
}</code>
好了到这里也分析完了onLayout
的方法,大意就是在onMeasure
之前先将原始的宽高和margin
都备份一下,然后在onMeasure
中根据百分比去设置对应的宽高和margin
,等到设置完之后在onLayout
方法中再去将这些值恢复到之前备份的起始数据。说实话我没看明白为什么要这样做?
通过上面的代码分析我们知道对布局影响力的优先顺序: app:layout_aspectRatio > app:layout_heightPercent > android:layout_height
如果我们同时都设置这三个参数值的话,最终会用app:layout_aspectRatio
的值。
遗留问题:
为什么在onLayout
方法中去恢复数据,这有什么作用? 看代码在处理如果指定的百分比过小但又指定wrap_content
时,会重新根据wrap_content
去重新计算的逻辑没有错,但是为什么我在上面测试的时候确没效果?有知道上面这两个问题的告诉我一下。
更多内容请关注Github
- 屏幕适配之百分比方案详解
- 屏幕适配之百分比方案详解
- 安卓适配之终极方案,百分比适配
- Android 控件屏幕适配之百分比布局
- Android屏幕适配,百分比布局
- Android屏幕适配,百分比布局
- android支持百分比的屏幕适配
- 屏幕百分比适配的属性
- 屏幕适配和百分比布局
- Android DraerLayout 抽屉百分比适配屏幕宽度
- Android百分比布局解决屏幕适配问题
- Android适配之百分比布局
- Android 屏幕适配方案(百分比)
- Android 屏幕适配方案(百分比)
- Android 百分比屏幕适配方案
- Android 屏幕适配方案 引入百分比
- Android屏幕适配方案(百分比)
- 百分比布局的延伸,百分比布局自动适配,解决了安卓做屏幕适配的麻烦。
- mybatis+maven实例
- Oracle 命令
- JAVA多线程之——互斥锁ReentrantLock
- Apache与Tomcat有什么关系和区别
- 排序算法之冒泡排序
- 屏幕适配之百分比方案详解
- keil4中debug信号函数的简单使用
- android中在fragment A里面点击button跳转到fragment B怎么实现?
- hello world在操作系统底层的执行过程
- 《春日飞翔》——为了纪念【小诗】
- java的classpath的作用
- 微信公众号如何关联小程序(小程序如何开发)
- 五分钟搞懂Gson的用法
- 《富爸爸穷爸爸》读书笔记