12da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam/* 22da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * Copyright (C) 2017 The Android Open Source Project 32da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * 42da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * Licensed under the Apache License, Version 2.0 (the "License"); 52da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * you may not use this file except in compliance with the License. 62da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * You may obtain a copy of the License at 72da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * 82da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * http://www.apache.org/licenses/LICENSE-2.0 92da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * 102da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * Unless required by applicable law or agreed to in writing, software 112da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * distributed under the License is distributed on an "AS IS" BASIS, 122da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * See the License for the specific language governing permissions and 142da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * limitations under the License. 152da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam */ 162da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 172da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lampackage com.android.setupwizardlib.view; 182da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 192da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lamimport android.content.Context; 202da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lamimport android.content.res.TypedArray; 212da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lamimport android.util.AttributeSet; 222da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lamimport android.view.View; 232da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lamimport android.widget.FrameLayout; 242da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 252da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lamimport com.android.setupwizardlib.R; 262da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 272da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam/** 282da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * A layout that will measure its children size based on the space it is given, by using its 292da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * {@code android:minWidth}, {@code android:minHeight}, {@code android:maxWidth}, and 302da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * {@code android:maxHeight} values. 312da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * 322da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * <p>Typically this is used to show an illustration image or video on the screen. For optimal UX, 332da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * those assets typically want to occupy the remaining space available on screen within a certain 342da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * range, and then stop scaling beyond the min/max size attributes. Therefore this view is typically 352da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * used inside a ScrollView with {@code fillViewport} set to true, together with a linear layout 362da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * weight or relative layout to fill the remaining space visible on screen. 372da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * 382da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * <p>When measuring, this view ignores its children and simply layout according to the minWidth / 392da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * minHeight given. Therefore it is common for children of this layout to have width / height set to 402da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * {@code match_parent}. The maxWidth / maxHeight values will then be applied to the children to 412da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam * make sure they are not too big. 422da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam */ 432da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lampublic class FillContentLayout extends FrameLayout { 442da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 452da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam private int mMaxWidth; 462da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam private int mMaxHeight; 472da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 482da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam public FillContentLayout(Context context) { 492da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam this(context, null); 502da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } 512da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 522da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam public FillContentLayout(Context context, AttributeSet attrs) { 532da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam this(context, attrs, R.attr.suwFillContentLayoutStyle); 542da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } 552da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 562da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam public FillContentLayout(Context context, AttributeSet attrs, int defStyleAttr) { 572da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam super(context, attrs, defStyleAttr); 582da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam init(context, attrs, defStyleAttr); 592da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } 602da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 612da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam private void init(Context context, AttributeSet attrs, int defStyleAttr) { 622da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam TypedArray a = context.obtainStyledAttributes( 632da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam attrs, 642da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam R.styleable.SuwFillContentLayout, 652da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam defStyleAttr, 662da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 0); 672da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 682da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam mMaxHeight = a.getDimensionPixelSize( 692da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam R.styleable.SuwFillContentLayout_android_maxHeight, -1); 702da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam mMaxWidth = a.getDimensionPixelSize(R.styleable.SuwFillContentLayout_android_maxWidth, -1); 712da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 722da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam a.recycle(); 732da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } 742da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 752da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam @Override 762da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 772da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // Measure this view with the minWidth and minHeight, without asking the children. 782da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // (Children size is the drawable's intrinsic size, and we don't want that to influence 792da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // the size of the illustration). 802da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam setMeasuredDimension( 812da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 822da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 832da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 842da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam int childCount = getChildCount(); 852da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam for (int i = 0; i < childCount; i++) { 862da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam measureIllustrationChild(getChildAt(i), getMeasuredWidth(), getMeasuredHeight()); 872da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } 882da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } 892da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 902da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam private void measureIllustrationChild(View child, int parentWidth, int parentHeight) { 912da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // Modified from ViewGroup#measureChildWithMargins 922da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); 932da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 942da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // Create measure specs that are no bigger than min(parentSize, maxSize) 952da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 962da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam int childWidthMeasureSpec = getMaxSizeMeasureSpec( 972da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam Math.min(mMaxWidth, parentWidth), 982da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin, 992da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam lp.width); 1002da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam int childHeightMeasureSpec = getMaxSizeMeasureSpec( 1012da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam Math.min(mMaxHeight, parentHeight), 1022da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin, 1032da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam lp.height); 1042da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 1052da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 1062da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } 1072da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 1082da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam private static int getMaxSizeMeasureSpec(int maxSize, int padding, int childDimension) { 1092da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // Modified from ViewGroup#getChildMeasureSpec 1102da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam int size = Math.max(0, maxSize - padding); 1112da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam 1122da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam if (childDimension >= 0) { 1132da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // Child wants a specific size... so be it 1142da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam return MeasureSpec.makeMeasureSpec(childDimension, MeasureSpec.EXACTLY); 1152da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } else if (childDimension == LayoutParams.MATCH_PARENT) { 1162da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // Child wants to be our size. So be it. 1172da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); 1182da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } else if (childDimension == LayoutParams.WRAP_CONTENT) { 1192da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // Child wants to determine its own size. It can't be 1202da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam // bigger than us. 1212da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam return MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST); 1222da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } 1232da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam return 0; 1242da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam } 1252da78450d5e9723ca93fa39bfdc3f8dd27b41e89Maurice Lam} 126