• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.android.setupdesign.view;
18 
19 import android.annotation.TargetApi;
20 import android.content.Context;
21 import android.content.res.TypedArray;
22 import android.os.Build.VERSION_CODES;
23 import android.util.AttributeSet;
24 import android.widget.FrameLayout;
25 import com.google.android.setupdesign.R;
26 
27 /**
28  * A FrameLayout subclass that has an "intrinsic size", which is the size it wants to be if that is
29  * within the constraints given by the parent. The intrinsic size can be set with the {@code
30  * android:width} and {@code android:height} attributes in XML.
31  *
32  * <p>Note that for the intrinsic size to be meaningful, {@code android:layout_width} and/or {@code
33  * android:layout_height} will need to be {@code wrap_content}.
34  */
35 public class IntrinsicSizeFrameLayout extends FrameLayout {
36 
37   private int intrinsicHeight = 0;
38   private int intrinsicWidth = 0;
39 
IntrinsicSizeFrameLayout(Context context)40   public IntrinsicSizeFrameLayout(Context context) {
41     super(context);
42     init(context, null, 0);
43   }
44 
IntrinsicSizeFrameLayout(Context context, AttributeSet attrs)45   public IntrinsicSizeFrameLayout(Context context, AttributeSet attrs) {
46     super(context, attrs);
47     init(context, attrs, 0);
48   }
49 
50   @TargetApi(VERSION_CODES.HONEYCOMB)
IntrinsicSizeFrameLayout(Context context, AttributeSet attrs, int defStyleAttr)51   public IntrinsicSizeFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
52     super(context, attrs, defStyleAttr);
53     init(context, attrs, defStyleAttr);
54   }
55 
init(Context context, AttributeSet attrs, int defStyleAttr)56   private void init(Context context, AttributeSet attrs, int defStyleAttr) {
57     final TypedArray a =
58         context.obtainStyledAttributes(
59             attrs, R.styleable.SudIntrinsicSizeFrameLayout, defStyleAttr, 0);
60     intrinsicHeight =
61         a.getDimensionPixelSize(R.styleable.SudIntrinsicSizeFrameLayout_android_height, 0);
62     intrinsicWidth =
63         a.getDimensionPixelSize(R.styleable.SudIntrinsicSizeFrameLayout_android_width, 0);
64     a.recycle();
65   }
66 
67   @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)68   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
69     super.onMeasure(
70         getIntrinsicMeasureSpec(widthMeasureSpec, intrinsicWidth),
71         getIntrinsicMeasureSpec(heightMeasureSpec, intrinsicHeight));
72   }
73 
getIntrinsicMeasureSpec(int measureSpec, int intrinsicSize)74   private int getIntrinsicMeasureSpec(int measureSpec, int intrinsicSize) {
75     if (intrinsicSize <= 0) {
76       // Intrinsic size is not set, just return the original spec
77       return measureSpec;
78     }
79     final int mode = MeasureSpec.getMode(measureSpec);
80     final int size = MeasureSpec.getSize(measureSpec);
81     if (mode == MeasureSpec.UNSPECIFIED) {
82       // Parent did not give any constraint, so we'll be the intrinsic size
83       return MeasureSpec.makeMeasureSpec(intrinsicHeight, MeasureSpec.EXACTLY);
84     } else if (mode == MeasureSpec.AT_MOST) {
85       // If intrinsic size is within parents constraint, take the intrinsic size.
86       // Otherwise take the parents size because that's closest to the intrinsic size.
87       return MeasureSpec.makeMeasureSpec(Math.min(size, intrinsicHeight), MeasureSpec.EXACTLY);
88     }
89     // Parent specified EXACTLY, or in all other cases, just return the original spec
90     return measureSpec;
91   }
92 }
93