Android 百分比布局库(percent-support-lib) 解析与扩展
Ò»¡¢¸ÅÊö
ÖÜÄ©ÓÎÏ·´òµÃ¹ýÃÍ£¬ÓÚÊÇÖÜÌì°¾Ò¹Âë´úÂ룬ÖÜÒ»ÔçÉÏ»ë»ëججµÄ·¢ÏÖandroid-percent-support-lib-sampleÕâ¸öÏîÄ¿£¬GoogleÖÕÓÚ¿ªÊ¼Ö§³Ö°Ù·Ö±ÈµÄ·½Ê½²¼¾ÖÁË£¬Ë²¼äÂö¶¯»ØÀ´£¬°¡ßÖßÖ¡£¶ÔÓÚÕâÖÖÀúÊ·ÐÔµÄʱ¿Ì£¬²»³öƪ²©¿ÍÄÑÒÔ±í´ïÎÒÄÚÐĵļ¤¶¯¡£
»¹¼ÇµÃ²»¾ÃÇ°£¬·¢ÁËƪ²©¿Í£ºAndroid ÆÁÄ»ÊÊÅä·½°¸£¬Õâƪ²©¿ÍÒÔWebÒ³ÃæÉè¼ÆÒý³öÒ»ÖÖÊÊÅä·½°¸£¬×îÖÕµÄÄ¿µÄ¾ÍÊÇ¿ÉÒÔͨ¹ý°Ù·Ö±È¿ØÖƿؼþµÄ´óС¡£µ±È»ÁË£¬´æÔÚһЩÎÊÌ⣬±ÈÈ磺
-
¶ÔÓÚûÓп¼Âǵ½ÆÁÄ»³ß´ç£¬¿ÉÄÜ»á³öÏÖÒâÍâµÄÇé¿ö£»
-
apkµÄ´óС»áÔö¼Ó£»
µ±È»ÁËandroid-percent-supportÕâ¸ö¿â£¬»ù±¾¿ÉÒÔ½â¾öÉÏÊöÎÊÌ⣬ÊDz»ÊÇÓеãС¼¤¶¯£¬ÉԵȣ¬ÎÒÃÇÏÈÃèÊöÏÂÕâ¸ösupport-lib¡£
Õâ¸ö¿âÌṩÁË£º
-
Á½ÖÖ²¼¾Ö¹©´ó¼ÒʹÓãº
PercentRelativeLayout¡¢PercentFrameLayout£¬Í¨¹ýÃû×־ͿÉÒÔ¿´³ö£¬ÕâÊǼ̳Ð×ÔFrameLayoutºÍRelativeLayoutÁ½¸öÈÝÆ÷Àࣻ -
Ö§³ÖµÄÊôÐÔÓУº
layout_widthPercent¡¢layout_heightPercent¡¢
layout_marginPercent¡¢layout_marginLeftPercent¡¢
layout_marginTopPercent¡¢layout_marginRightPercent¡¢
layout_marginBottomPercent¡¢layout_marginStartPercent¡¢layout_marginEndPercent¡£
¿ÉÒÔ¿´µ½Ö§³Ö¿í¸ß£¬ÒÔ¼°margin¡£
Ò²¾ÍÊÇ˵£¬´ó¼ÒÖ»ÒªÔÚ¿ª·¢¹ý³ÌÖÐʹÓÃPercentRelativeLayout¡¢PercentFrameLayoutÌæ»»FrameLayout¡¢RelativeLayout¼´¿É¡£
ÊDz»ÊǺܼòµ¥£¬²»¹ýòËÆûÓÐLinearLayout£¬ÓÐÈË»á˵LinearLayoutÓÐweightÊôÐÔѽ¡£µ«ÊÇ£¬weightÊôÐÔÖ»ÄÜÖ§³ÖÒ»¸ö·½Ïòѽ~~¹þ£¬Ã»Ê£¬¸ÕºÃ¸øÎÒÃÇÒ»¸ö»ú»áÈ¥×Ô¶¨ÒåÒ»¸öPercentLinearLayout¡£
ºÃÁË£¬±¾ÎÄ·ÖΪ3¸ö²¿·Ö£º
-
PercentRelativeLayout¡¢PercentFrameLayoutµÄʹÓÃ
-
¶ÔÉÏÊö¿Ø¼þÔ´Âë·ÖÎö
-
×Ô¶¨ÒåPercentLinearLayout
¶þ¡¢Ê¹ÓÃ
¹ØÓÚʹÓã¬Æäʵ¼°Æä¼òµ¥£¬²¢ÇÒgithubÉÏÒ²ÓÐÀý×Ó£¬android-percent-support-lib-sample¡£ÎÒÃǾͼòµ¥¹ýһϣº
Ê×ÏȼǵÃÔÚbuild.gradleÌí¼Ó£º
compile 'com.android.support:percent:22.2.0'
£¨Ò»£©PercentFrameLayout
<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="left|top"
android:background="#44ff0000"
android:text="width:30%,height:20%"
app:layout_heightPercent="20%"
android:gravity="center"
app:layout_widthPercent="30%"/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="right|top"
android:gravity="center"
android:background="#4400ff00"
android:text="width:70%,height:20%"
app:layout_heightPercent="20%"
app:layout_widthPercent="70%"/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="bottom"
android:background="#770000ff"
android:text="width:100%,height:10%"
android:gravity="center"
app:layout_heightPercent="10%"
app:layout_widthPercent="100%"/>
</android.support.percent.PercentFrameLayout>
3¸öTextView£¬ºÜ¼òµ¥£¬Ö±½Ó¿´Ð§¹ûͼ£º
(¶þ) PercentRelativeLayout
<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true">
<TextView
android:id="@+id/row_one_item_one"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentTop="true"
android:background="#7700ff00"
android:text="w:70%,h:20%"
android:gravity="center"
app:layout_heightPercent="20%"
app:layout_widthPercent="70%"/>
<TextView
android:id="@+id/row_one_item_two"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_toRightOf="@+id/row_one_item_one"
android:background="#396190"
android:text="w:30%,h:20%"
app:layout_heightPercent="20%"
android:gravity="center"
app:layout_widthPercent="30%"/>
<ImageView
android:id="@+id/row_two_item_one"
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@drawable/tangyan"
android:scaleType="centerCrop"
android:layout_below="@+id/row_one_item_one"
android:background="#d89695"
app:layout_heightPercent="70%"/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_below="@id/row_two_item_one"
android:background="#770000ff"
android:gravity="center"
android:text="width:100%,height:10%"
app:layout_heightPercent="10%"
app:layout_widthPercent="100%"/>
</android.support.percent.PercentRelativeLayout>
ok£¬ÒÀÈ»ÊÇÖ±½Ó¿´Ð§¹ûͼ:
ʹÓÃûʲôºÃ˵µÄ£¬¾ÍÊÇÖ±¹ÛµÄ¿´Ò»Ï¡£
Èý¡¢Ô´Âë·ÖÎö
ÆäʵϸÏëһϣ¬GoogleÖ»ÊǶÔÎÒÃÇÔ±¾ÊìϤµÄRelativeLayoutºÍFrameLayout½øÐеŦÄܵÄÀ©Õ¹£¬Ê¹ÆäÖ§³ÖÁËpercentÏà¹ØµÄÊôÐÔ¡£
ÄÇô£¬ÎÒÃÇ¿¼ÂÇÏ£¬Èç¹ûÊÇÎÒÃÇÌí¼ÓÕâÖÖÀ©Õ¹£¬ÎÒÃÇ»áÔõô×ö£º
-
ͨ¹ýLayoutParams»ñÈ¡childÉèÖõÄpercentÏà¹ØÊôÐÔµÄÖµ
-
onMeasureµÄʱºò£¬½«childµÄwidth,heightµÄÖµ£¬Í¨¹ý»ñÈ¡µÄ×Ô¶¨ÒåÊôÐÔµÄÖµ½øÐмÆË㣨eg:ÈÝÆ÷µÄ¿í * fraction £©£¬¼ÆËãºó´«Èë¸øchild.measure(w,h);
ok£¬ÓÐÁËÉÏÃæµÄ²ÂÏ룬ÎÒÃÇÖ±½Ó¿´PercentFrameLayoutµÄÔ´Âë¡£
public class PercentFrameLayout extends FrameLayout {
private final PercentLayoutHelper mHelper = new PercentLayoutHelper(this);
//Ê¡ÂÔÁË£¬Á½¸ö¹¹Ôì·½·¨
public PercentFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@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);
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);
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);
}
}
}
´úÂëÊÇÏ൱µÄ¶Ì£¬¿ÉÒÔ¿´µ½PercentFrameLayoutÀïÃæÊ×ÏÈÖØдÁËgenerateLayoutParams·½·¨£¬µ±È»ÁË£¬ÓÉÓÚÖ§³ÖÁËһЩеÄlayout_ÊôÐÔ£¬ÄÇô¿Ï¶¨ÐèÒª¶¨Òå¶ÔÓ¦µÄLayoutParams¡£
£¨Ò»£©percentÏà¹ØÊôÐԵĻñÈ¡
¿ÉÒÔ¿´µ½PercentFrameLayout.LayoutParamsÔÚÔÓеÄFrameLayout.LayoutParams»ù´¡ÉÏ£¬ÊµÏÖÁËPercentLayoutHelper.PercentLayoutParams½Ó¿Ú¡£
Õâ¸ö½Ó¿ÚºÜ¼òµ¥£¬Ö»ÓÐÒ»¸ö·½·¨£º
public interface PercentLayoutParams {
PercentLayoutInfo getPercentLayoutInfo();
}
¶ø£¬Õâ¸ö·½·¨µÄʵÏÖÄØ£¬Ò²Ö»ÓÐÒ»ÐУºreturn mPercentLayoutInfo;£¬ÄÇôÕâ¸ömPercentLayoutInfoÔÚÄÄÍê³É¸³ÖµÄØ£¿
¿´PercentFrameLayout.LayoutParamsµÄ¹¹Ôì·½·¨£º
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
}
¿ÉÒÔ¿´µ½£¬½«attrs´«Èë¸øgetPercentLayoutInfo·½·¨£¬ÄÇô²»ÓÃ˵£¬Õâ¸ö·½·¨µÄÄÚ²¿£¬¿Ï¶¨ÊÇ»ñÈ¡×Ô¶¨ÒåÊôÐÔµÄÖµ£¬È»ºó½«Æä·â×°µ½PercentLayoutInfo¶ÔÏóÖУ¬×îºó·µ»Ø¡£
´úÂëÈçÏ£º
public static PercentLayoutInfo getPercentLayoutInfo(Context context, AttributeSet attrs) {
PercentLayoutInfo info = null;
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PercentLayout_Layout);
float value = array.getFraction(R.styleable.PercentLayout_Layout_layout_widthPercent, 1, 1, -1f);
if (value != -1f) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent width: " + value);
}
info = info != null ? info: new PercentLayoutInfo();
info.widthPercent = value;
}
value = array.getFraction(R.styleable.PercentLayout_Layout_layout_heightPercent, 1, 1, -1f);
if (value != -1f) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent height: " + value);
}
info = info != null ? info: new PercentLayoutInfo();
info.heightPercent = value;
}
value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginPercent, 1, 1, -1f);
if (value != -1f) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent margin: " + value);
}
info = info != null ? info: new PercentLayoutInfo();
info.leftMarginPercent = value;
info.topMarginPercent = value;
info.rightMarginPercent = value;
info.bottomMarginPercent = value;
}
value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginLeftPercent, 1, 1, -1f);
if (value != -1f) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent left margin: " + value);
}
info = info != null ? info: new PercentLayoutInfo();
info.leftMarginPercent = value;
}
value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginTopPercent, 1, 1, -1f);
if (value != -1f) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent top margin: " + value);
}
info = info != null ? info: new PercentLayoutInfo();
info.topMarginPercent = value;
}
value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginRightPercent, 1, 1, -1f);
if (value != -1f) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent right margin: " + value);
}
info = info != null ? info: new PercentLayoutInfo();
info.rightMarginPercent = value;
}
value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginBottomPercent, 1, 1, -1f);
if (value != -1f) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent bottom margin: " + value);
}
info = info != null ? info: new PercentLayoutInfo();
info.bottomMarginPercent = value;
}
value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginStartPercent, 1, 1, -1f);
if (value != -1f) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent start margin: " + value);
}
info = info != null ? info: new PercentLayoutInfo();
info.startMarginPercent = value;
}
value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginEndPercent, 1, 1, -1f);
if (value != -1f) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "percent end margin: " + value);
}
info = info != null ? info: new PercentLayoutInfo();
info.endMarginPercent = value;
}
array.recycle();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "constructed: " + info);
}
return info;
}
ÊDz»ÊǺÍÎÒÃÇƽʱµÄÈ¡ÖµºÜÀàËÆ£¬ËùÓеÄÖµ×îÖÕ·â×°µ½PercentLayoutInfo¶ÔÏóÖС£
ok£¬µ½´ËÎÒÃǵÄÊôÐÔ»ñÈ¡¾Í½éÉÜÍê³É£¬ÓÐÁËÕâЩÊôÐÔ£¬ÊDz»ÊÇonMeasureÀïÃæÒª½øÐÐʹÓÃÄØ£¿
(¶þ) onMeasueÖÐÖØмÆËãchildµÄ³ß´ç
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mHelper.handleMeasuredStateTooSmall()) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
¿ÉÒÔ¿´µ½onMeasureÖеĴúÂëÒ³ºÜÉÙ£¬¿´À´ºËÐĵĴúÂ붼±»·â×°ÔÚmHelperµÄ·½·¨ÖУ¬ÎÒÃÇÖ±½Ó¿´mHelper.adjustChildren·½·¨¡£
/**
* 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) {
//...
int widthHint = View.MeasureSpec.getSize(widthMeasureSpec);
int heightHint = View.MeasureSpec.getSize(heightMeasureSpec);
for (int i = 0, N = mHost.getChildCount(); i < N; i++) {
View view = mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();
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.fillMarginLayoutParams((ViewGroup.MarginLayoutParams) params, widthHint, heightHint);
} else {
info.fillLayoutParams(params, widthHint, heightHint);
}
}
}
}
}
ͨ¹ý×¢ÊÍÒ²ÄÜ¿´³ö£¬´Ë·½·¨ÖбéÀúËùÓеĺ¢×Ó£¬Í¨¹ý°Ù·Ö±ÈµÄÊôÐÔÖØÐÂÉèÖÃÆä¿í¶ÈºÍ¸ß¶È¡£
Ê×ÏÈÔÚwidthHint¡¢heightHint±£´æÈÝÆ÷µÄ¿í¡¢¸ß£¬È»ºó±éÀúËùÓеĺ¢×Ó£¬ÅжÏÆäLayoutParamsÊÇ·ñÊÇPercentLayoutParamsÀàÐÍ£¬Èç¹ûÊÇ£¬Í¨¹ýparams.getPercentLayoutInfoÄóöinfo¶ÔÏó¡£
ÊÇ·ñ»¹¼ÇµÃ£¬ÉÏÃæµÄ·ÖÎöÖУ¬PercentLayoutInfo±£´æÁËpercentÏà¹ØÊôÐÔµÄÖµ¡£
Èç¹ûinfo²»Îªnull£¬ÔòÅжÏÊÇ·ñÐèÒª´¦Àímargin£»ÎÒÃÇÖ±½Ó¿´fillLayoutParams·½·¨£¨´¦ÀímarginÒ²ÊÇÀàËƵģ©¡£
/**
* Fills {@code ViewGroup.LayoutParams} dimensions based on percentage values.
*/
public void fillLayoutParams(ViewGroup.LayoutParams params, int widthHint, int heightHint) {
// Preserve the original layout params, so we can restore them after the measure step.
mPreservedParams.width = params.width;
mPreservedParams.height = params.height;
if (widthPercent >= 0) {
params.width = (int)(widthHint * widthPercent);
}
if (heightPercent >= 0) {
params.height = (int)(heightHint * heightPercent);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "after fillLayoutParams: (" + params.width + ", " + params.height + ")");
}
}
Ê×Ïȱ£´æÔ±¾µÄwidthºÍheight£¬È»ºóÖØÖÃparamsµÄwidthºÍheightΪ(int) (widthHint * widthPercent)ºÍ(int) (heightHint * heightPercent);¡£
µ½´Ë£¬ÆäʵÎÒÃǵİٷֱÈת»»¾Í½áÊøÁË£¬ÀíÂÛÉϾÍÒѾʵÏÖÁ˶ÔÓڰٷֱȵÄÖ§³Ö£¬²»¹ýGoogle»¹¿¼ÂÇÁËһЩϸ½Ú¡£
ÎÒÃǻص½onMeasure·½·¨£º
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mHelper.handleMeasuredStateTooSmall()) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
ÏÂÃ滹ÓиömHelper.handleMeasuredStateTooSmallµÄÅжϣ¬Ò²¾ÍÊÇ˵£¬Èç¹ûÄãÉèÖõİٷֱȣ¬×îÖÕ¼ÆËã³öÀ´µÄMeasuredSize¹ýСµÄ»°£¬»á½øÐÐһЩ²Ù×÷¡£
´úÂëÈçÏ£º
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) {
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;
}
Ê×ÏȱéÀúËùÓеĺ¢×Ó£¬Äóöº¢×ÓµÄlayoutparams£¬Èç¹ûÊÇPercentLayoutParamsʵÀý£¬ÔòÈ¡³öinfo¡£Èç¹ûinfo²»Îªnull£¬µ÷ÓÃshouldHandleMeasuredWidthTooSmallÅжϣº
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;
}
ÕâÀï¾ÍÊÇÅжϣ¬Èç¹ûÄãÉèÖõÄmeasuredWidth»òÕßmeasureHeight¹ýСµÄ»°£¬²¢ÇÒÄãÔÚ²¼¾ÖÎļþÖÐlayout_w/h ÉèÖõÄÊÇWRAP_CONTENTµÄ»°£¬½«params.width / height= ViewGroup.LayoutParams.WRAP_CONTENT£¬È»ºóÖØвâÁ¿¡£
¹þ£¬onMeasureÖÕÓÚ½áÊøÁË~~~ÏÖÔÚÎÒ¾õµÃÓ¦¸Ã´úÂë½áÊøÁË°É£¬³ß´ç¶¼ÉèÖúÃÁË£¬»¹ÐèÒª¸ÉÂïô£¬but£¬Äã»á·¢ÏÖonLayoutÒ²ÖØдÁË£¬ÎÒÃÇÓÖ²»¸Ä±älayout¹æÔò£¬ÔÚonLayoutÀïÃæ¸ÉʲôëÏߣº
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mHelper.restoreOriginalParams();
}
¼ÌÐø¿´mHelper.restoreOriginalParams
/**
* 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);
}
}
}
}
}
àÛ£¬ÔÀ´ÊÇÖØлָ´Ô±¾µÄ³ß´çÖµ£¬Ò²¾ÍÊÇ˵onMeasureÀïÃæµÄ¶ÔÖµ½øÐÐÁ˸ı䣬²âÁ¿Íê³Éºó¡£ÔÚÕâ¸öµØ·½£¬½«ÖµÓÖ»Ö¸´³ÉÈç¹û²¼¾ÖÎļþÖеÄÖµ£¬ÉÏÃæдµÄ¶¼ÊÇ0¡£»Ö¸´ºÜ¼òµ¥£º
public void restoreLayoutParams(ViewGroup.LayoutParams params) {
params.width = mPreservedParams.width;
params.height = mPreservedParams.height;
}
ÄãÓ¦¸ÃûÓÐÍüÔÚÄÄ´æµÄ°Ñ~ÍüÁ˵Ļ°£¬Âé·³Ctrl+F ¡®mPreservedParams.width¡¯ ¡£
Ò²¾ÍÊÇ˵£¬ÄãÈ¥´òÓ¡ÉÏÃæд·¨£¬²¼¾ÖÎļþÖÐviewµÄv.getLayoutParams().width£¬Õâ¸öÖµÓ¦¸ÃÊÇ0¡£
ÕâÀï¸Ð¾õÂÔ΢²»Ë¬~Õâ¸ö0ûÈöÓô¦Ñ½£¬»¹²»Èç²»ÖØÖÃ~~
ºÃÁË£¬µ½´Ë¾Í·ÖÎöÍêÁË£¬ÆäʵÖ÷Òª¾Í¼¸¸ö²½Ö裺
-
LayoutParamsÖÐÊôÐԵĻñÈ¡
-
onMeasureÖУ¬¸Ä±äparams.widthΪ°Ù·Ö±È¼ÆËã½á¹û£¬²âÁ¿
-
Èç¹û²âÁ¿Öµ¹ýСÇÒÉèÖõÄw/hÊÇwrap_content£¬ÖØвâÁ¿
-
onLayoutÖУ¬ÖØÖÃparams.w/hΪ²¼¾ÖÎļþÖбàдµÄÖµ
¿ÉÒÔ¿´µ½£¬ÓÐÁËRelativeLayout¡¢FrameLayoutµÄÀ©Õ¹£¬¾¹È»Ã»ÓÐLinearLayout¼¸¸öÒâ˼¡£ºÃÔÚ£¬ÎÒÃǵĺËÐÄ´úÂ붼ÓÉPercentLayoutHelper·â×°ÁË£¬×Ô¼ºÀ©Õ¹ÏÂLinearLayoutÒ²²»¸´ÔÓ¡£
Èý¡¢ÊµÏÖPercentLinearlayout
¿ÉÄÜÓÐÈË»á˵£¬ÓÐÁËweightѽ£¬µ«ÊÇweightÄÜ×öµ½¿í¡¢¸ßͬʱ°Ù·Ö±È¸³ÖµÂ
ºÃÁË£¬´úÂëºÜ¼òµ¥£¬ÈçÏ£º
£¨Ò»£©PercentLinearLayout
package com.juliengenoud.percentsamples;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.percent.PercentLayoutHelper;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.LinearLayout;
/**
* Created by zhy on 15/6/30.
*/
public class PercentLinearLayout extends LinearLayout
{
private PercentLayoutHelper mPercentLayoutHelper;
public PercentLinearLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
mPercentLayoutHelper = new PercentLayoutHelper(this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
mPercentLayoutHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mPercentLayoutHelper.handleMeasuredStateTooSmall())
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@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);
}
}
}
Èç¹ûÄãÏêϸ¿´ÁËÉÏÃæµÄÔ´Âë·ÖÎö£¬Õâ¸ö´úÂëÊDz»ÊÇûÈö½âÊ͵ÄÁË~
£¨¶þ£©²âÊÔ²¼¾Ö
<?xml version="1.0" encoding="utf-8"?>
<com.juliengenoud.percentsamples.PercentLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ff44aacc"
android:text="width:60%,height:5%"
android:textColor="#ffffff"
app:layout_heightPercent="5%"
app:layout_marginBottomPercent="5%"
app:layout_widthPercent="60%"/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ff4400cc"
android:gravity="center"
android:textColor="#ffffff"
android:text="width:70%,height:10%"
app:layout_heightPercent="10%"
app:layout_marginBottomPercent="5%"
app:layout_widthPercent="70%"/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ff44aacc"
android:gravity="center"
android:text="width:80%,height:15%"
android:textColor="#ffffff"
app:layout_heightPercent="15%"
app:layout_marginBottomPercent="5%"
app:layout_widthPercent="80%"/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ff4400cc"
android:gravity="center"
android:text="width:90%,height:5%"
android:textColor="#ffffff"
app:layout_heightPercent="20%"
app:layout_marginBottomPercent="10%"
app:layout_widthPercent="90%"/>
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#ff44aacc"
android:gravity="center"
android:text="width:100%,height:25%"
android:textColor="#ffffff"
app:layout_heightPercent="25%"
app:layout_marginBottomPercent="5%"
/>
</com.juliengenoud.percentsamples.PercentLinearLayout>
ÎÒÃÇ×ÝÏòÅÅÁеļ¸¸öTextView£¬·Ö±ðÉèÖÿí/¸ß¶¼Îª°Ù·Ö±È£¬ÇÒÖ®¼äµÄ¼ä¸ôΪ5%p¡£
(Èý)Ч¹ûͼ
ok£¬µ½´Ë£¬ÎÒÃÇʹÓá¢Ô´Âë·ÖÎö¡¢À©Õ¹PercentLinearLayout¾Í½áÊøÁË¡£
Ìí¼ÓPercentLinearLayoutºóµÄµØÖ·£ºµã»÷²é¿´
~~have a nice day ~~