1 /*
2  * Copyright (C) 2015 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 package android.support.car.ui;
17 
18 import android.content.Context;
19 import android.content.res.TypedArray;
20 import android.util.AttributeSet;
21 import android.view.View;
22 import android.widget.FrameLayout;
23 
24 import java.util.ArrayList;
25 import java.util.List;
26 
27 /**
28  * Acts as a container to make the width of all its children not larger than the setup max width.
29  *
30  * To use MaxWidthLayout, put it as the outermost layout of all children you want to limit its max
31  * width and set the maxWidth appropriately.
32  */
33 public class MaxWidthLayout extends FrameLayout {
34 
35     // If mMaxChildrenWidth == 0, it means that it doesn't set the max width, just use the current
36     // width directly.
37     private int mMaxChildrenWidth;
38 
MaxWidthLayout(Context context)39     public MaxWidthLayout(Context context) {
40         super(context);
41         initialize(context.obtainStyledAttributes(R.styleable.MaxWidthLayout));
42     }
43 
MaxWidthLayout(Context context, AttributeSet attrs)44     public MaxWidthLayout(Context context, AttributeSet attrs) {
45         super(context, attrs);
46         initialize(context.obtainStyledAttributes(attrs, R.styleable.MaxWidthLayout));
47     }
48 
MaxWidthLayout(Context context, AttributeSet attrs, int defStyleAttr)49     public MaxWidthLayout(Context context, AttributeSet attrs, int defStyleAttr) {
50         super(context, attrs, defStyleAttr);
51         initialize(context
52                 .obtainStyledAttributes(attrs, R.styleable.MaxWidthLayout, defStyleAttr, 0));
53     }
54 
55     /**
56      * Initialize MaxWidthLayout specific attributes and recycle the TypeArray.
57      */
initialize(TypedArray ta)58     private void initialize(TypedArray ta) {
59         mMaxChildrenWidth = (int) (ta.getDimension(R.styleable.MaxWidthLayout_carMaxWidth, 0));
60         ta.recycle();
61     }
62 
63     /**
64      * Re-measure the child width if it is greater than max width.
65      */
66     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)67     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
68         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
69         if (mMaxChildrenWidth == 0) {
70             return;
71         }
72 
73         final List<View> matchParentChildren = new ArrayList<View>();
74         for (int i = getChildCount() - 1; i >= 0; --i) {
75             final View child = getChildAt(i);
76             if (child.getVisibility() != GONE) {
77                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
78                 if (lp.width == LayoutParams.MATCH_PARENT) {
79                     matchParentChildren.add(child);
80                 }
81             }
82         }
83         for (int i = matchParentChildren.size() - 1; i >= 0; --i) {
84             final View child = matchParentChildren.get(i);
85             final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
86             if (child.getMeasuredWidth() > mMaxChildrenWidth) {
87                 int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
88                         mMaxChildrenWidth - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
89                 int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
90                         child.getMeasuredHeight(), MeasureSpec.EXACTLY);
91                 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
92             }
93         }
94     }
95 }
96