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 17 package com.android.internal.widget; 18 19 import android.content.Context; 20 import android.graphics.drawable.Drawable; 21 import android.util.AttributeSet; 22 import android.view.View; 23 import android.widget.ViewAnimator; 24 25 import java.util.ArrayList; 26 27 /** 28 * ViewAnimator with a more reasonable handling of MATCH_PARENT. 29 */ 30 public class DialogViewAnimator extends ViewAnimator { 31 private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1); 32 DialogViewAnimator(Context context)33 public DialogViewAnimator(Context context) { 34 super(context); 35 } 36 DialogViewAnimator(Context context, AttributeSet attrs)37 public DialogViewAnimator(Context context, AttributeSet attrs) { 38 super(context, attrs); 39 } 40 41 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)42 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 43 final boolean measureMatchParentChildren = 44 MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY || 45 MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY; 46 47 int maxHeight = 0; 48 int maxWidth = 0; 49 int childState = 0; 50 51 // First measure all children and record maximum dimensions where the 52 // spec isn't MATCH_PARENT. 53 final int count = getChildCount(); 54 for (int i = 0; i < count; i++) { 55 final View child = getChildAt(i); 56 if (getMeasureAllChildren() || child.getVisibility() != GONE) { 57 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 58 final boolean matchWidth = lp.width == LayoutParams.MATCH_PARENT; 59 final boolean matchHeight = lp.height == LayoutParams.MATCH_PARENT; 60 if (measureMatchParentChildren && (matchWidth || matchHeight)) { 61 mMatchParentChildren.add(child); 62 } 63 64 measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); 65 66 // Measured dimensions only count against the maximum 67 // dimensions if they're not MATCH_PARENT. 68 int state = 0; 69 70 if (measureMatchParentChildren && !matchWidth) { 71 maxWidth = Math.max(maxWidth, child.getMeasuredWidth() 72 + lp.leftMargin + lp.rightMargin); 73 state |= child.getMeasuredWidthAndState() & MEASURED_STATE_MASK; 74 } 75 76 if (measureMatchParentChildren && !matchHeight) { 77 maxHeight = Math.max(maxHeight, child.getMeasuredHeight() 78 + lp.topMargin + lp.bottomMargin); 79 state |= (child.getMeasuredHeightAndState() >> MEASURED_HEIGHT_STATE_SHIFT) 80 & (MEASURED_STATE_MASK >> MEASURED_HEIGHT_STATE_SHIFT); 81 } 82 83 childState = combineMeasuredStates(childState, state); 84 } 85 } 86 87 // Account for padding too. 88 maxWidth += getPaddingLeft() + getPaddingRight(); 89 maxHeight += getPaddingTop() + getPaddingBottom(); 90 91 // Check against our minimum height and width. 92 maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); 93 maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); 94 95 // Check against our foreground's minimum height and width. 96 final Drawable drawable = getForeground(); 97 if (drawable != null) { 98 maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); 99 maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); 100 } 101 102 setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), 103 resolveSizeAndState(maxHeight, heightMeasureSpec, 104 childState << MEASURED_HEIGHT_STATE_SHIFT)); 105 106 // Measure remaining MATCH_PARENT children again using real dimensions. 107 final int matchCount = mMatchParentChildren.size(); 108 for (int i = 0; i < matchCount; i++) { 109 final View child = mMatchParentChildren.get(i); 110 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); 111 112 final int childWidthMeasureSpec; 113 if (lp.width == LayoutParams.MATCH_PARENT) { 114 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( 115 getMeasuredWidth() - getPaddingLeft() - getPaddingRight() 116 - lp.leftMargin - lp.rightMargin, 117 MeasureSpec.EXACTLY); 118 } else { 119 childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 120 getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin, 121 lp.width); 122 } 123 124 final int childHeightMeasureSpec; 125 if (lp.height == LayoutParams.MATCH_PARENT) { 126 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( 127 getMeasuredHeight() - getPaddingTop() - getPaddingBottom() 128 - lp.topMargin - lp.bottomMargin, 129 MeasureSpec.EXACTLY); 130 } else { 131 childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 132 getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin, 133 lp.height); 134 } 135 136 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 137 } 138 139 mMatchParentChildren.clear(); 140 } 141 } 142