ScaleFrameLayout.java revision 3595aa0cbdaa8e754365ca94a0b9eb8fc52b9796
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14package android.support.v17.leanback.widget; 15 16import android.content.Context; 17import android.graphics.drawable.Drawable; 18import android.util.AttributeSet; 19import android.view.Gravity; 20import android.view.View; 21import android.widget.FrameLayout; 22 23/** 24 * Subclass of FrameLayout that support scale layout area size for children. 25 * @hide 26 */ 27public class ScaleFrameLayout extends FrameLayout { 28 29 private static final int DEFAULT_CHILD_GRAVITY = Gravity.TOP | Gravity.START; 30 31 private float mLayoutScaleX = 1f; 32 private float mLayoutScaleY = 1f; 33 34 public ScaleFrameLayout(Context context) { 35 this(context ,null); 36 } 37 38 public ScaleFrameLayout(Context context, AttributeSet attrs) { 39 this(context, attrs, 0); 40 } 41 42 public ScaleFrameLayout(Context context, AttributeSet attrs, 43 int defStyle) { 44 super(context, attrs, defStyle); 45 } 46 47 public void setLayoutScaleX(float scaleX) { 48 if (scaleX != mLayoutScaleX) { 49 mLayoutScaleX = scaleX; 50 requestLayout(); 51 } 52 } 53 54 public void setLayoutScaleY(float scaleY) { 55 if (scaleY != mLayoutScaleY) { 56 mLayoutScaleY = scaleY; 57 requestLayout(); 58 } 59 } 60 61 @Override 62 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 63 final int count = getChildCount(); 64 65 final int parentLeft, parentRight; 66 final float pivotX = getPivotX(); 67 if (mLayoutScaleX != 1f) { 68 parentLeft = getPaddingLeft() + (int)(pivotX - pivotX / mLayoutScaleX + 0.5f); 69 parentRight = (int)(pivotX + (right - left - pivotX) / mLayoutScaleX + 0.5f) 70 - getPaddingRight(); 71 } else { 72 parentLeft = getPaddingLeft(); 73 parentRight = right - left - getPaddingRight(); 74 } 75 76 final int parentTop, parentBottom; 77 final float pivotY = getPivotY(); 78 if (mLayoutScaleY != 1f) { 79 parentTop = getPaddingTop() + (int)(pivotY - pivotY / mLayoutScaleY + 0.5f); 80 parentBottom = (int)(pivotY + (bottom - top - pivotY) / mLayoutScaleY + 0.5f) 81 - getPaddingBottom(); 82 } else { 83 parentTop = getPaddingTop(); 84 parentBottom = bottom - top - getPaddingBottom(); 85 } 86 87 for (int i = 0; i < count; i++) { 88 final View child = getChildAt(i); 89 if (child.getVisibility() != GONE) { 90 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 91 92 final int width = child.getMeasuredWidth(); 93 final int height = child.getMeasuredHeight(); 94 95 int childLeft; 96 int childTop; 97 98 int gravity = lp.gravity; 99 if (gravity == -1) { 100 gravity = DEFAULT_CHILD_GRAVITY; 101 } 102 103 final int layoutDirection = getLayoutDirection(); 104 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); 105 final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; 106 107 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { 108 case Gravity.CENTER_HORIZONTAL: 109 childLeft = parentLeft + (parentRight - parentLeft - width) / 2 + 110 lp.leftMargin - lp.rightMargin; 111 break; 112 case Gravity.RIGHT: 113 childLeft = parentRight - width - lp.rightMargin; 114 break; 115 case Gravity.LEFT: 116 default: 117 childLeft = parentLeft + lp.leftMargin; 118 } 119 120 switch (verticalGravity) { 121 case Gravity.TOP: 122 childTop = parentTop + lp.topMargin; 123 break; 124 case Gravity.CENTER_VERTICAL: 125 childTop = parentTop + (parentBottom - parentTop - height) / 2 + 126 lp.topMargin - lp.bottomMargin; 127 break; 128 case Gravity.BOTTOM: 129 childTop = parentBottom - height - lp.bottomMargin; 130 break; 131 default: 132 childTop = parentTop + lp.topMargin; 133 } 134 135 child.layout(childLeft, childTop, childLeft + width, childTop + height); 136 // synchronize child pivot to be same as ScaleFrameLayout's pivot 137 child.setPivotX(pivotX - childLeft); 138 child.setPivotY(pivotY - childTop); 139 } 140 } 141 } 142 143 private static int getScaledMeasureSpec(int measureSpec, float scale) { 144 return scale == 1f ? measureSpec : MeasureSpec.makeMeasureSpec( 145 (int) (MeasureSpec.getSize(measureSpec) / scale + 0.5f), 146 MeasureSpec.getMode(measureSpec)); 147 } 148 149 @Override 150 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 151 if (mLayoutScaleX != 1f || mLayoutScaleY != 1f) { 152 final int scaledWidthMeasureSpec = 153 getScaledMeasureSpec(widthMeasureSpec, mLayoutScaleX); 154 final int scaledHeightMeasureSpec = 155 getScaledMeasureSpec(heightMeasureSpec, mLayoutScaleY); 156 super.onMeasure(scaledWidthMeasureSpec, scaledHeightMeasureSpec); 157 setMeasuredDimension((int)(getMeasuredWidth() * mLayoutScaleX + 0.5f), 158 (int)(getMeasuredHeight() * mLayoutScaleY + 0.5f)); 159 } else { 160 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 161 } 162 } 163 164 /** 165 * setForeground() is not supported, throws UnsupportedOperationException() when called. 166 */ 167 @Override 168 public void setForeground(Drawable d) { 169 throw new UnsupportedOperationException(); 170 } 171} 172