Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 屏幕適配之百分比方案詳解

屏幕適配之百分比方案詳解

編輯:關於Android編程

最近看到DrawerLayoutsupport 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

看到了嗎? 說提供了PercentFrameLayoutPercentRelativeLayout來支持百分比了。這樣不就完美的解決了適配的問題嘛。啥也不說了,立馬配置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.

上代碼:


    

效果如下:
image
完美.

支持的屬性:

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;">

效果:
image

加入wrap_content後一點效果也沒有啊,還是顯示不全啊,還沒加wrap_content一樣,- -!

你也可以通過只設置width或者heightlayout_aspectRatio這種比例值的方式來讓第另一個值自動計算。例如,如果你想要使用16:9的比例,你可以使用:

android:layout_width="300dp"
app:layout_aspectRatio="178%"

這樣將會在寬固定為300dp的基礎上以16:9(1.78:1)來計算高度。

PercentRelativeLayout的使用都是一樣的,這裡就不貼了。

那它是怎麼實現的呢?其實就是內部給通過屬性換算,把本布局的寬高和百分比去計算每個view的大小和位置。但是還有為什麼上面設置的wrap_content無效呢?是我理解錯了嗎?

帶著這兩個疑問我們來看下源碼:

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);
        }
    }
}

源碼不長,主要是三個部分:

重寫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);:

/**
     * 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);
                    }
                }
            }
        }
    }

所以上面代碼的意思就是通過對每個子View調用getLayoutParams方法,然後從該LayoutParams中獲取到它的PercentLayoutInfo屬性,然後再調用PercentLayoutInfo.fillMarginLayoutParams()方法。

那我們繼續看一下PercentLayoutInfo.fillMarginLayoutParams()方法的實現,該方法是根據百分比去設置尺寸和margin:

/**
         * 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
                        + ")");
            }
        }

再看一下PercentLayoutInfo.fillLayoutParams()的實現,該方法是通過百分比設置View的尺寸:

        /**
         * 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 + ")");
            }
        }

到這裡onMeasure中通過百分比值設置寬高以及margin的部分就看完了,那我們接著看一下關於百分比值過小時對wrap_content的處理:

if (mHelper.handleMeasuredStateTooSmall()) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

看一下PercentLayoutHelper.handleMeasuredStateTooSmall()方法的實現:

/**
     * 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;
    }

那繼續看一下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;
    }

繼續看ViewCompat.getMeasuredWidthAndState()的源碼:

public static int getMeasuredWidthAndState(View view) {
        return IMPL.getMeasuredWidthAndState(view);
    }

繼續往下看,這個IMPL是什麼呢?

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();
        }
    }

繼續看,IMPL.getMeasuredWidthAndState(),方法其實最終就是使用的BaseViewCompatImpl.getMeasuredWidthAndState()方法,接著看它的的源碼:

 @Override
        public int getMeasuredWidthAndState(View view) {
            return view.getMeasuredWidth();
        }

最後就是調用了getMeasuredWidth()方法。 沒毛病- -!

onMeasure的到這裡就分析完了。
那接著來看一下onLayout方法,onLayout方法直接調用了PercentLayoutHelper.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);
                    }
                }
            }
        }
    }

調用了PercentLayoutInfo.restoreMarginLayoutParams()方法,我們看下它的源碼:

/**
         * 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));
        }

意思是說,再他們被以百分比為基礎的數據更改之後恢復成原始的尺寸和margin。
然後繼續看一下restoreLayoutParams():

/**
         * 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;
        }

好了到這裡也分析完了onLayout的方法,大意就是在onMeasure之前先將原始的寬高和margin都備份一下,然後在onMeasure中根據百分比去設置對應的寬高和margin,等到設置完之後在onLayout方法中再去將這些值恢復到之前備份的起始數據。說實話我沒看明白為什麼要這樣做?

通過上面的代碼分析我們知道對布局影響力的優先順序: app:layout_aspectRatio > app:layout_heightPercent > android:layout_height如果我們同時都設置這三個參數值的話,最終會用app:layout_aspectRatio的值。

遺留問題:

為什麼在onLayout方法中去恢復數據,這有什麼作用? 看代碼在處理如果指定的百分比過小但又指定wrap_content時,會重新根據wrap_content去重新計算的邏輯沒有錯,但是為什麼我在上面測試的時候確沒效果?

有知道上面這兩個問題的告訴我一下。


更多內容請關注Github

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved