17677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng/* 27677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * Copyright (C) 2012 The Android Open Source Project 37677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * 47677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 57677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * you may not use this file except in compliance with the License. 67677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * You may obtain a copy of the License at 77677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * 87677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 97677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * 107677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * Unless required by applicable law or agreed to in writing, software 117677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 127677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * See the License for the specific language governing permissions and 147677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * limitations under the License. 157677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng */ 167677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1769c182afb0e6d82a341a28b4317aa703af768906Gary Maipackage com.android.contacts.widget; 187677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 197677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.content.Context; 207677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.content.res.TypedArray; 217677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.util.AttributeSet; 227677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.view.View; 237677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengimport android.view.ViewGroup; 247677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 253f6a2444e0134b7380cdb2e13abf4bf1163336d0Arthur Wangimport com.android.contacts.R; 267677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 277677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng/** 287677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * Layout that calculates its height based on its width, or vice versa (depending on the set 297677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * {@link #setDirection(Direction)}. The factor is specified in {@link #setRatio(float)}. 307677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * <p>For {@link Direction#heightToWidth}: width := height * factor</p> 317677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * <p>For {@link Direction#widthToHeight}: height := width * factor</p> 327677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * <p>Only one child is allowed; if more are required, another ViewGroup can be used as the direct 337677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * child of this layout.</p> 347677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng */ 357677fb674f7528a974a0352d9029eb3462f99da2Chiao Chengpublic class ProportionalLayout extends ViewGroup { 367677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng /** Specifies whether the width should be calculated based on the height or vice-versa */ 377677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public enum Direction { 387677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng widthToHeight("widthToHeight"), 397677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng heightToWidth("heightToWidth"); 407677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 417677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public final String XmlName; 427677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 437677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng private Direction(String xmlName) { 447677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng XmlName = xmlName; 457677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 467677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 477677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng /** 487677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * Parses the given direction string and returns the Direction instance. This 497677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng * should be used when inflating from xml 507677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng */ 517677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public static Direction parse(String value) { 527677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng if (widthToHeight.XmlName.equals(value)) { 537677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng return Direction.widthToHeight; 547677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } else if (heightToWidth.XmlName.equals(value)) { 557677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng return Direction.heightToWidth; 567677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } else { 577677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng throw new IllegalStateException("direction must be either " + 587677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng widthToHeight.XmlName + " or " + heightToWidth.XmlName); 597677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 607677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 617677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 627677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 637677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng private Direction mDirection; 647677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng private float mRatio; 657677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 667677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public ProportionalLayout(Context context) { 677677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng super(context); 687677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 697677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 707677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public ProportionalLayout(Context context, AttributeSet attrs) { 717677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng super(context, attrs); 727677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng initFromAttributes(context, attrs); 737677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 747677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 757677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public ProportionalLayout(Context context, AttributeSet attrs, int defStyle) { 767677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng super(context, attrs, defStyle); 777677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng initFromAttributes(context, attrs); 787677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 797677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 807677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng private void initFromAttributes(Context context, AttributeSet attrs) { 817677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProportionalLayout); 827677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 837677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng mDirection = Direction.parse(a.getString(R.styleable.ProportionalLayout_direction)); 847677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng mRatio = a.getFloat(R.styleable.ProportionalLayout_ratio, 1.0f); 857677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 867677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng a.recycle(); 877677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 887677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 897677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng @Override 907677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 917677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng if (getChildCount() != 1) { 927677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng throw new IllegalStateException("ProportionalLayout requires exactly one child"); 937677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 947677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 957677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng final View child = getChildAt(0); 967677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 977677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng // Do a first pass to get the optimal size 987677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng measureChild(child, widthMeasureSpec, heightMeasureSpec); 997677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng final int childWidth = child.getMeasuredWidth(); 1007677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng final int childHeight = child.getMeasuredHeight(); 1017677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1027677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng final int width; 1037677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng final int height; 1047677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng if (mDirection == Direction.heightToWidth) { 1057677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng width = Math.round(childHeight * mRatio); 1067677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng height = childHeight; 1077677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } else { 1087677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng width = childWidth; 1097677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng height = Math.round(childWidth * mRatio); 1107677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 1117677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1127677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng // Do a second pass so that all children are informed of the new size 1137677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng measureChild(child, 1147677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 1157677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); 1167677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1177677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng setMeasuredDimension( 1187677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec)); 1197677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 1207677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1217677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng @Override 1227677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 1237677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng if (getChildCount() != 1) { 1247677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng throw new IllegalStateException("ProportionalLayout requires exactly one child"); 1257677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 1267677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1277677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng final View child = getChildAt(0); 1287677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng child.layout(0, 0, right-left, bottom-top); 1297677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 1307677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1317677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public Direction getDirection() { 1327677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng return mDirection; 1337677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 1347677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1357677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public void setDirection(Direction direction) { 1367677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng mDirection = direction; 1377677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 1387677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1397677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public float getRatio() { 1407677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng return mRatio; 1417677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 1427677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng 1437677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng public void setRatio(float ratio) { 1447677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng mRatio = ratio; 1457677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng } 1467677fb674f7528a974a0352d9029eb3462f99da2Chiao Cheng} 147