• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
14 package android.support.v17.leanback.widget;
15 
16 import android.content.Context;
17 import android.graphics.drawable.Drawable;
18 import android.util.AttributeSet;
19 import android.view.Gravity;
20 import android.view.View;
21 import android.view.ViewGroup;
22 import android.widget.FrameLayout;
23 
24 /**
25  * Subclass of FrameLayout that support scale layout area size for children.
26  * @hide
27  */
28 public class ScaleFrameLayout extends FrameLayout {
29 
30     private static final int DEFAULT_CHILD_GRAVITY = Gravity.TOP | Gravity.START;
31 
32     private float mLayoutScaleX = 1f;
33     private float mLayoutScaleY = 1f;
34 
35     private float mChildScale = 1f;
36 
ScaleFrameLayout(Context context)37     public ScaleFrameLayout(Context context) {
38         this(context ,null);
39     }
40 
ScaleFrameLayout(Context context, AttributeSet attrs)41     public ScaleFrameLayout(Context context, AttributeSet attrs) {
42         this(context, attrs, 0);
43     }
44 
ScaleFrameLayout(Context context, AttributeSet attrs, int defStyle)45     public ScaleFrameLayout(Context context, AttributeSet attrs,
46             int defStyle) {
47         super(context, attrs, defStyle);
48     }
49 
setLayoutScaleX(float scaleX)50     public void setLayoutScaleX(float scaleX) {
51         if (scaleX != mLayoutScaleX) {
52             mLayoutScaleX = scaleX;
53             requestLayout();
54         }
55     }
56 
setLayoutScaleY(float scaleY)57     public void setLayoutScaleY(float scaleY) {
58         if (scaleY != mLayoutScaleY) {
59             mLayoutScaleY = scaleY;
60             requestLayout();
61         }
62     }
63 
setChildScale(float scale)64     public void setChildScale(float scale) {
65         if (mChildScale != scale) {
66             mChildScale = scale;
67             for (int i = 0; i < getChildCount(); i++) {
68                 getChildAt(i).setScaleX(scale);
69                 getChildAt(i).setScaleY(scale);
70             }
71         }
72     }
73 
74     @Override
addView(View child, int index, ViewGroup.LayoutParams params)75     public void addView(View child, int index, ViewGroup.LayoutParams params) {
76         super.addView(child, index, params);
77         child.setScaleX(mChildScale);
78         child.setScaleY(mChildScale);
79     }
80 
81     @Override
addViewInLayout(View child, int index, ViewGroup.LayoutParams params, boolean preventRequestLayout)82     protected boolean addViewInLayout (View child, int index, ViewGroup.LayoutParams params,
83             boolean preventRequestLayout) {
84         boolean ret = super.addViewInLayout(child, index, params, preventRequestLayout);
85         if (ret) {
86             child.setScaleX(mChildScale);
87             child.setScaleY(mChildScale);
88         }
89         return ret;
90     }
91 
92     @Override
onLayout(boolean changed, int left, int top, int right, int bottom)93     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
94         final int count = getChildCount();
95 
96         final int parentLeft, parentRight;
97         final int layoutDirection = getLayoutDirection();
98         final float pivotX = (layoutDirection == View.LAYOUT_DIRECTION_RTL) ?
99                 getWidth() - getPivotX() :
100                 getPivotX();
101         if (mLayoutScaleX != 1f) {
102             parentLeft = getPaddingLeft() + (int)(pivotX - pivotX / mLayoutScaleX + 0.5f);
103             parentRight = (int)(pivotX + (right - left - pivotX) / mLayoutScaleX + 0.5f)
104                     - getPaddingRight();
105         } else {
106             parentLeft = getPaddingLeft();
107             parentRight = right - left - getPaddingRight();
108         }
109 
110         final int parentTop, parentBottom;
111         final float pivotY = getPivotY();
112         if (mLayoutScaleY != 1f) {
113             parentTop = getPaddingTop() + (int)(pivotY - pivotY / mLayoutScaleY + 0.5f);
114             parentBottom = (int)(pivotY + (bottom - top - pivotY) / mLayoutScaleY + 0.5f)
115                     - getPaddingBottom();
116         } else {
117             parentTop = getPaddingTop();
118             parentBottom = bottom - top - getPaddingBottom();
119         }
120 
121         for (int i = 0; i < count; i++) {
122             final View child = getChildAt(i);
123             if (child.getVisibility() != GONE) {
124                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
125 
126                 final int width = child.getMeasuredWidth();
127                 final int height = child.getMeasuredHeight();
128 
129                 int childLeft;
130                 int childTop;
131 
132                 int gravity = lp.gravity;
133                 if (gravity == -1) {
134                     gravity = DEFAULT_CHILD_GRAVITY;
135                 }
136 
137                 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
138                 final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
139 
140                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
141                     case Gravity.CENTER_HORIZONTAL:
142                         childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
143                                 lp.leftMargin - lp.rightMargin;
144                         break;
145                     case Gravity.RIGHT:
146                         childLeft = parentRight - width - lp.rightMargin;
147                         break;
148                     case Gravity.LEFT:
149                     default:
150                         childLeft = parentLeft + lp.leftMargin;
151                 }
152 
153                 switch (verticalGravity) {
154                     case Gravity.TOP:
155                         childTop = parentTop + lp.topMargin;
156                         break;
157                     case Gravity.CENTER_VERTICAL:
158                         childTop = parentTop + (parentBottom - parentTop - height) / 2 +
159                                 lp.topMargin - lp.bottomMargin;
160                         break;
161                     case Gravity.BOTTOM:
162                         childTop = parentBottom - height - lp.bottomMargin;
163                         break;
164                     default:
165                         childTop = parentTop + lp.topMargin;
166                 }
167 
168                 child.layout(childLeft, childTop, childLeft + width, childTop + height);
169                 // synchronize child pivot to be same as ScaleFrameLayout's pivot
170                 child.setPivotX(pivotX - childLeft);
171                 child.setPivotY(pivotY - childTop);
172             }
173         }
174     }
175 
getScaledMeasureSpec(int measureSpec, float scale)176     private static int getScaledMeasureSpec(int measureSpec, float scale) {
177         return scale == 1f ? measureSpec : MeasureSpec.makeMeasureSpec(
178                 (int) (MeasureSpec.getSize(measureSpec) / scale + 0.5f),
179                 MeasureSpec.getMode(measureSpec));
180     }
181 
182     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)183     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
184         if (mLayoutScaleX != 1f || mLayoutScaleY != 1f) {
185             final int scaledWidthMeasureSpec =
186                     getScaledMeasureSpec(widthMeasureSpec, mLayoutScaleX);
187             final int scaledHeightMeasureSpec =
188                     getScaledMeasureSpec(heightMeasureSpec, mLayoutScaleY);
189             super.onMeasure(scaledWidthMeasureSpec, scaledHeightMeasureSpec);
190             setMeasuredDimension((int)(getMeasuredWidth() * mLayoutScaleX + 0.5f),
191                     (int)(getMeasuredHeight() * mLayoutScaleY + 0.5f));
192         } else {
193             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
194         }
195     }
196 
197     /**
198      * setForeground() is not supported,  throws UnsupportedOperationException() when called.
199      */
200     @Override
setForeground(Drawable d)201     public void setForeground(Drawable d) {
202         throw new UnsupportedOperationException();
203     }
204 
205 }
206