[go: nahoru, domu]

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.view.ViewGroup;
22import android.widget.FrameLayout;
23
24/**
25 * Subclass of FrameLayout that support scale layout area size for children.
26 * @hide
27 */
28public 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
37    public ScaleFrameLayout(Context context) {
38        this(context ,null);
39    }
40
41    public ScaleFrameLayout(Context context, AttributeSet attrs) {
42        this(context, attrs, 0);
43    }
44
45    public ScaleFrameLayout(Context context, AttributeSet attrs,
46            int defStyle) {
47        super(context, attrs, defStyle);
48    }
49
50    public void setLayoutScaleX(float scaleX) {
51        if (scaleX != mLayoutScaleX) {
52            mLayoutScaleX = scaleX;
53            requestLayout();
54        }
55    }
56
57    public void setLayoutScaleY(float scaleY) {
58        if (scaleY != mLayoutScaleY) {
59            mLayoutScaleY = scaleY;
60            requestLayout();
61        }
62    }
63
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
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
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
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
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
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
201    public void setForeground(Drawable d) {
202        throw new UnsupportedOperationException();
203    }
204
205}
206