110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng/* 210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * Copyright (C) 2012 The Android Open Source Project 310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * 410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * you may not use this file except in compliance with the License. 610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * You may obtain a copy of the License at 710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * 810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * 1010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * Unless required by applicable law or agreed to in writing, software 1110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 1210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * See the License for the specific language governing permissions and 1410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * limitations under the License. 1510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng */ 1610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 1710392a75b43c34be8580a9fa101062201ce441d6Chiao Chengpackage com.android.contacts.common.widget; 1810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 1910392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.content.Context; 2010392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.content.res.TypedArray; 2110392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.util.AttributeSet; 2210392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.view.View; 2310392a75b43c34be8580a9fa101062201ce441d6Chiao Chengimport android.view.ViewGroup; 2410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 25baefde748cd02bde8934d66c34b3e1067745771dChiao Chengimport com.android.contacts.common.R; 2610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 2710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng/** 2810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * Layout that calculates its height based on its width, or vice versa (depending on the set 2910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * {@link #setDirection(Direction)}. The factor is specified in {@link #setRatio(float)}. 3010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * <p>For {@link Direction#heightToWidth}: width := height * factor</p> 3110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * <p>For {@link Direction#widthToHeight}: height := width * factor</p> 3210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * <p>Only one child is allowed; if more are required, another ViewGroup can be used as the direct 3310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * child of this layout.</p> 3410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng */ 3510392a75b43c34be8580a9fa101062201ce441d6Chiao Chengpublic class ProportionalLayout extends ViewGroup { 3610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng /** Specifies whether the width should be calculated based on the height or vice-versa */ 3710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public enum Direction { 3810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng widthToHeight("widthToHeight"), 3910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng heightToWidth("heightToWidth"); 4010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 4110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public final String XmlName; 4210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 4310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng private Direction(String xmlName) { 4410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng XmlName = xmlName; 4510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 4610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 4710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng /** 4810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * Parses the given direction string and returns the Direction instance. This 4910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng * should be used when inflating from xml 5010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng */ 5110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public static Direction parse(String value) { 5210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng if (widthToHeight.XmlName.equals(value)) { 5310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng return Direction.widthToHeight; 5410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } else if (heightToWidth.XmlName.equals(value)) { 5510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng return Direction.heightToWidth; 5610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } else { 5710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng throw new IllegalStateException("direction must be either " + 5810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng widthToHeight.XmlName + " or " + heightToWidth.XmlName); 5910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 6010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 6110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 6210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 6310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng private Direction mDirection; 6410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng private float mRatio; 6510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 6610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public ProportionalLayout(Context context) { 6710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng super(context); 6810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 6910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 7010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public ProportionalLayout(Context context, AttributeSet attrs) { 7110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng super(context, attrs); 7210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng initFromAttributes(context, attrs); 7310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 7410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 7510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public ProportionalLayout(Context context, AttributeSet attrs, int defStyle) { 7610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng super(context, attrs, defStyle); 7710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng initFromAttributes(context, attrs); 7810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 7910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 8010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng private void initFromAttributes(Context context, AttributeSet attrs) { 8110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProportionalLayout); 8210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 8310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng mDirection = Direction.parse(a.getString(R.styleable.ProportionalLayout_direction)); 8410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng mRatio = a.getFloat(R.styleable.ProportionalLayout_ratio, 1.0f); 8510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 8610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng a.recycle(); 8710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 8810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 8910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng @Override 9010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 9110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng if (getChildCount() != 1) { 9210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng throw new IllegalStateException("ProportionalLayout requires exactly one child"); 9310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 9410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 9510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng final View child = getChildAt(0); 9610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 9710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng // Do a first pass to get the optimal size 9810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng measureChild(child, widthMeasureSpec, heightMeasureSpec); 9910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng final int childWidth = child.getMeasuredWidth(); 10010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng final int childHeight = child.getMeasuredHeight(); 10110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 10210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng final int width; 10310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng final int height; 10410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng if (mDirection == Direction.heightToWidth) { 10510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng width = Math.round(childHeight * mRatio); 10610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng height = childHeight; 10710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } else { 10810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng width = childWidth; 10910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng height = Math.round(childWidth * mRatio); 11010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 11110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 11210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng // Do a second pass so that all children are informed of the new size 11310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng measureChild(child, 11410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 11510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); 11610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 11710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng setMeasuredDimension( 11810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec)); 11910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 12010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 12110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng @Override 12210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 12310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng if (getChildCount() != 1) { 12410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng throw new IllegalStateException("ProportionalLayout requires exactly one child"); 12510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 12610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 12710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng final View child = getChildAt(0); 12810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng child.layout(0, 0, right-left, bottom-top); 12910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 13010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 13110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public Direction getDirection() { 13210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng return mDirection; 13310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 13410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 13510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public void setDirection(Direction direction) { 13610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng mDirection = direction; 13710392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 13810392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 13910392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public float getRatio() { 14010392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng return mRatio; 14110392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 14210392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng 14310392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng public void setRatio(float ratio) { 14410392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng mRatio = ratio; 14510392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng } 14610392a75b43c34be8580a9fa101062201ce441d6Chiao Cheng} 147