GridLayout.java revision fbd9997e681dedffa85831948b3f22dd47f09f2a
13f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/* 23f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Copyright (C) 2011 The Android Open Source Project 33f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 43f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Licensed under the Apache License, Version 2.0 (the "License"); 53f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * you may not use this file except in compliance with the License. 63f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * You may obtain a copy of the License at 73f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 83f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * http://www.apache.org/licenses/LICENSE-2.0 93f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Unless required by applicable law or agreed to in writing, software 113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * distributed under the License is distributed on an "AS IS" BASIS, 123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See the License for the specific language governing permissions and 143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * limitations under the License. 153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepackage android.widget; 183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbyeimport android.annotation.IntDef; 203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.Context; 213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.res.TypedArray; 223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Canvas; 233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Color; 241557fd7809078e421f751efc7d2539b3efdc54b2Philip Milneimport android.graphics.Insets; 253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Paint; 263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.AttributeSet; 273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.Log; 28211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milneimport android.util.LogPrinter; 2948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milneimport android.util.Pair; 30211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milneimport android.util.Printer; 313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.Gravity; 323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.View; 333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.ViewGroup; 34edd69518ffec87fb7b1931e708678ef441152cdePhilip Milneimport android.widget.RemoteViews.RemoteView; 3510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milneimport com.android.internal.R; 363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 37d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbyeimport java.lang.annotation.Retention; 38d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbyeimport java.lang.annotation.RetentionPolicy; 393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.lang.reflect.Array; 403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.ArrayList; 413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Arrays; 423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.HashMap; 433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.List; 443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Map; 453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 465125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milneimport static android.view.Gravity.*; 47899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.EXACTLY; 48899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.makeMeasureSpec; 493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.max; 503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.min; 513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/** 533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * A layout that places its children in a rectangular <em>grid</em>. 543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The grid is composed of a set of infinitely thin lines that separate the 563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced 577fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * by grid <em>indices</em>. A grid with {@code N} columns 587fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * has {@code N + 1} grid indices that run from {@code 0} 597fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * through {@code N} inclusive. Regardless of how GridLayout is 607fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * configured, grid index {@code 0} is fixed to the leading edge of the 617fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * container and grid index {@code N} is fixed to its trailing edge 623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * (after padding is taken into account). 633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 6493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <h4>Row and Column Specs</h4> 653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Children occupy one or more contiguous cells, as defined 6793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and 6893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters. 6993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Each spec defines the set of rows or columns that are to be 703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * occupied; and how children should be aligned within the resulting group of cells. 713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Although cells do not normally overlap in a GridLayout, GridLayout does 723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * not prevent children being defined to occupy the same cell or group of cells. 733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * In this case however, there is no guarantee that children will not themselves 743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * overlap after the layout operation completes. 753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Default Cell Assignment</h4> 773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 7848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne * If a child does not specify the row and column indices of the cell it 793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * wishes to occupy, GridLayout assigns cell locations automatically using its: 803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setOrientation(int) orientation}, 813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setRowCount(int) rowCount} and 823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setColumnCount(int) columnCount} properties. 833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Space</h4> 853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Space between children may be specified either by using instances of the 873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * dedicated {@link Space} view or by setting the 883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#leftMargin leftMargin}, 903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#topMargin topMargin}, 913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#rightMargin rightMargin} and 923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#bottomMargin bottomMargin} 933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters. When the 953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} 963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * property is set, default margins around children are automatically 97f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * allocated based on the prevailing UI style guide for the platform. 98f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Each of the margins so defined may be independently overridden by an assignment 993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to the appropriate layout parameter. 100f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Default values will generally produce a reasonable spacing between components 101f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * but values may change between different releases of the platform. 1023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 1033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Excess Space Distribution</h4> 1043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 10587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * As of API 21, GridLayout's distribution of excess space accomodates the principle of weight. 10687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * In the event that no weights are specified, the previous conventions are respected and 10787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * columns and rows are taken as flexible if their views specify some form of alignment 10887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * within their groups. 109f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p> 11087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * The flexibility of a view is therefore influenced by its alignment which is, 11187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * in turn, typically defined by setting the 11287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters. 11387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * If either a weight or alignment were defined along a given axis then the component 11487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * is taken as <em>flexible</em> in that direction. If no weight or alignment was set, 115f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * the component is instead assumed to be <em>inflexible</em>. 116f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p> 117f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Multiple components in the same row or column group are 118f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * considered to act in <em>parallel</em>. Such a 119899d5922870c78e0e663bc5661849eb468afc984Philip Milne * group is flexible only if <em>all</em> of the components 120899d5922870c78e0e663bc5661849eb468afc984Philip Milne * within it are flexible. Row and column groups that sit either side of a common boundary 121899d5922870c78e0e663bc5661849eb468afc984Philip Milne * are instead considered to act in <em>series</em>. The composite group made of these two 122899d5922870c78e0e663bc5661849eb468afc984Philip Milne * elements is flexible if <em>one</em> of its elements is flexible. 123899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p> 124899d5922870c78e0e663bc5661849eb468afc984Philip Milne * To make a column stretch, make sure all of the components inside it define a 12587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * weight or a gravity. To prevent a column from stretching, ensure that one of the components 12687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * in the column does not define a weight or a gravity. 1273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 128f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When the principle of flexibility does not provide complete disambiguation, 129f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em> 13087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * and <em>bottom</em> edges. To be more precise, GridLayout treats each of its layout 13187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * parameters as a constraint in the a set of variables that define the grid-lines along a 13287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * given axis. During layout, GridLayout solves the constraints so as to return the unique 13387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * solution to those constraints for which all variables are less-than-or-equal-to 13487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * the corresponding value in any other valid solution. 135f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 136a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * <h4>Interpretation of GONE</h4> 137a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * 138a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * For layout purposes, GridLayout treats views whose visibility status is 139a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * {@link View#GONE GONE}, as having zero width and height. This is subtly different from 140a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * the policy of ignoring views that are marked as GONE outright. If, for example, a gone-marked 141a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * view was alone in a column, that column would itself collapse to zero width if and only if 142a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * no gravity was defined on the view. If gravity was defined, then the gone-marked 143a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * view has no effect on the layout and the container should be laid out as if the view 1446dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar * had never been added to it. GONE views are taken to have zero weight during excess space 1456dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar * distribution. 1466dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar * <p> 147a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * These statements apply equally to rows as well as columns, and to groups of rows or columns. 148a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * 1493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 1503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See {@link GridLayout.LayoutParams} for a full description of the 1513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters used by GridLayout. 1523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 1533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation 1543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount 1553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount 1563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins 1573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved 1583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved 1593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 160edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne@RemoteView 1613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepublic class GridLayout extends ViewGroup { 1623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Public constants 1643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 165d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye /** @hide */ 166d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye @IntDef({HORIZONTAL, VERTICAL}) 167d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye @Retention(RetentionPolicy.SOURCE) 168d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye public @interface Orientation {} 169d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye 1703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The horizontal orientation. 1723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final int HORIZONTAL = LinearLayout.HORIZONTAL; 174aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The vertical orientation. 1773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final int VERTICAL = LinearLayout.VERTICAL; 1793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 180aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 181aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * The constant used to indicate that a value is undefined. 182aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * Fields can use this value to indicate that their values 183aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * have not yet been set. Similarly, methods can return this value 184aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * to indicate that there is no suitable value that the implementation 185aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * can return. 186aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * The value used for the constant (currently {@link Integer#MIN_VALUE}) is 187aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * intended to avoid confusion between valid values whose sign may not be known. 188aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 189aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public static final int UNDEFINED = Integer.MIN_VALUE; 190aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 191d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye /** @hide */ 192d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye @IntDef({ALIGN_BOUNDS, ALIGN_MARGINS}) 193d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye @Retention(RetentionPolicy.SOURCE) 194d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye public @interface AlignmentMode {} 195d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye 1961e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne /** 1971e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * This constant is an {@link #setAlignmentMode(int) alignmentMode}. 1981e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * When the {@code alignmentMode} is set to {@link #ALIGN_BOUNDS}, alignment 1991e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * is made between the edges of each component's raw 2001e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * view boundary: i.e. the area delimited by the component's: 2011e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getTop() top}, 2021e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getLeft() left}, 2031e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getBottom() bottom} and 2041e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getRight() right} properties. 2051e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * <p> 2061e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * For example, when {@code GridLayout} is in {@link #ALIGN_BOUNDS} mode, 2071e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * children that belong to a row group that uses {@link #TOP} alignment will 2081e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * all return the same value when their {@link android.view.View#getTop()} 2091e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * method is called. 2101e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 2111e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 2121e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne */ 2131e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public static final int ALIGN_BOUNDS = 0; 2141e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne 2151e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne /** 2161e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * This constant is an {@link #setAlignmentMode(int) alignmentMode}. 2171e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * When the {@code alignmentMode} is set to {@link #ALIGN_MARGINS}, 2181e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * the bounds of each view are extended outwards, according 2191e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * to their margins, before the edges of the resulting rectangle are aligned. 2201e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * <p> 2211e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * For example, when {@code GridLayout} is in {@link #ALIGN_MARGINS} mode, 2221e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * the quantity {@code top - layoutParams.topMargin} is the same for all children that 2231e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * belong to a row group that uses {@link #TOP} alignment. 2241e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 2251e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 2261e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne */ 2271e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public static final int ALIGN_MARGINS = 1; 2281e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne 2293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Misc constants 2303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 231f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final int MAX_SIZE = 100000; 232f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final int DEFAULT_CONTAINER_MARGIN = 0; 233d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne static final int UNINITIALIZED_HASH = 0; 234a2353621524472f71850a54b5a41188dd8281039Philip Milne static final Printer LOG_PRINTER = new LogPrinter(Log.DEBUG, GridLayout.class.getName()); 235a2353621524472f71850a54b5a41188dd8281039Philip Milne static final Printer NO_PRINTER = new Printer() { 236a2353621524472f71850a54b5a41188dd8281039Philip Milne @Override 237a2353621524472f71850a54b5a41188dd8281039Philip Milne public void println(String x) { 238a2353621524472f71850a54b5a41188dd8281039Philip Milne } 239a2353621524472f71850a54b5a41188dd8281039Philip Milne }; 2403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Defaults 2423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_ORIENTATION = HORIZONTAL; 2443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_COUNT = UNDEFINED; 2453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false; 246899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static final boolean DEFAULT_ORDER_PRESERVED = true; 2471e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS; 2483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // TypedArray indices 2503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 251b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ORIENTATION = R.styleable.GridLayout_orientation; 252b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW_COUNT = R.styleable.GridLayout_rowCount; 253b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount; 254b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins; 255b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode; 256b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved; 257b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved; 2583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Instance variables 2603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 261465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell final Axis mHorizontalAxis = new Axis(true); 262465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell final Axis mVerticalAxis = new Axis(false); 263465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int mOrientation = DEFAULT_ORIENTATION; 264465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS; 265465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int mAlignmentMode = DEFAULT_ALIGNMENT_MODE; 266465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int mDefaultGap; 267465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int mLastLayoutParamsHashCode = UNINITIALIZED_HASH; 268465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Printer mPrinter = LOG_PRINTER; 269aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Constructors 2713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 272d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette public GridLayout(Context context) { 273d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette this(context, null); 274d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette } 275d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette 276d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette public GridLayout(Context context, AttributeSet attrs) { 277d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette this(context, attrs, 0); 278d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette } 279d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette 280617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public GridLayout(Context context, AttributeSet attrs, int defStyleAttr) { 281617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette this(context, attrs, defStyleAttr, 0); 282617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette } 283617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette 284617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public GridLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 285617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 286465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap); 287617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette final TypedArray a = context.obtainStyledAttributes( 288617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette attrs, R.styleable.GridLayout, defStyleAttr, defStyleRes); 2893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne try { 2901e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT)); 2911e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT)); 2925125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne setOrientation(a.getInt(ORIENTATION, DEFAULT_ORIENTATION)); 2935125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne setUseDefaultMargins(a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS)); 2945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne setAlignmentMode(a.getInt(ALIGNMENT_MODE, DEFAULT_ALIGNMENT_MODE)); 2953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); 2963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); 2973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } finally { 2983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne a.recycle(); 2993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Implementation 3033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 3053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the current orientation. 3063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3077fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return either {@link #HORIZONTAL} or {@link #VERTICAL} 3083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setOrientation(int) 3103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation 3123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 313d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye @Orientation 3143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int getOrientation() { 315465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mOrientation; 3163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 319b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * 320b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * GridLayout uses the orientation property for two purposes: 321b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <ul> 322b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <li> 323b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * To control the 'direction' in which default row/column indices are generated 324b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * when they are not specified in a component's layout parameters. 325b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * </li> 326b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <li> 327b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * To control which axis should be processed first during the layout operation: 328b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * when orientation is {@link #HORIZONTAL} the horizontal axis is laid out first. 329b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * </li> 330b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * </ul> 331b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * 332b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * The order in which axes are laid out is important if, for example, the height of 333b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * one of GridLayout's children is dependent on its width - and its width is, in turn, 334b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * dependent on the widths of other components. 335b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <p> 336b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * If your layout contains a {@link TextView} (or derivative: 337b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * {@code Button}, {@code EditText}, {@code CheckBox}, etc.) which is 338b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * in multi-line mode (the default) it is normally best to leave GridLayout's 339b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * orientation as {@code HORIZONTAL} - because {@code TextView} is capable of 340b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * deriving its height for a given width, but not the other way around. 341b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <p> 342b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * Other than the effects above, orientation does not affect the actual layout operation of 343b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * GridLayout, so it's fine to leave GridLayout in {@code HORIZONTAL} mode even if 344b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * the height of the intended layout greatly exceeds its width. 3457fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 3467fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * The default value of this property is {@link #HORIZONTAL}. 3473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3487fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param orientation either {@link #HORIZONTAL} or {@link #VERTICAL} 3493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getOrientation() 3513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation 3533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 354d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye public void setOrientation(@Orientation int orientation) { 355465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (this.mOrientation != orientation) { 356465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell this.mOrientation = orientation; 357f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne invalidateStructure(); 3583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne requestLayout(); 3593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 3633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the current number of rows. This is either the last value that was set 3643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * with {@link #setRowCount(int)} or, if no such value was set, the maximum 36593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * value of each the upper bounds defined in {@link LayoutParams#rowSpec}. 3663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return the current number of rows 3683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setRowCount(int) 37093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#rowSpec 3713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount 3733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int getRowCount() { 375465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mVerticalAxis.getCount(); 3763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 379f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * RowCount is used only to generate default row/column indices when 380f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * they are not specified by a component's layout parameters. 3813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3827fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param rowCount the number of rows 3833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getRowCount() 38593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#rowSpec 3863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount 3883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setRowCount(int rowCount) { 390465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.setCount(rowCount); 391f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne invalidateStructure(); 392f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne requestLayout(); 3933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 3963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the current number of columns. This is either the last value that was set 3973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * with {@link #setColumnCount(int)} or, if no such value was set, the maximum 39893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * value of each the upper bounds defined in {@link LayoutParams#columnSpec}. 3993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return the current number of columns 4013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setColumnCount(int) 40393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#columnSpec 4043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount 4063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int getColumnCount() { 408465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mHorizontalAxis.getCount(); 4093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 4103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 4113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 412f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * ColumnCount is used only to generate default column/column indices when 413f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * they are not specified by a component's layout parameters. 4143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @param columnCount the number of columns. 4163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getColumnCount() 41893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#columnSpec 4193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount 4213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setColumnCount(int columnCount) { 423465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.setCount(columnCount); 424f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne invalidateStructure(); 425f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne requestLayout(); 4263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 4273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 4283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 4293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns whether or not this GridLayout will allocate default margins when no 4303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * corresponding layout parameters are defined. 4313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4327fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return {@code true} if default margins should be allocated 4333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setUseDefaultMargins(boolean) 4353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins 4373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean getUseDefaultMargins() { 439465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mUseDefaultMargins; 4403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 4413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 4423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 4437fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When {@code true}, GridLayout allocates default margins around children 4443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * based on the child's visual characteristics. Each of the 4453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * margins so defined may be independently overridden by an assignment 4463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to the appropriate layout parameter. 4473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 4487fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When {@code false}, the default value of all margins is zero. 449aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * <p> 4507fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When setting to {@code true}, consider setting the value of the 4511e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link #setAlignmentMode(int) alignmentMode} 4521e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * property to {@link #ALIGN_BOUNDS}. 4537fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 4547fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * The default value of this property is {@code false}. 4553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4567fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins 4573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getUseDefaultMargins() 4591e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 4603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#leftMargin 4623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#topMargin 4633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#rightMargin 4643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#bottomMargin 4653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins 4673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setUseDefaultMargins(boolean useDefaultMargins) { 469465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell this.mUseDefaultMargins = useDefaultMargins; 470aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 471aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 472aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 473aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 4741e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * Returns the alignment mode. 4751e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 4761e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @return the alignment mode; either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS} 477aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4781e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_BOUNDS 4791e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_MARGINS 480aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4811e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 482aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4831e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @attr ref android.R.styleable#GridLayout_alignmentMode 484aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 485d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye @AlignmentMode 4861e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public int getAlignmentMode() { 487465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mAlignmentMode; 488aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 489aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 490aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 4911e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * Sets the alignment mode to be used for all of the alignments between the 4921e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * children of this container. 4937fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 4941e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * The default value of this property is {@link #ALIGN_MARGINS}. 4951e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 4961e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @param alignmentMode either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS} 497aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4981e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_BOUNDS 4991e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_MARGINS 500aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 5011e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #getAlignmentMode() 502aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 5031e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @attr ref android.R.styleable#GridLayout_alignmentMode 504aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 505d9273d6f289d9b55da3fd0db2f659fdfb48106a8Tor Norbye public void setAlignmentMode(@AlignmentMode int alignmentMode) { 506465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell this.mAlignmentMode = alignmentMode; 507aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 5083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns whether or not row boundaries are ordered by their grid indices. 5123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5137fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return {@code true} if row boundaries must appear in the order of their indices, 5147fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false} otherwise 5153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setRowOrderPreserved(boolean) 5173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved 5193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean isRowOrderPreserved() { 521465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mVerticalAxis.isOrderPreserved(); 5223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5257fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When this property is {@code true}, GridLayout is forced to place the row boundaries 526aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * so that their associated grid indices are in ascending order in the view. 5273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 528899d5922870c78e0e663bc5661849eb468afc984Philip Milne * When this property is {@code false} GridLayout is at liberty to place the vertical row 529899d5922870c78e0e663bc5661849eb468afc984Philip Milne * boundaries in whatever order best fits the given constraints. 5307fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 531899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The default value of this property is {@code true}. 5327fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 5337fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param rowOrderPreserved {@code true} to force GridLayout to respect the order 5347fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * of row boundaries 5353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #isRowOrderPreserved() 5373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved 5393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setRowOrderPreserved(boolean rowOrderPreserved) { 541465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.setOrderPreserved(rowOrderPreserved); 542aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne invalidateStructure(); 543aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 5443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns whether or not column boundaries are ordered by their grid indices. 5483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5497fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return {@code true} if column boundaries must appear in the order of their indices, 5507fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false} otherwise 5513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setColumnOrderPreserved(boolean) 5533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved 5553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean isColumnOrderPreserved() { 557465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mHorizontalAxis.isOrderPreserved(); 5583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5617fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When this property is {@code true}, GridLayout is forced to place the column boundaries 562aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * so that their associated grid indices are in ascending order in the view. 5633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 564899d5922870c78e0e663bc5661849eb468afc984Philip Milne * When this property is {@code false} GridLayout is at liberty to place the horizontal column 565899d5922870c78e0e663bc5661849eb468afc984Philip Milne * boundaries in whatever order best fits the given constraints. 5667fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 567899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The default value of this property is {@code true}. 5683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5697fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param columnOrderPreserved use {@code true} to force GridLayout to respect the order 5703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * of column boundaries. 5713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #isColumnOrderPreserved() 5733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved 5753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setColumnOrderPreserved(boolean columnOrderPreserved) { 577465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.setOrderPreserved(columnOrderPreserved); 578aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne invalidateStructure(); 579aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 5803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 582211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne /** 583211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * Return the printer that will log diagnostics from this layout. 584211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * 585211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * @see #setPrinter(android.util.Printer) 586211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * 587211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * @return the printer associated with this view 588465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell * 589465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell * @hide 590211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne */ 591211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne public Printer getPrinter() { 592465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mPrinter; 593211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne } 594211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne 595211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne /** 596211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * Set the printer that will log diagnostics from this layout. 597211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * The default value is created by {@link android.util.LogPrinter}. 598211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * 599211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * @param printer the printer associated with this layout 600211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * 601211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * @see #getPrinter() 602465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell * 603465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell * @hide 604211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne */ 605211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne public void setPrinter(Printer printer) { 606465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell this.mPrinter = (printer == null) ? NO_PRINTER : printer; 607211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne } 608211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne 6095125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne // Static utility methods 6105125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 611f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static int max2(int[] a, int valueIfEmpty) { 61251f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne int result = valueIfEmpty; 61351f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne for (int i = 0, N = a.length; i < N; i++) { 61451f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne result = Math.max(result, a[i]); 61551f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne } 61651f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne return result; 61751f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne } 61851f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne 619899d5922870c78e0e663bc5661849eb468afc984Philip Milne @SuppressWarnings("unchecked") 620f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static <T> T[] append(T[] a, T[] b) { 62148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length); 62248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne System.arraycopy(a, 0, result, 0, a.length); 62348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne System.arraycopy(b, 0, result, a.length, b.length); 6243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 6253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 627f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static Alignment getAlignment(int gravity, boolean horizontal) { 6285125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK; 6295125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT; 6305125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int flags = (gravity & mask) >> shift; 6315125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne switch (flags) { 6325125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case (AXIS_SPECIFIED | AXIS_PULL_BEFORE): 6331557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne return horizontal ? LEFT : TOP; 6345125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case (AXIS_SPECIFIED | AXIS_PULL_AFTER): 6351557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne return horizontal ? RIGHT : BOTTOM; 6365125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER): 6375125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return FILL; 6385125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case AXIS_SPECIFIED: 6395125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return CENTER; 64047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | RELATIVE_LAYOUT_DIRECTION): 64147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio return START; 64247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio case (AXIS_SPECIFIED | AXIS_PULL_AFTER | RELATIVE_LAYOUT_DIRECTION): 64347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio return END; 6445125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne default: 6455125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return UNDEFINED_ALIGNMENT; 6465125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 6475125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 6485125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 6494c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne /** @noinspection UnusedParameters*/ 6501fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getDefaultMargin(View c, boolean horizontal, boolean leading) { 651899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (c.getClass() == Space.class) { 652899d5922870c78e0e663bc5661849eb468afc984Philip Milne return 0; 653899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 654465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mDefaultGap / 2; 6553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 6571fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) { 6587b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne return /*isAtEdge ? DEFAULT_CONTAINER_MARGIN :*/ getDefaultMargin(c, horizontal, leading); 6593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 6617a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) { 662465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (!mUseDefaultMargins) { 6633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return 0; 6643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 66593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? p.columnSpec : p.rowSpec; 666465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 66793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval span = spec.span; 66847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio boolean leading1 = (horizontal && isLayoutRtl()) ? !leading : leading; 66947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount()); 6703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 6711fd16378812792913a6aa6923acbec20037e09ffPhilip Milne return getDefaultMargin(c, isAtEdge, horizontal, leading); 6723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 674f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int getMargin1(View view, boolean horizontal, boolean leading) { 6753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne LayoutParams lp = getLayoutParams(view); 6763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int margin = horizontal ? 677aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne (leading ? lp.leftMargin : lp.rightMargin) : 678aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne (leading ? lp.topMargin : lp.bottomMargin); 6797a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne return margin == UNDEFINED ? getDefaultMargin(view, lp, horizontal, leading) : margin; 6801fd16378812792913a6aa6923acbec20037e09ffPhilip Milne } 6811fd16378812792913a6aa6923acbec20037e09ffPhilip Milne 6824c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne private int getMargin(View view, boolean horizontal, boolean leading) { 683465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (mAlignmentMode == ALIGN_MARGINS) { 6844c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return getMargin1(view, horizontal, leading); 6854c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne } else { 686465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 6874c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins(); 6884c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne LayoutParams lp = getLayoutParams(view); 6894c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 6904c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int index = leading ? spec.span.min : spec.span.max; 6914c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return margins[index]; 6924c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne } 6934c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne } 6944c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne 6951fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getTotalMargin(View child, boolean horizontal) { 6961fd16378812792913a6aa6923acbec20037e09ffPhilip Milne return getMargin(child, horizontal, true) + getMargin(child, horizontal, false); 6973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 699899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static boolean fits(int[] a, int value, int start, int end) { 700899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (end > a.length) { 701899d5922870c78e0e663bc5661849eb468afc984Philip Milne return false; 702899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 703899d5922870c78e0e663bc5661849eb468afc984Philip Milne for (int i = start; i < end; i++) { 704899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (a[i] > value) { 705899d5922870c78e0e663bc5661849eb468afc984Philip Milne return false; 7063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 707899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 708899d5922870c78e0e663bc5661849eb468afc984Philip Milne return true; 709899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 7103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 711899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static void procrusteanFill(int[] a, int start, int end, int value) { 712899d5922870c78e0e663bc5661849eb468afc984Philip Milne int length = a.length; 713899d5922870c78e0e663bc5661849eb468afc984Philip Milne Arrays.fill(a, Math.min(start, length), Math.min(end, length), value); 714899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 7153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 716899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static void setCellGroup(LayoutParams lp, int row, int rowSpan, int col, int colSpan) { 717899d5922870c78e0e663bc5661849eb468afc984Philip Milne lp.setRowSpecSpan(new Interval(row, row + rowSpan)); 718899d5922870c78e0e663bc5661849eb468afc984Philip Milne lp.setColumnSpecSpan(new Interval(col, col + colSpan)); 719899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 7203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 721899d5922870c78e0e663bc5661849eb468afc984Philip Milne // Logic to avert infinite loops by ensuring that the cells can be placed somewhere. 722899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static int clip(Interval minorRange, boolean minorWasDefined, int count) { 723899d5922870c78e0e663bc5661849eb468afc984Philip Milne int size = minorRange.size(); 724899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (count == 0) { 725899d5922870c78e0e663bc5661849eb468afc984Philip Milne return size; 726899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 727899d5922870c78e0e663bc5661849eb468afc984Philip Milne int min = minorWasDefined ? min(minorRange.min, count) : 0; 728899d5922870c78e0e663bc5661849eb468afc984Philip Milne return min(size, count - min); 729899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 730f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne 731899d5922870c78e0e663bc5661849eb468afc984Philip Milne // install default indices for cells that don't define them 732899d5922870c78e0e663bc5661849eb468afc984Philip Milne private void validateLayoutParams() { 733465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell final boolean horizontal = (mOrientation == HORIZONTAL); 734465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell final Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 735782c04b864dc5f71f7ec0c8e36cbaf5b838dc69cJim Miller final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0; 736f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne 737899d5922870c78e0e663bc5661849eb468afc984Philip Milne int major = 0; 738899d5922870c78e0e663bc5661849eb468afc984Philip Milne int minor = 0; 739899d5922870c78e0e663bc5661849eb468afc984Philip Milne int[] maxSizes = new int[count]; 740f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne 741899d5922870c78e0e663bc5661849eb468afc984Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 742d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); 743899d5922870c78e0e663bc5661849eb468afc984Philip Milne 744f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec; 745f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Interval majorRange = majorSpec.span; 746f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean majorWasDefined = majorSpec.startDefined; 747899d5922870c78e0e663bc5661849eb468afc984Philip Milne final int majorSpan = majorRange.size(); 748899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (majorWasDefined) { 749899d5922870c78e0e663bc5661849eb468afc984Philip Milne major = majorRange.min; 750899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 751899d5922870c78e0e663bc5661849eb468afc984Philip Milne 752f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec; 753f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Interval minorRange = minorSpec.span; 754f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean minorWasDefined = minorSpec.startDefined; 755899d5922870c78e0e663bc5661849eb468afc984Philip Milne final int minorSpan = clip(minorRange, minorWasDefined, count); 756899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (minorWasDefined) { 757899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor = minorRange.min; 758899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 759899d5922870c78e0e663bc5661849eb468afc984Philip Milne 760899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (count != 0) { 761899d5922870c78e0e663bc5661849eb468afc984Philip Milne // Find suitable row/col values when at least one is undefined. 762899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (!majorWasDefined || !minorWasDefined) { 763899d5922870c78e0e663bc5661849eb468afc984Philip Milne while (!fits(maxSizes, major, minor, minor + minorSpan)) { 764899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (minorWasDefined) { 765899d5922870c78e0e663bc5661849eb468afc984Philip Milne major++; 766899d5922870c78e0e663bc5661849eb468afc984Philip Milne } else { 767899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (minor + minorSpan <= count) { 768899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor++; 769899d5922870c78e0e663bc5661849eb468afc984Philip Milne } else { 770899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor = 0; 771899d5922870c78e0e663bc5661849eb468afc984Philip Milne major++; 772899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 773f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne } 774f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne } 7753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 776899d5922870c78e0e663bc5661849eb468afc984Philip Milne procrusteanFill(maxSizes, minor, minor + minorSpan, major + majorSpan); 7773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 778899d5922870c78e0e663bc5661849eb468afc984Philip Milne 779899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (horizontal) { 780899d5922870c78e0e663bc5661849eb468afc984Philip Milne setCellGroup(lp, major, majorSpan, minor, minorSpan); 781899d5922870c78e0e663bc5661849eb468afc984Philip Milne } else { 782899d5922870c78e0e663bc5661849eb468afc984Philip Milne setCellGroup(lp, minor, minorSpan, major, majorSpan); 783899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 784899d5922870c78e0e663bc5661849eb468afc984Philip Milne 785899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor = minor + minorSpan; 786899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 7873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void invalidateStructure() { 790465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mLastLayoutParamsHashCode = UNINITIALIZED_HASH; 791465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.invalidateStructure(); 792465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.invalidateStructure(); 793899d5922870c78e0e663bc5661849eb468afc984Philip Milne // This can end up being done twice. Better twice than not at all. 7943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateValues(); 7953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void invalidateValues() { 798aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne // Need null check because requestLayout() is called in View's initializer, 799aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne // before we are set up. 800465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (mHorizontalAxis != null && mVerticalAxis != null) { 801465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.invalidateValues(); 802465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.invalidateValues(); 803aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 8043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 806d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne /** @hide */ 807d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne @Override 808d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne protected void onSetLayoutParams(View child, ViewGroup.LayoutParams layoutParams) { 809d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne super.onSetLayoutParams(child, layoutParams); 8100f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8110f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (!checkLayoutParams(layoutParams)) { 8120f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams("supplied LayoutParams are of the wrong type"); 8130f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8140f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 815d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne invalidateStructure(); 8163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 818f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final LayoutParams getLayoutParams(View c) { 819d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne return (LayoutParams) c.getLayoutParams(); 8203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8220f57cea8989cc03bcae19b621096e50b035b7308Philip Milne private static void handleInvalidParams(String msg) { 8230f57cea8989cc03bcae19b621096e50b035b7308Philip Milne throw new IllegalArgumentException(msg + ". "); 8240f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8250f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8260f57cea8989cc03bcae19b621096e50b035b7308Philip Milne private void checkLayoutParams(LayoutParams lp, boolean horizontal) { 8270f57cea8989cc03bcae19b621096e50b035b7308Philip Milne String groupName = horizontal ? "column" : "row"; 8280f57cea8989cc03bcae19b621096e50b035b7308Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 8290f57cea8989cc03bcae19b621096e50b035b7308Philip Milne Interval span = spec.span; 8300f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (span.min != UNDEFINED && span.min < 0) { 8310f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams(groupName + " indices must be positive"); 8320f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 833465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 8340f57cea8989cc03bcae19b621096e50b035b7308Philip Milne int count = axis.definedCount; 8350f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (count != UNDEFINED) { 8360f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (span.max > count) { 8370f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams(groupName + 8380f57cea8989cc03bcae19b621096e50b035b7308Philip Milne " indices (start + span) mustn't exceed the " + groupName + " count"); 8390f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8400f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (span.size() > count) { 8410f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams(groupName + " span mustn't exceed the " + groupName + " count"); 8420f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8430f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8440f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8450f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8460f57cea8989cc03bcae19b621096e50b035b7308Philip Milne @Override 8470f57cea8989cc03bcae19b621096e50b035b7308Philip Milne protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 8480f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (!(p instanceof LayoutParams)) { 8490f57cea8989cc03bcae19b621096e50b035b7308Philip Milne return false; 8500f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8510f57cea8989cc03bcae19b621096e50b035b7308Philip Milne LayoutParams lp = (LayoutParams) p; 8520f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8530f57cea8989cc03bcae19b621096e50b035b7308Philip Milne checkLayoutParams(lp, true); 8540f57cea8989cc03bcae19b621096e50b035b7308Philip Milne checkLayoutParams(lp, false); 8550f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8560f57cea8989cc03bcae19b621096e50b035b7308Philip Milne return true; 8570f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8580f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 8603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected LayoutParams generateDefaultLayoutParams() { 8613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return new LayoutParams(); 8623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 8653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams generateLayoutParams(AttributeSet attrs) { 8665125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return new LayoutParams(getContext(), attrs); 8673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 8703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 8713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return new LayoutParams(p); 8723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Draw grid 8753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) { 87747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio if (isLayoutRtl()) { 87847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio int width = getWidth(); 8797b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne graphics.drawLine(width - x1, y1, width - x2, y2, paint); 88047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio } else { 8817b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne graphics.drawLine(x1, y1, x2, y2, paint); 88247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio } 8833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 88510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne /** 88610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne * @hide 88710ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne */ 88810ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne @Override 8897b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne protected void onDebugDrawMargins(Canvas canvas, Paint paint) { 89010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne // Apply defaults, so as to remove UNDEFINED values 89110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne LayoutParams lp = new LayoutParams(); 89210ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne for (int i = 0; i < getChildCount(); i++) { 89310ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne View c = getChildAt(i); 89410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne lp.setMargins( 8957b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne getMargin1(c, true, true), 8967b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne getMargin1(c, false, true), 8977b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne getMargin1(c, true, false), 8987b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne getMargin1(c, false, false)); 8997b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne lp.onDebugDraw(c, canvas, paint); 90010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne } 901b559976a50c34848d602cc7138859507a379893cPhilip Milne } 902b559976a50c34848d602cc7138859507a379893cPhilip Milne 90310ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne /** 90410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne * @hide 90510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne */ 9063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 90710ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne protected void onDebugDraw(Canvas canvas) { 90810ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne Paint paint = new Paint(); 90910ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne paint.setStyle(Paint.Style.STROKE); 91010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne paint.setColor(Color.argb(50, 255, 255, 255)); 91110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne 9127b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne Insets insets = getOpticalInsets(); 9137b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne 9147b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int top = getPaddingTop() + insets.top; 9157b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int left = getPaddingLeft() + insets.left; 9167b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int right = getWidth() - getPaddingRight() - insets.right; 9177b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int bottom = getHeight() - getPaddingBottom() - insets.bottom; 9187b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne 919465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int[] xs = mHorizontalAxis.locations; 92010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne if (xs != null) { 92110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne for (int i = 0, length = xs.length; i < length; i++) { 9227b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int x = left + xs[i]; 9237b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne drawLine(canvas, x, top, x, bottom, paint); 924b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 92510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne } 926b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 927465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int[] ys = mVerticalAxis.locations; 92810ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne if (ys != null) { 92910ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne for (int i = 0, length = ys.length; i < length; i++) { 9307b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int y = top + ys[i]; 9317b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne drawLine(canvas, left, y, right, y, paint); 9323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 9333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 93410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne 93510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne super.onDebugDraw(canvas); 9363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 9373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 9383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Add/remove 9393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 940e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne /** 941e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne * @hide 942e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne */ 9433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 944f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne protected void onViewAdded(View child) { 945f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne super.onViewAdded(child); 9463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateStructure(); 9473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 9483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 949e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne /** 950e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne * @hide 951e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne */ 9523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 953f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne protected void onViewRemoved(View child) { 954f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne super.onViewRemoved(child); 955b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne invalidateStructure(); 956350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne } 957350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne 958350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne /** 959350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * We need to call invalidateStructure() when a child's GONE flag changes state. 960350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * This implementation is a catch-all, invalidating on any change in the visibility flags. 961350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * 962350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * @hide 963350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne */ 964350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne @Override 9650d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) { 9660d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase super.onChildVisibilityChanged(child, oldVisibility, newVisibility); 9670d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase if (oldVisibility == GONE || newVisibility == GONE) { 968a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne invalidateStructure(); 9690d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase } 970b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne } 971b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne 972d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne private int computeLayoutParamsHashCode() { 973d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne int result = 1; 974d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 975d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne View c = getChildAt(i); 976d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) continue; 977d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne LayoutParams lp = (LayoutParams) c.getLayoutParams(); 978d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne result = 31 * result + lp.hashCode(); 979d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 980d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne return result; 981d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 9823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 983edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne private void consistencyCheck() { 984465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (mLastLayoutParamsHashCode == UNINITIALIZED_HASH) { 985edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne validateLayoutParams(); 986465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mLastLayoutParamsHashCode = computeLayoutParamsHashCode(); 987465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell } else if (mLastLayoutParamsHashCode != computeLayoutParamsHashCode()) { 988465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mPrinter.println("The fields of some layout parameters were modified in between " 989211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne + "layout operations. Check the javadoc for GridLayout.LayoutParams#rowSpec."); 990edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne invalidateStructure(); 991edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne consistencyCheck(); 992d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 993b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 994b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 995d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne // Measurement 996d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 997e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne // Note: padding has already been removed from the supplied specs 9984a145d72622772b920f60195e80942058984259cPhilip Milne private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec, 999edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne int childWidth, int childHeight) { 10004a145d72622772b920f60195e80942058984259cPhilip Milne int childWidthSpec = getChildMeasureSpec(parentWidthSpec, 1001e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne getTotalMargin(child, true), childWidth); 10024a145d72622772b920f60195e80942058984259cPhilip Milne int childHeightSpec = getChildMeasureSpec(parentHeightSpec, 1003e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne getTotalMargin(child, false), childHeight); 10044a145d72622772b920f60195e80942058984259cPhilip Milne child.measure(childWidthSpec, childHeightSpec); 1005b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 1006b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 1007e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne // Note: padding has already been removed from the supplied specs 10084a145d72622772b920f60195e80942058984259cPhilip Milne private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) { 1009b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1010b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 1011d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) continue; 10124a145d72622772b920f60195e80942058984259cPhilip Milne LayoutParams lp = getLayoutParams(c); 10134a145d72622772b920f60195e80942058984259cPhilip Milne if (firstPass) { 10144a145d72622772b920f60195e80942058984259cPhilip Milne measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height); 10154a145d72622772b920f60195e80942058984259cPhilip Milne } else { 1016465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell boolean horizontal = (mOrientation == HORIZONTAL); 1017ecab1178648670f2c72b47faf250040fcded3d13Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 10186dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar if (spec.getAbsoluteAlignment(horizontal) == FILL) { 10194a145d72622772b920f60195e80942058984259cPhilip Milne Interval span = spec.span; 1020465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 10214a145d72622772b920f60195e80942058984259cPhilip Milne int[] locations = axis.getLocations(); 1022ecab1178648670f2c72b47faf250040fcded3d13Philip Milne int cellSize = locations[span.max] - locations[span.min]; 1023ecab1178648670f2c72b47faf250040fcded3d13Philip Milne int viewSize = cellSize - getTotalMargin(c, horizontal); 1024ecab1178648670f2c72b47faf250040fcded3d13Philip Milne if (horizontal) { 1025ecab1178648670f2c72b47faf250040fcded3d13Philip Milne measureChildWithMargins2(c, widthSpec, heightSpec, viewSize, lp.height); 10264a145d72622772b920f60195e80942058984259cPhilip Milne } else { 1027ecab1178648670f2c72b47faf250040fcded3d13Philip Milne measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, viewSize); 10284a145d72622772b920f60195e80942058984259cPhilip Milne } 10294a145d72622772b920f60195e80942058984259cPhilip Milne } 10304a145d72622772b920f60195e80942058984259cPhilip Milne } 1031b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 1032b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 1033b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 1034e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne static int adjust(int measureSpec, int delta) { 1035e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne return makeMeasureSpec( 1036e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne MeasureSpec.getSize(measureSpec + delta), MeasureSpec.getMode(measureSpec)); 1037e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne } 1038e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne 1039aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne @Override 1040aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne protected void onMeasure(int widthSpec, int heightSpec) { 1041edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne consistencyCheck(); 1042d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 10434a145d72622772b920f60195e80942058984259cPhilip Milne /** If we have been called by {@link View#measure(int, int)}, one of width or height 10444a145d72622772b920f60195e80942058984259cPhilip Milne * is likely to have changed. We must invalidate if so. */ 10454a145d72622772b920f60195e80942058984259cPhilip Milne invalidateValues(); 10464a145d72622772b920f60195e80942058984259cPhilip Milne 1047e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int hPadding = getPaddingLeft() + getPaddingRight(); 1048e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int vPadding = getPaddingTop() + getPaddingBottom(); 1049e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne 1050e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int widthSpecSansPadding = adjust( widthSpec, -hPadding); 1051e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int heightSpecSansPadding = adjust(heightSpec, -vPadding); 10524a145d72622772b920f60195e80942058984259cPhilip Milne 1053e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, true); 1054e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne 1055e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int widthSansPadding; 1056e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int heightSansPadding; 10574a145d72622772b920f60195e80942058984259cPhilip Milne 10584a145d72622772b920f60195e80942058984259cPhilip Milne // Use the orientation property to decide which axis should be laid out first. 1059465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (mOrientation == HORIZONTAL) { 1060465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding); 1061e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false); 1062465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding); 10634a145d72622772b920f60195e80942058984259cPhilip Milne } else { 1064465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding); 1065e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false); 1066465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding); 10674a145d72622772b920f60195e80942058984259cPhilip Milne } 1068aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1069e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int measuredWidth = Math.max(widthSansPadding + hPadding, getSuggestedMinimumWidth()); 1070e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int measuredHeight = Math.max(heightSansPadding + vPadding, getSuggestedMinimumHeight()); 107109e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne 10723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setMeasuredDimension( 1073e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne resolveSizeAndState(measuredWidth, widthSpec, 0), 107409e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne resolveSizeAndState(measuredHeight, heightSpec, 0)); 10753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 10763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 107748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private int getMeasurement(View c, boolean horizontal) { 10787b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight(); 10793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 10803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1081f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final int getMeasurementIncludingMargin(View c, boolean horizontal) { 1082d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) { 10835125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return 0; 10845125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 10854c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal); 1086aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 10873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1088aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne @Override 1089aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public void requestLayout() { 1090aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne super.requestLayout(); 1091aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne invalidateValues(); 1092aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1093aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 10943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Layout container 10953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1096aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 1097aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * {@inheritDoc} 1098aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 1099aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1100aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne The layout operation is implemented by delegating the heavy lifting to the 1101aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne to the mHorizontalAxis and mVerticalAxis instances of the internal Axis class. 1102aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Together they compute the locations of the vertical and horizontal lines of 1103aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne the grid (respectively!). 1104aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1105aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This method is then left with the simpler task of applying margins, gravity 1106aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne and sizing to each child view and then placing it in its cell. 1107aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 11083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 110909e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 1110edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne consistencyCheck(); 1111d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 111209e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne int targetWidth = right - left; 111309e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne int targetHeight = bottom - top; 11143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingLeft = getPaddingLeft(); 11163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingTop = getPaddingTop(); 11173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingRight = getPaddingRight(); 11183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingBottom = getPaddingBottom(); 11193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1120465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight); 1121465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom); 11223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1123465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int[] hLocations = mHorizontalAxis.getLocations(); 1124465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int[] vLocations = mVerticalAxis.getLocations(); 11254c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne 1126b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1127b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 1128d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) continue; 1129b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne LayoutParams lp = getLayoutParams(c); 113093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec columnSpec = lp.columnSpec; 113193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec rowSpec = lp.rowSpec; 1132aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 113393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval colSpan = columnSpec.span; 113493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval rowSpan = rowSpec.span; 11353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11364c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int x1 = hLocations[colSpan.min]; 11374c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int y1 = vLocations[rowSpan.min]; 11383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11394c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int x2 = hLocations[colSpan.max]; 11404c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int y2 = vLocations[rowSpan.max]; 11413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int cellWidth = x2 - x1; 11433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int cellHeight = y2 - y1; 11443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 114548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int pWidth = getMeasurement(c, true); 114648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int pHeight = getMeasurement(c, false); 11473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11486dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar Alignment hAlign = columnSpec.getAbsoluteAlignment(true); 11496dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar Alignment vAlign = rowSpec.getAbsoluteAlignment(false); 1150aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1151465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i); 1152465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i); 11537fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 11547fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne // Gravity offsets: the location of the alignment group relative to its cell group. 11556216e87fe8ad3273855233965b34049d22763e94Philip Milne int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true)); 11566216e87fe8ad3273855233965b34049d22763e94Philip Milne int gravityOffsetY = vAlign.getGravityOffset(c, cellHeight - boundsY.size(true)); 11576216e87fe8ad3273855233965b34049d22763e94Philip Milne 11586216e87fe8ad3273855233965b34049d22763e94Philip Milne int leftMargin = getMargin(c, true, true); 11594c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int topMargin = getMargin(c, false, true); 11606216e87fe8ad3273855233965b34049d22763e94Philip Milne int rightMargin = getMargin(c, true, false); 11614c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int bottomMargin = getMargin(c, false, false); 11627fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 11631557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int sumMarginsX = leftMargin + rightMargin; 11641557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int sumMarginsY = topMargin + bottomMargin; 11651557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne 11664c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne // Alignment offsets: the location of the view relative to its alignment group. 11671557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true); 11681557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false); 11697fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 11701557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX); 11711557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY); 11727fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 11736216e87fe8ad3273855233965b34049d22763e94Philip Milne int dx = x1 + gravityOffsetX + alignmentOffsetX; 11743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11756216e87fe8ad3273855233965b34049d22763e94Philip Milne int cx = !isLayoutRtl() ? paddingLeft + leftMargin + dx : 11766216e87fe8ad3273855233965b34049d22763e94Philip Milne targetWidth - width - paddingRight - rightMargin - dx; 11776216e87fe8ad3273855233965b34049d22763e94Philip Milne int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin; 11783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1179899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) { 1180899d5922870c78e0e663bc5661849eb468afc984Philip Milne c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY)); 1181899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 1182b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne c.layout(cx, cy, cx + width, cy + height); 11833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11868a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 1187a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn public CharSequence getAccessibilityClassName() { 1188a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn return GridLayout.class.getName(); 11898a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 11908a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 11913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Inner classes 11923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1193aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1194aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This internal class houses the algorithm for computing the locations of grid lines; 1195aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne along either the horizontal or vertical axis. A GridLayout uses two instances of this class - 1196aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne distinguished by the "horizontal" flag which is true for the horizontal axis and false 1197aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne for the vertical one. 1198aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 1199f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final class Axis { 120048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private static final int NEW = 0; 12013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int PENDING = 1; 12023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int COMPLETE = 2; 12033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final boolean horizontal; 12053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1206f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int definedCount = UNDEFINED; 12074a145d72622772b920f60195e80942058984259cPhilip Milne private int maxIndex = UNDEFINED; 12083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 120993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne PackedMap<Spec, Bounds> groupBounds; 12103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean groupBoundsValid = false; 12113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 121248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne PackedMap<Interval, MutableInt> forwardLinks; 121348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean forwardLinksValid = false; 121448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 121548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne PackedMap<Interval, MutableInt> backwardLinks; 121648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean backwardLinksValid = false; 12173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int[] leadingMargins; 1219aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public boolean leadingMarginsValid = false; 1220aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 12213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int[] trailingMargins; 1222aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public boolean trailingMarginsValid = false; 12233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public Arc[] arcs; 12253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean arcsValid = false; 12263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1227aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public int[] locations; 122848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean locationsValid = false; 1229aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 12309505480ee37494a33e12565db4febfb18b6d7494Philip Milne public boolean hasWeights; 12319505480ee37494a33e12565db4febfb18b6d7494Philip Milne public boolean hasWeightsValid = false; 12329505480ee37494a33e12565db4febfb18b6d7494Philip Milne public int[] deltas; 12339505480ee37494a33e12565db4febfb18b6d7494Philip Milne 1234f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean orderPreserved = DEFAULT_ORDER_PRESERVED; 12353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 123648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private MutableInt parentMin = new MutableInt(0); 123748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private MutableInt parentMax = new MutableInt(-MAX_SIZE); 123848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 12393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private Axis(boolean horizontal) { 12403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.horizontal = horizontal; 12413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12434a145d72622772b920f60195e80942058984259cPhilip Milne private int calculateMaxIndex() { 12444a145d72622772b920f60195e80942058984259cPhilip Milne // the number Integer.MIN_VALUE + 1 comes up in undefined cells 12454a145d72622772b920f60195e80942058984259cPhilip Milne int result = -1; 1246b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1247b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 1248b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne LayoutParams params = getLayoutParams(c); 124993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? params.columnSpec : params.rowSpec; 12504a145d72622772b920f60195e80942058984259cPhilip Milne Interval span = spec.span; 12514a145d72622772b920f60195e80942058984259cPhilip Milne result = max(result, span.min); 12524a145d72622772b920f60195e80942058984259cPhilip Milne result = max(result, span.max); 12530f57cea8989cc03bcae19b621096e50b035b7308Philip Milne result = max(result, span.size()); 12543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12554a145d72622772b920f60195e80942058984259cPhilip Milne return result == -1 ? UNDEFINED : result; 12563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12584a145d72622772b920f60195e80942058984259cPhilip Milne private int getMaxIndex() { 12594a145d72622772b920f60195e80942058984259cPhilip Milne if (maxIndex == UNDEFINED) { 12604a145d72622772b920f60195e80942058984259cPhilip Milne maxIndex = max(0, calculateMaxIndex()); // use zero when there are no children 12613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12624a145d72622772b920f60195e80942058984259cPhilip Milne return maxIndex; 1263f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1264f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1265f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int getCount() { 12664a145d72622772b920f60195e80942058984259cPhilip Milne return max(definedCount, getMaxIndex()); 12673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setCount(int count) { 12700f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (count != UNDEFINED && count < getMaxIndex()) { 12710f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams((horizontal ? "column" : "row") + 12720f57cea8989cc03bcae19b621096e50b035b7308Philip Milne "Count must be greater than or equal to the maximum of all grid indices " + 12730f57cea8989cc03bcae19b621096e50b035b7308Philip Milne "(and spans) defined in the LayoutParams of each child"); 12740f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 1275f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.definedCount = count; 12763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean isOrderPreserved() { 1279f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return orderPreserved; 12803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setOrderPreserved(boolean orderPreserved) { 1283f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.orderPreserved = orderPreserved; 12843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateStructure(); 12853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 128793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne private PackedMap<Spec, Bounds> createGroupBounds() { 128893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class); 128948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1290b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 1291a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne // we must include views that are GONE here, see introductory javadoc 12925125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne LayoutParams lp = getLayoutParams(c); 12935125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 12946dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar Bounds bounds = spec.getAbsoluteAlignment(horizontal).getBounds(); 12955125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne assoc.put(spec, bounds); 12963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 129748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return assoc.pack(); 12983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 13003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void computeGroupBounds() { 1301b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne Bounds[] values = groupBounds.values; 1302b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0; i < values.length; i++) { 1303b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne values[i].reset(); 13043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 1305aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 13063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne View c = getChildAt(i); 1307a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne // we must include views that are GONE here, see introductory javadoc 13083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne LayoutParams lp = getLayoutParams(c); 130993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 1310fbd9997e681dedffa85831948b3f22dd47f09f2aYigit Boyar int size = getMeasurementIncludingMargin(c, horizontal) + 1311fbd9997e681dedffa85831948b3f22dd47f09f2aYigit Boyar ((spec.weight == 0) ? 0 : getDeltas()[i]); 13129505480ee37494a33e12565db4febfb18b6d7494Philip Milne groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size); 13133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1316f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public PackedMap<Spec, Bounds> getGroupBounds() { 13173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (groupBounds == null) { 13183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBounds = createGroupBounds(); 13193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (!groupBoundsValid) { 13213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne computeGroupBounds(); 13223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBoundsValid = true; 13233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return groupBounds; 13253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 13273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Add values computed by alignment - taking the max of all alignments in each span 132848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private PackedMap<Interval, MutableInt> createLinks(boolean min) { 132948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class); 133093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec[] keys = getGroupBounds().keys; 133148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0, N = keys.length; i < N; i++) { 133248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Interval span = min ? keys[i].span : keys[i].span.inverse(); 133348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne result.put(span, new MutableInt()); 13343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 133548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return result.pack(); 13363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 133848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) { 133948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne MutableInt[] spans = links.values; 13403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < spans.length; i++) { 13413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne spans[i].reset(); 13423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 13445d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne // Use getter to trigger a re-evaluation 134548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Bounds[] bounds = getGroupBounds().values; 13463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < bounds.length; i++) { 134748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int size = bounds[i].size(min); 134848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne MutableInt valueHolder = links.getValue(i); 13495125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne // this effectively takes the max() of the minima and the min() of the maxima 13505125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne valueHolder.value = max(valueHolder.value, min ? size : -size); 13513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 135448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private PackedMap<Interval, MutableInt> getForwardLinks() { 135548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (forwardLinks == null) { 135648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinks = createLinks(true); 13573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 135848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!forwardLinksValid) { 135948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeLinks(forwardLinks, true); 136048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinksValid = true; 13613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 136248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return forwardLinks; 13633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 136548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private PackedMap<Interval, MutableInt> getBackwardLinks() { 136648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (backwardLinks == null) { 136748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinks = createLinks(false); 13683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 136948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!backwardLinksValid) { 137048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeLinks(backwardLinks, false); 137148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinksValid = true; 137248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 137348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return backwardLinks; 13743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 137648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void include(List<Arc> arcs, Interval key, MutableInt size, 1377edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne boolean ignoreIfAlreadyPresent) { 137848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne /* 137948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Remove self referential links. 138048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne These appear: 138148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne . as parental constraints when GridLayout has no children 138248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne . when components have been marked as GONE 138348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne */ 138448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (key.size() == 0) { 138548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return; 13863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 138748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // this bit below should really be computed outside here - 138848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // its just to stop default (row/col > 0) constraints obliterating valid entries 138948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (ignoreIfAlreadyPresent) { 139048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (Arc arc : arcs) { 139148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Interval span = arc.span; 139248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (span.equals(key)) { 139348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return; 139448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 139548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 139648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 139748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne arcs.add(new Arc(key, size)); 13983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 140048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void include(List<Arc> arcs, Interval key, MutableInt size) { 140148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(arcs, key, size, true); 14023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1404aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne // Group arcs by their first vertex, returning an array of arrays. 14053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // This is linear in the number of arcs. 1406f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Arc[][] groupArcsByFirstVertex(Arc[] arcs) { 140748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int N = getCount() + 1; // the number of vertices 14083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Arc[][] result = new Arc[N][]; 14093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int[] sizes = new int[N]; 14103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (Arc arc : arcs) { 14113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne sizes[arc.span.min]++; 14125d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 14133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < sizes.length; i++) { 14143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result[i] = new Arc[sizes[i]]; 14153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // reuse the sizes array to hold the current last elements as we insert each arc 14173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Arrays.fill(sizes, 0); 14183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (Arc arc : arcs) { 14193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int i = arc.span.min; 14203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result[i][sizes[i]++] = arc; 14213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 14233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 14243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 142648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private Arc[] topologicalSort(final Arc[] arcs) { 142748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return new Object() { 142848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] result = new Arc[arcs.length]; 142948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int cursor = result.length - 1; 143048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs); 14313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int[] visited = new int[getCount() + 1]; 14323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 143348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne void walk(int loc) { 143448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne switch (visited[loc]) { 143548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case NEW: { 143648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne visited[loc] = PENDING; 143748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (Arc arc : arcsByVertex[loc]) { 143848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne walk(arc.span.max); 143948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne result[cursor--] = arc; 14403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 144148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne visited[loc] = COMPLETE; 144248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne break; 144348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 144448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case PENDING: { 1445b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne // le singe est dans l'arbre 144648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne assert false; 144748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne break; 144848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 144948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case COMPLETE: { 145048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne break; 14513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 145448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 145548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] sort() { 145648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) { 145748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne walk(loc); 145848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 145948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne assert cursor == -1; 146048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return result; 146148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 146248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne }.sort(); 146348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 146448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 146548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private Arc[] topologicalSort(List<Arc> arcs) { 146648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return topologicalSort(arcs.toArray(new Arc[arcs.size()])); 14673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 146948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) { 147048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0; i < links.keys.length; i++) { 147148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Interval key = links.keys[i]; 147248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(result, key, links.values[i], false); 147348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 147448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 147548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1476aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private Arc[] createArcs() { 147748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne List<Arc> mins = new ArrayList<Arc>(); 147848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne List<Arc> maxs = new ArrayList<Arc>(); 14793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 148048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add the minimum values from the components. 148148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne addComponentSizes(mins, getForwardLinks()); 148248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add the maximum values from the components. 148348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne addComponentSizes(maxs, getBackwardLinks()); 14843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 148548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add ordering constraints to prevent row/col sizes from going negative 1486f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (orderPreserved) { 148748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add a constraint for every row/col 14883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < getCount(); i++) { 1489899d5922870c78e0e663bc5661849eb468afc984Philip Milne include(mins, new Interval(i, i + 1), new MutableInt(0)); 14903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 149248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 149348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add the container constraints. Use the version of include that allows 149448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // duplicate entries in case a child spans the entire grid. 149548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int N = getCount(); 149648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(mins, new Interval(0, N), parentMin, false); 149748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(maxs, new Interval(N, 0), parentMax, false); 149848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 149948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Sort 150048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] sMins = topologicalSort(mins); 150148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] sMaxs = topologicalSort(maxs); 150248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 150348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return append(sMins, sMaxs); 150448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 150548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 150648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void computeArcs() { 150748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // getting the links validates the values that are shared by the arc list 150848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne getForwardLinks(); 150948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne getBackwardLinks(); 15103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1512aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public Arc[] getArcs() { 15133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (arcs == null) { 1514aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne arcs = createArcs(); 15153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (!arcsValid) { 151748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeArcs(); 15183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne arcsValid = true; 15193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return arcs; 15213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1523aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private boolean relax(int[] locations, Arc entry) { 152448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!entry.valid) { 152548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return false; 152648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 15273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Interval span = entry.span; 15283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int u = span.min; 15293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int v = span.max; 15303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int value = entry.value.value; 15313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int candidate = locations[u] + value; 1532aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (candidate > locations[v]) { 15333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne locations[v] = candidate; 15343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 15353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 15373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1539f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private void init(int[] locations) { 15404a145d72622772b920f60195e80942058984259cPhilip Milne Arrays.fill(locations, 0); 1541f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1542f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1543f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private String arcsToString(List<Arc> arcs) { 15444a145d72622772b920f60195e80942058984259cPhilip Milne String var = horizontal ? "x" : "y"; 1545f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne StringBuilder result = new StringBuilder(); 15464a145d72622772b920f60195e80942058984259cPhilip Milne boolean first = true; 15474a145d72622772b920f60195e80942058984259cPhilip Milne for (Arc arc : arcs) { 15484a145d72622772b920f60195e80942058984259cPhilip Milne if (first) { 15494a145d72622772b920f60195e80942058984259cPhilip Milne first = false; 1550f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } else { 15514a145d72622772b920f60195e80942058984259cPhilip Milne result = result.append(", "); 1552f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1553f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int src = arc.span.min; 1554f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int dst = arc.span.max; 1555f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int value = arc.value.value; 1556f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne result.append((src < dst) ? 1557edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne var + dst + "-" + var + src + ">=" + value : 1558edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne var + src + "-" + var + dst + "<=" + -value); 1559f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1560f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1561f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return result.toString(); 1562f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1563f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1564f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private void logError(String axisName, Arc[] arcs, boolean[] culprits0) { 1565f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne List<Arc> culprits = new ArrayList<Arc>(); 1566f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne List<Arc> removed = new ArrayList<Arc>(); 1567f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int c = 0; c < arcs.length; c++) { 1568f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Arc arc = arcs[c]; 1569f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (culprits0[c]) { 1570f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne culprits.add(arc); 1571f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1572f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (!arc.valid) { 1573f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne removed.add(arc); 1574f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1575f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1576465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mPrinter.println(axisName + " constraints: " + arcsToString(culprits) + 1577211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne " are inconsistent; permanently removing: " + arcsToString(removed) + ". "); 1578f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1579f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1580aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1581aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N) 1582aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1583aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne GridLayout converts its requirements into a system of linear constraints of the 1584aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne form: 1585aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1586aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne x[i] - x[j] < a[k] 1587aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1588aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Where the x[i] are variables and the a[k] are constants. 1589aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1590aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne For example, if the variables were instead labeled x, y, z we might have: 1591aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1592aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne x - y < 17 1593aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne y - z < 23 1594aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne z - x < 42 1595aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1596aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This is a special case of the Linear Programming problem that is, in turn, 1597aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne equivalent to the single-source shortest paths problem on a digraph, for 1598aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne which the O(n^2) Bellman-Ford algorithm the most commonly used general solution. 1599aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 160098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar private boolean solve(Arc[] arcs, int[] locations) { 160198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar return solve(arcs, locations, true); 160298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar } 160398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar 160498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar private boolean solve(Arc[] arcs, int[] locations, boolean modifyOnError) { 1605f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne String axisName = horizontal ? "horizontal" : "vertical"; 16063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1. 1607f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean[] originalCulprits = null; 16083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1609f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int p = 0; p < arcs.length; p++) { 1610f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne init(locations); 1611f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1612f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne // We take one extra pass over traditional Bellman-Ford (and omit their final step) 1613f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int i = 0; i < N; i++) { 1614f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean changed = false; 1615f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int j = 0, length = arcs.length; j < length; j++) { 1616f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne changed |= relax(locations, arcs[j]); 1617f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1618f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (!changed) { 1619f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (originalCulprits != null) { 1620f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne logError(axisName, arcs, originalCulprits); 1621f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 162298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar return true; 16233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 162548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 162698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar if (!modifyOnError) { 162798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar return false; // cannot solve with these constraints 162898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar } 162998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar 1630f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean[] culprits = new boolean[arcs.length]; 1631f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int i = 0; i < N; i++) { 1632f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int j = 0, length = arcs.length; j < length; j++) { 1633f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne culprits[j] |= relax(locations, arcs[j]); 1634f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1635f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 163648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1637f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (p == 0) { 1638f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne originalCulprits = culprits; 163948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1640f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1641f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int i = 0; i < arcs.length; i++) { 1642f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (culprits[i]) { 1643f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Arc arc = arcs[i]; 1644f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne // Only remove max values, min values alone cannot be inconsistent 1645f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (arc.span.min < arc.span.max) { 1646f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne continue; 1647f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1648f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne arc.valid = false; 1649f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne break; 165048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 165148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 165248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 165398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar return true; 16543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1656aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private void computeMargins(boolean leading) { 1657aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int[] margins = leading ? leadingMargins : trailingMargins; 1658b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 16593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne View c = getChildAt(i); 1660d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) continue; 16613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne LayoutParams lp = getLayoutParams(c); 166293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 166393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval span = spec.span; 16643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int index = leading ? span.min : span.max; 16654c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne margins[index] = max(margins[index], getMargin1(c, horizontal, leading)); 16663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1669f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne // External entry points 1670f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1671f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int[] getLeadingMargins() { 1672aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (leadingMargins == null) { 1673aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMargins = new int[getCount() + 1]; 1674aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1675aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (!leadingMarginsValid) { 1676aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne computeMargins(true); 1677aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMarginsValid = true; 1678aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1679aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return leadingMargins; 1680aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1681aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1682f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int[] getTrailingMargins() { 1683aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (trailingMargins == null) { 1684aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMargins = new int[getCount() + 1]; 1685aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1686aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (!trailingMarginsValid) { 1687aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne computeMargins(false); 1688aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMarginsValid = true; 1689aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1690aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return trailingMargins; 1691aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 16923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 169398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar private boolean solve(int[] a) { 169498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar return solve(getArcs(), a); 169587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 169687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne 16979505480ee37494a33e12565db4febfb18b6d7494Philip Milne private boolean computeHasWeights() { 16989505480ee37494a33e12565db4febfb18b6d7494Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 16996dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar final View child = getChildAt(i); 17006dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar if (child.getVisibility() == View.GONE) { 17016dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar continue; 17026dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar } 17036dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar LayoutParams lp = getLayoutParams(child); 17049505480ee37494a33e12565db4febfb18b6d7494Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 17059505480ee37494a33e12565db4febfb18b6d7494Philip Milne if (spec.weight != 0) { 170687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return true; 170787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 170887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 170987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return false; 171087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 171187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne 17129505480ee37494a33e12565db4febfb18b6d7494Philip Milne private boolean hasWeights() { 17139505480ee37494a33e12565db4febfb18b6d7494Philip Milne if (!hasWeightsValid) { 17149505480ee37494a33e12565db4febfb18b6d7494Philip Milne hasWeights = computeHasWeights(); 17159505480ee37494a33e12565db4febfb18b6d7494Philip Milne hasWeightsValid = true; 17169505480ee37494a33e12565db4febfb18b6d7494Philip Milne } 17179505480ee37494a33e12565db4febfb18b6d7494Philip Milne return hasWeights; 17189505480ee37494a33e12565db4febfb18b6d7494Philip Milne } 17199505480ee37494a33e12565db4febfb18b6d7494Philip Milne 17209505480ee37494a33e12565db4febfb18b6d7494Philip Milne public int[] getDeltas() { 17219505480ee37494a33e12565db4febfb18b6d7494Philip Milne if (deltas == null) { 17229505480ee37494a33e12565db4febfb18b6d7494Philip Milne deltas = new int[getChildCount()]; 17239505480ee37494a33e12565db4febfb18b6d7494Philip Milne } 17249505480ee37494a33e12565db4febfb18b6d7494Philip Milne return deltas; 17259505480ee37494a33e12565db4febfb18b6d7494Philip Milne } 17269505480ee37494a33e12565db4febfb18b6d7494Philip Milne 172798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar private void shareOutDelta(int totalDelta, float totalWeight) { 172898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar Arrays.fill(deltas, 0); 17299505480ee37494a33e12565db4febfb18b6d7494Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 17306dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar final View c = getChildAt(i); 17316dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar if (c.getVisibility() == View.GONE) { 17326dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar continue; 17336dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar } 17349505480ee37494a33e12565db4febfb18b6d7494Philip Milne LayoutParams lp = getLayoutParams(c); 17359505480ee37494a33e12565db4febfb18b6d7494Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 17369505480ee37494a33e12565db4febfb18b6d7494Philip Milne float weight = spec.weight; 17379505480ee37494a33e12565db4febfb18b6d7494Philip Milne if (weight != 0) { 173887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne int delta = Math.round((weight * totalDelta / totalWeight)); 17399505480ee37494a33e12565db4febfb18b6d7494Philip Milne deltas[i] = delta; 174098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar // the two adjustments below are to counter the above rounding and avoid 174198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar // off-by-ones at the end 174287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne totalDelta -= delta; 174387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne totalWeight -= weight; 174487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 174587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 174687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 174787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne 174887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne private void solveAndDistributeSpace(int[] a) { 17499505480ee37494a33e12565db4febfb18b6d7494Philip Milne Arrays.fill(getDeltas(), 0); 17509505480ee37494a33e12565db4febfb18b6d7494Philip Milne solve(a); 175198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar int deltaMax = parentMin.value * getChildCount() + 1; //exclusive 175298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar if (deltaMax < 2) { 175398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar return; //don't have any delta to distribute 175498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar } 175598d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar int deltaMin = 0; //inclusive 175698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar 175798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar float totalWeight = calculateTotalWeight(); 175898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar 175998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar int validDelta = -1; //delta for which a solution exists 176098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar boolean validSolution = true; 176198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar // do a binary search to find the max delta that won't conflict with constraints 176298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar while(deltaMin < deltaMax) { 176398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar final int delta = (deltaMin + deltaMax) / 2; 176498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar invalidateValues(); 176598d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar shareOutDelta(delta, totalWeight); 176698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar validSolution = solve(getArcs(), a, false); 176798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar if (validSolution) { 176898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar validDelta = delta; 176998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar deltaMin = delta + 1; 177098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar } else { 177198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar deltaMax = delta; 177298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar } 177398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar } 177498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar if (validDelta > 0 && !validSolution) { 177598d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar // last solution was not successful but we have a successful one. Use it. 177698d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar invalidateValues(); 177798d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar shareOutDelta(validDelta, totalWeight); 177898d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar solve(a); 177998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar } 178098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar } 178198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar 178298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar private float calculateTotalWeight() { 178398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar float totalWeight = 0f; 178498d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar for (int i = 0, N = getChildCount(); i < N; i++) { 178598d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar View c = getChildAt(i); 17866dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar if (c.getVisibility() == View.GONE) { 17876dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar continue; 17886dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar } 178998d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar LayoutParams lp = getLayoutParams(c); 179098d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 179198d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar totalWeight += spec.weight; 179298d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar } 179398d5f04f91580bf8b517c17132eeb8d42008b61dYigit Boyar return totalWeight; 179487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 179587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne 179687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne private void computeLocations(int[] a) { 17979505480ee37494a33e12565db4febfb18b6d7494Philip Milne if (!hasWeights()) { 17989505480ee37494a33e12565db4febfb18b6d7494Philip Milne solve(a); 17999505480ee37494a33e12565db4febfb18b6d7494Philip Milne } else { 18009505480ee37494a33e12565db4febfb18b6d7494Philip Milne solveAndDistributeSpace(a); 18019505480ee37494a33e12565db4febfb18b6d7494Philip Milne } 18024a145d72622772b920f60195e80942058984259cPhilip Milne if (!orderPreserved) { 18034a145d72622772b920f60195e80942058984259cPhilip Milne // Solve returns the smallest solution to the constraint system for which all 18044a145d72622772b920f60195e80942058984259cPhilip Milne // values are positive. One value is therefore zero - though if the row/col 18054a145d72622772b920f60195e80942058984259cPhilip Milne // order is not preserved this may not be the first vertex. For consistency, 18064a145d72622772b920f60195e80942058984259cPhilip Milne // translate all the values so that they measure the distance from a[0]; the 18074a145d72622772b920f60195e80942058984259cPhilip Milne // leading edge of the parent. After this transformation some values may be 18084a145d72622772b920f60195e80942058984259cPhilip Milne // negative. 18094a145d72622772b920f60195e80942058984259cPhilip Milne int a0 = a[0]; 18104a145d72622772b920f60195e80942058984259cPhilip Milne for (int i = 0, N = a.length; i < N; i++) { 18114a145d72622772b920f60195e80942058984259cPhilip Milne a[i] = a[i] - a0; 18124a145d72622772b920f60195e80942058984259cPhilip Milne } 18134a145d72622772b920f60195e80942058984259cPhilip Milne } 18143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1816f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int[] getLocations() { 1817aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (locations == null) { 1818aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int N = getCount() + 1; 1819aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne locations = new int[N]; 1820aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 182148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!locationsValid) { 182248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeLocations(locations); 182348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne locationsValid = true; 182448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1825aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return locations; 18263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1828aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private int size(int[] locations) { 18294a145d72622772b920f60195e80942058984259cPhilip Milne // The parental edges are attached to vertices 0 and N - even when order is not 18304a145d72622772b920f60195e80942058984259cPhilip Milne // being preserved and other vertices fall outside this range. Measure the distance 18314a145d72622772b920f60195e80942058984259cPhilip Milne // between vertices 0 and N, assuming that locations[0] = 0. 18324a145d72622772b920f60195e80942058984259cPhilip Milne return locations[getCount()]; 1833aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1834aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 183548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void setParentConstraints(int min, int max) { 183648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne parentMin.value = min; 183748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne parentMax.value = -max; 183848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne locationsValid = false; 18393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 184148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private int getMeasure(int min, int max) { 184248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne setParentConstraints(min, max); 184348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return size(getLocations()); 184448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1845aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1846f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int getMeasure(int measureSpec) { 184748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int mode = MeasureSpec.getMode(measureSpec); 184848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int size = MeasureSpec.getSize(measureSpec); 184948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne switch (mode) { 185048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case MeasureSpec.UNSPECIFIED: { 185193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne return getMeasure(0, MAX_SIZE); 185248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 185348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case MeasureSpec.EXACTLY: { 185448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return getMeasure(size, size); 185548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 185648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case MeasureSpec.AT_MOST: { 185748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return getMeasure(0, size); 185848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 185948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne default: { 186048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne assert false; 186148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return 0; 186248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 18633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 186448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1865aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1866f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void layout(int size) { 186748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne setParentConstraints(size, size); 186848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne getLocations(); 18693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1871f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void invalidateStructure() { 18724a145d72622772b920f60195e80942058984259cPhilip Milne maxIndex = UNDEFINED; 1873aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 18743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBounds = null; 187548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinks = null; 187648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinks = null; 187748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1878aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMargins = null; 1879aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMargins = null; 1880c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne arcs = null; 188148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1882aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne locations = null; 18833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18849505480ee37494a33e12565db4febfb18b6d7494Philip Milne deltas = null; 18859505480ee37494a33e12565db4febfb18b6d7494Philip Milne hasWeightsValid = false; 18869505480ee37494a33e12565db4febfb18b6d7494Philip Milne 18873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateValues(); 18883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1890f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void invalidateValues() { 18913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBoundsValid = false; 189248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinksValid = false; 189348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinksValid = false; 189448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1895aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMarginsValid = false; 1896aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMarginsValid = false; 189748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne arcsValid = false; 189848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 189948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne locationsValid = false; 19003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 19043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Layout information associated with each of the children of a GridLayout. 19053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 19063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * GridLayout supports both row and column spanning and arbitrary forms of alignment within 19073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * each cell group. The fundamental parameters associated with each cell group are 19083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * gathered into their vertical and horizontal components and stored 190993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * in the {@link #rowSpec} and {@link #columnSpec} layout parameters. 19106216e87fe8ad3273855233965b34049d22763e94Philip Milne * {@link GridLayout.Spec Specs} are immutable structures 1911b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne * and may be shared between the layout parameters of different children. 19123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 191393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * The row and column specs contain the leading and trailing indices along each axis 1914aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * and together specify the four grid indices that delimit the cells of this cell group. 19153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 191693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * The alignment properties of the row and column specs together specify 19173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * both aspects of alignment within the cell group. It is also possible to specify a child's 19183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)} 19193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * method. 192087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * <p> 192187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * The weight property is also included in Spec and specifies the proportion of any 19229505480ee37494a33e12565db4febfb18b6d7494Philip Milne * excess space that is due to the associated view. 1923f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1924f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h4>WRAP_CONTENT and MATCH_PARENT</h4> 1925f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1926f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Because the default values of the {@link #width} and {@link #height} 1927f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly 1928f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * declared in the layout parameters of GridLayout's children. In addition, 1929f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from 1930f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is 1931f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * instead controlled by the principle of <em>flexibility</em>, 1932f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * as discussed in {@link GridLayout}. 1933f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1934f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h4>Summary</h4> 1935f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1936f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * You should not need to use either of the special size values: 1937f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of 1938f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * a GridLayout. 19393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 19403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Default values</h4> 19413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 19423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <ul> 19433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #width} = {@link #WRAP_CONTENT}</li> 19443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #height} = {@link #WRAP_CONTENT}</li> 19453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #topMargin} = 0 when 19463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 19477fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 19483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 19493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #leftMargin} = 0 when 19503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 19517fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 19523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 19533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #bottomMargin} = 0 when 19543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 19557fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 19563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 19573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #rightMargin} = 0 when 19583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 19597fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 19603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 1961f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li> 1962f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li> 1963f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li> 196487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * <li>{@link #rowSpec}<code>.weight</code> = 0 </li> 1965f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li> 1966f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li> 19676216e87fe8ad3273855233965b34049d22763e94Philip Milne * <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li> 196887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * <li>{@link #columnSpec}<code>.weight</code> = 0 </li> 19693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * </ul> 19703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 1971f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * See {@link GridLayout} for a more complete description of the conventions 1972f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * used by GridLayout in the interpretation of the properties of this class. 1973f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 19743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_row 19753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan 197687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_rowWeight 19773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_column 19783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan 197987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_columnWeight 19803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity 19813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 19823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static class LayoutParams extends MarginLayoutParams { 19833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Default values 19853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_WIDTH = WRAP_CONTENT; 19873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_HEIGHT = WRAP_CONTENT; 19883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_MARGIN = UNDEFINED; 19893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_ROW = UNDEFINED; 19903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_COLUMN = UNDEFINED; 1991f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne private static final Interval DEFAULT_SPAN = new Interval(UNDEFINED, UNDEFINED + 1); 19923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size(); 19933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // TypedArray indices 19953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1996b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin; 1997b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft; 1998b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop; 1999b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int RIGHT_MARGIN = 2000b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne R.styleable.ViewGroup_MarginLayout_layout_marginRight; 20013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int BOTTOM_MARGIN = 2002b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne R.styleable.ViewGroup_MarginLayout_layout_marginBottom; 2003b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column; 2004b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan; 200587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight; 20065d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 2007b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW = R.styleable.GridLayout_Layout_layout_row; 2008b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan; 200987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne private static final int ROW_WEIGHT = R.styleable.GridLayout_Layout_layout_rowWeight; 20105d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 2011b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity; 20123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Instance variables 20143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 2016f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * The spec that defines the vertical characteristics of the cell group 20173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * described by these layout parameters. 2018d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * If an assignment is made to this field after a measurement or layout operation 2019d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * has already taken place, a call to 2020d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)} 2021d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * must be made to notify GridLayout of the change. GridLayout is normally able 2022d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * to detect when code fails to observe this rule, issue a warning and take steps to 2023d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * compensate for the omission. This facility is implemented on a best effort basis 2024d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * and should not be relied upon in production code - so it is best to include the above 2025d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * calls to remove the warnings as soon as it is practical. 20263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2027f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public Spec rowSpec = Spec.UNDEFINED; 2028f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 20293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 2030f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * The spec that defines the horizontal characteristics of the cell group 20313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * described by these layout parameters. 2032d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * If an assignment is made to this field after a measurement or layout operation 2033d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * has already taken place, a call to 2034d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)} 2035d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * must be made to notify GridLayout of the change. GridLayout is normally able 2036d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * to detect when code fails to observe this rule, issue a warning and take steps to 2037d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * compensate for the omission. This facility is implemented on a best effort basis 2038d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * and should not be relied upon in production code - so it is best to include the above 2039d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * calls to remove the warnings as soon as it is practical. 20403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2041f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public Spec columnSpec = Spec.UNDEFINED; 20423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Constructors 20443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private LayoutParams( 20463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int width, int height, 20473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int left, int top, int right, int bottom, 204893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec rowSpec, Spec columnSpec) { 20493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(width, height); 20503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setMargins(left, top, right, bottom); 205193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne this.rowSpec = rowSpec; 205293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne this.columnSpec = columnSpec; 20533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 205693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Constructs a new LayoutParams instance for this <code>rowSpec</code> 205793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * and <code>columnSpec</code>. All other fields are initialized with 20583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * default values as defined in {@link LayoutParams}. 20593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 206093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param rowSpec the rowSpec 206193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param columnSpec the columnSpec 20623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 206393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public LayoutParams(Spec rowSpec, Spec columnSpec) { 20643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this(DEFAULT_WIDTH, DEFAULT_HEIGHT, 20653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, 206693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne rowSpec, columnSpec); 20673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 20703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}. 20713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 20723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams() { 2073f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this(Spec.UNDEFINED, Spec.UNDEFINED); 20743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Copying constructors 20773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 20793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 20803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 20813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(ViewGroup.LayoutParams params) { 20823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(params); 20833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 20863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 20873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 20883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(MarginLayoutParams params) { 20893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(params); 20903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 20930a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette * Copy constructor. Clones the width, height, margin values, row spec, 20940a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette * and column spec of the source. 20950a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette * 20960a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette * @param source The layout params to copy from. 20973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 20980a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette public LayoutParams(LayoutParams source) { 20990a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette super(source); 21000a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette 21010a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette this.rowSpec = source.rowSpec; 21020a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette this.columnSpec = source.columnSpec; 21033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // AttributeSet constructors 21063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 21083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 21093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 21103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Values not defined in the attribute set take the default values 21113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * defined in {@link LayoutParams}. 21123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 21133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(Context context, AttributeSet attrs) { 21145125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne super(context, attrs); 21155125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne reInitSuper(context, attrs); 21165125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne init(context, attrs); 21173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Implementation 21203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Reinitialise the margins using a different default policy than MarginLayoutParams. 21223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Here we use the value UNDEFINED (as distinct from zero) to represent the undefined state 21233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // so that a layout manager default can be accessed post set up. We need this as, at the 21243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // point of installation, we do not know how many rows/cols there are and therefore 21253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // which elements are positioned next to the container's trailing edges. We need to 21263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // know this as margins around the container's boundary should have different 21273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // defaults to those between peers. 21283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // This method could be parametrized and moved into MarginLayout. 21303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void reInitSuper(Context context, AttributeSet attrs) { 2131b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne TypedArray a = 2132b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout); 21333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne try { 21343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN); 21353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.leftMargin = a.getDimensionPixelSize(LEFT_MARGIN, margin); 21373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.topMargin = a.getDimensionPixelSize(TOP_MARGIN, margin); 21383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.rightMargin = a.getDimensionPixelSize(RIGHT_MARGIN, margin); 21393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.bottomMargin = a.getDimensionPixelSize(BOTTOM_MARGIN, margin); 21403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } finally { 21413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne a.recycle(); 21423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21455125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne private void init(Context context, AttributeSet attrs) { 2146b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout); 21473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne try { 21485125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int gravity = a.getInt(GRAVITY, Gravity.NO_GRAVITY); 21493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21501e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne int column = a.getInt(COLUMN, DEFAULT_COLUMN); 21515125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE); 215287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne float colWeight = a.getFloat(COLUMN_WEIGHT, Spec.DEFAULT_WEIGHT); 215387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne this.columnSpec = spec(column, colSpan, getAlignment(gravity, true), colWeight); 21543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21551e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne int row = a.getInt(ROW, DEFAULT_ROW); 21561e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE); 215787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne float rowWeight = a.getFloat(ROW_WEIGHT, Spec.DEFAULT_WEIGHT); 215887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false), rowWeight); 21593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } finally { 21603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne a.recycle(); 21613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 21657fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}. 21666216e87fe8ad3273855233965b34049d22763e94Philip Milne * See {@link Gravity}. 21673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 21687fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param gravity the new gravity value 21693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 21703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity 21713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 21723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setGravity(int gravity) { 21735125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne rowSpec = rowSpec.copyWriteAlignment(getAlignment(gravity, false)); 21745125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne columnSpec = columnSpec.copyWriteAlignment(getAlignment(gravity, true)); 21753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 21783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected void setBaseAttributes(TypedArray attributes, int widthAttr, int heightAttr) { 21793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.width = attributes.getLayoutDimension(widthAttr, DEFAULT_WIDTH); 21803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT); 21813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2183f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final void setRowSpecSpan(Interval span) { 218493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne rowSpec = rowSpec.copyWriteSpan(span); 21853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2187f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final void setColumnSpecSpan(Interval span) { 218893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne columnSpec = columnSpec.copyWriteSpan(span); 21893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2190d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2191d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne @Override 2192d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne public boolean equals(Object o) { 2193d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (this == o) return true; 2194d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (o == null || getClass() != o.getClass()) return false; 2195d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2196d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne LayoutParams that = (LayoutParams) o; 2197d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2198d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (!columnSpec.equals(that.columnSpec)) return false; 2199d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (!rowSpec.equals(that.rowSpec)) return false; 2200d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2201d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne return true; 2202d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 2203d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2204d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne @Override 2205d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne public int hashCode() { 2206d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne int result = rowSpec.hashCode(); 2207d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne result = 31 * result + columnSpec.hashCode(); 2208d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne return result; 2209d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 22103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2212aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 2213aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs. 2214aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles. 2215aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 2216f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class Arc { 22173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final Interval span; 2218aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public final MutableInt value; 221948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean valid = true; 22203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2221aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public Arc(Interval span, MutableInt value) { 22223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.span = span; 22233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.value = value; 22243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 22273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public String toString() { 222848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return span + " " + (!valid ? "+>" : "->") + " " + value; 22293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // A mutable Integer - used to avoid heap allocation during the layout operation 22333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2234f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class MutableInt { 22353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int value; 22363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2237f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public MutableInt() { 22383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne reset(); 22393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2241f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public MutableInt(int value) { 22423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.value = value; 22433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2245f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void reset() { 22463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne value = Integer.MIN_VALUE; 22473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 224848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 224948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne @Override 225048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public String toString() { 225148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return Integer.toString(value); 225248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 225348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 225448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 2255f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class Assoc<K, V> extends ArrayList<Pair<K, V>> { 225648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private final Class<K> keyType; 225748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private final Class<V> valueType; 225848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 225948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private Assoc(Class<K> keyType, Class<V> valueType) { 226048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne this.keyType = keyType; 226148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne this.valueType = valueType; 226248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 226348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 2264f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) { 226548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return new Assoc<K, V>(keyType, valueType); 226648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 226748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 226848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public void put(K key, V value) { 226948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne add(Pair.create(key, value)); 227048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 227148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 227248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne @SuppressWarnings(value = "unchecked") 227348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public PackedMap<K, V> pack() { 227448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int N = size(); 227548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne K[] keys = (K[]) Array.newInstance(keyType, N); 227648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne V[] values = (V[]) Array.newInstance(valueType, N); 227748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0; i < N; i++) { 227848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne keys[i] = get(i).first; 227948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne values[i] = get(i).second; 228048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 228148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return new PackedMap<K, V>(keys, values); 228248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 22833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2285aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 2286aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This data structure is used in place of a Map where we have an index that refers to the order 2287aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne in which each key/value pairs were added to the map. In this case we store keys and values 2288aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne in arrays of a length that is equal to the number of unique keys. We also maintain an 2289aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne array of indexes from insertion order to the compacted arrays of keys and values. 2290aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2291aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Note that behavior differs from that of a LinkedHashMap in that repeated entries 2292aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne *do* get added multiples times. So the length of index is equals to the number of 2293aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne items added. 2294aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2295aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This is useful in the GridLayout class where we can rely on the order of children not 2296aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne changing during layout - to use integer-based lookup for our internal structures 2297aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne rather than using (and storing) an implementation of Map<Key, ?>. 2298aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 22993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @SuppressWarnings(value = "unchecked") 2300f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class PackedMap<K, V> { 23013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final int[] index; 23023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final K[] keys; 23033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final V[] values; 23043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private PackedMap(K[] keys, V[] values) { 23063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.index = createIndex(keys); 23073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2308aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne this.keys = compact(keys, index); 2309aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne this.values = compact(values, index); 23103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2312f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public V getValue(int i) { 23133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return values[index[i]]; 23143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static <K> int[] createIndex(K[] keys) { 23173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int size = keys.length; 23183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int[] result = new int[size]; 23193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Map<K, Integer> keyToIndex = new HashMap<K, Integer>(); 23213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < size; i++) { 23223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne K key = keys[i]; 23233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Integer index = keyToIndex.get(key); 23243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (index == null) { 23253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne index = keyToIndex.size(); 23263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne keyToIndex.put(key, index); 23273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result[i] = index; 23293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 23313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2333aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 2334aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Create a compact array of keys or values using the supplied index. 2335aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 2336aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private static <K> K[] compact(K[] a, int[] index) { 2337aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int size = a.length; 2338aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Class<?> componentType = a.getClass().getComponentType(); 233951f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1); 23403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // this overwrite duplicates, retaining the last equivalent entry 23423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < size; i++) { 2343aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne result[index[i]] = a[i]; 23443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 23463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2349aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 235093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne For each group (with a given alignment) we need to store the amount of space required 23517fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne before the alignment point and the amount of space required after it. One side of this 235247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio calculation is always 0 for START and END alignments but we don't make use of this. 2353aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no 2354aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne simple optimisations are possible. 2355aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2356aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne The general algorithm therefore is to create a Map (actually a PackedMap) from 235793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne group to Bounds and to loop through all Views in the group taking the maximum 2358aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne of the values for each View. 2359aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 2360f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static class Bounds { 23617fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne public int before; 23627fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne public int after; 23635125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public int flexibility; // we're flexible iff all included specs are flexible 23643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private Bounds() { 23663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne reset(); 23673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2369a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void reset() { 23707fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne before = Integer.MIN_VALUE; 23717fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne after = Integer.MIN_VALUE; 23725125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne flexibility = CAN_STRETCH; // from the above, we're flexible when empty 23733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2375a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void include(int before, int after) { 23767fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne this.before = max(this.before, before); 23777fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne this.after = max(this.after, after); 23783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 238048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne protected int size(boolean min) { 23815d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne if (!min) { 23825125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne if (canStretch(flexibility)) { 23835d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne return MAX_SIZE; 23845d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 238548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 23864885f2f773915a48d0e2f67bc604b081327372a0Philip Milne return before + after; 23873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23891557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) { 23907a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne return before - a.getAlignmentValue(c, size, gl.getLayoutMode()); 239148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 239248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 23939505480ee37494a33e12565db4febfb18b6d7494Philip Milne protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) { 23945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne this.flexibility &= spec.getFlexibility(); 23951557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne boolean horizontal = axis.horizontal; 23966dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar Alignment alignment = spec.getAbsoluteAlignment(axis.horizontal); 23974c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne // todo test this works correctly when the returned value is UNDEFINED 23987a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode()); 239948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(before, size - before); 2400a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2401a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 24023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 24033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public String toString() { 24043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return "Bounds{" + 24057fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne "before=" + before + 24067fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne ", after=" + after + 24073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne '}'; 24083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * An Interval represents a contiguous range of values that lie between 24133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * the interval's {@link #min} and {@link #max} values. 24143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 24153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Intervals are immutable so may be passed as values and used as keys in hash tables. 24163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * It is not necessary to have multiple instances of Intervals which have the same 24173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link #min} and {@link #max} values. 24183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 24197fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Intervals are often written as {@code [min, max]} and represent the set of values 24207fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code x} such that {@code min <= x < max}. 24213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2422f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class Interval { 24233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The minimum value. 24253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 24263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final int min; 2427aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 24283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The maximum value. 24303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 24313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final int max; 24323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24347fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Construct a new Interval, {@code interval}, where: 24353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <ul> 24367fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <li> {@code interval.min = min} </li> 24377fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <li> {@code interval.max = max} </li> 24383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * </ul> 24393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 24403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @param min the minimum value. 24413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @param max the maximum value. 24423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 24433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public Interval(int min, int max) { 24443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.min = min; 24453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.max = max; 24463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2448f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int size() { 24493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return max - min; 24503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2452f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Interval inverse() { 24533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return new Interval(max, min); 24543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24577fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Returns {@code true} if the {@link #getClass class}, 24587fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@link #min} and {@link #max} properties of this Interval and the 24597fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * supplied parameter are pairwise equal; {@code false} otherwise. 24603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 24617fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param that the object to compare this interval with 24623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 24633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return {@code true} if the specified object is equal to this 24647fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code Interval}, {@code false} otherwise. 24653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 24663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 24673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean equals(Object that) { 24683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (this == that) { 24693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 24703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (that == null || getClass() != that.getClass()) { 24723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 24733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Interval interval = (Interval) that; 24763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (max != interval.max) { 24783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 24793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24804c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne //noinspection RedundantIfStatement 24813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (min != interval.min) { 24823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 24833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 24863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 24893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int hashCode() { 24903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int result = min; 24913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result = 31 * result + max; 24923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 24933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 24963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public String toString() { 24973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return "[" + min + ", " + max + "]"; 24983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2501899d5922870c78e0e663bc5661849eb468afc984Philip Milne /** 2502899d5922870c78e0e663bc5661849eb468afc984Philip Milne * A Spec defines the horizontal or vertical characteristics of a group of 25034a145d72622772b920f60195e80942058984259cPhilip Milne * cells. Each spec. defines the <em>grid indices</em> and <em>alignment</em> 25044a145d72622772b920f60195e80942058984259cPhilip Milne * along the appropriate axis. 2505899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p> 2506899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The <em>grid indices</em> are the leading and trailing edges of this cell group. 2507899d5922870c78e0e663bc5661849eb468afc984Philip Milne * See {@link GridLayout} for a description of the conventions used by GridLayout 2508899d5922870c78e0e663bc5661849eb468afc984Philip Milne * for grid indices. 2509899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p> 2510899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The <em>alignment</em> property specifies how cells should be aligned in this group. 2511899d5922870c78e0e663bc5661849eb468afc984Philip Milne * For row groups, this specifies the vertical alignment. 2512899d5922870c78e0e663bc5661849eb468afc984Philip Milne * For column groups, this specifies the horizontal alignment. 25134a145d72622772b920f60195e80942058984259cPhilip Milne * <p> 25144a145d72622772b920f60195e80942058984259cPhilip Milne * Use the following static methods to create specs: 25154a145d72622772b920f60195e80942058984259cPhilip Milne * <ul> 25164a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int)}</li> 25174a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int, int)}</li> 25184a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int, Alignment)}</li> 25194a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int, int, Alignment)}</li> 252087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * <li>{@link #spec(int, float)}</li> 252187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * <li>{@link #spec(int, int, float)}</li> 252287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * <li>{@link #spec(int, Alignment, float)}</li> 252387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * <li>{@link #spec(int, int, Alignment, float)}</li> 25244a145d72622772b920f60195e80942058984259cPhilip Milne * </ul> 25254a145d72622772b920f60195e80942058984259cPhilip Milne * 2526899d5922870c78e0e663bc5661849eb468afc984Philip Milne */ 252793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public static class Spec { 2528f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final Spec UNDEFINED = spec(GridLayout.UNDEFINED); 252987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne static final float DEFAULT_WEIGHT = 0; 2530f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 2531f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean startDefined; 253248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne final Interval span; 253393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne final Alignment alignment; 253487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne final float weight; 25353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 253687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne private Spec(boolean startDefined, Interval span, Alignment alignment, float weight) { 2537f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.startDefined = startDefined; 25385d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne this.span = span; 25395d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne this.alignment = alignment; 254087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne this.weight = weight; 25415d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 25425d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 254387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne private Spec(boolean startDefined, int start, int size, Alignment alignment, float weight) { 254487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne this(startDefined, new Interval(start, start + size), alignment, weight); 25453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 25476dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar public Alignment getAbsoluteAlignment(boolean horizontal) { 25486dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar if (alignment != UNDEFINED_ALIGNMENT) { 25496dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar return alignment; 25506dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar } 25516dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar if (weight == 0f) { 25526dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar return horizontal ? START : BASELINE; 25536dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar } 25546dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar return FILL; 25556dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar } 25566dafd87fb4174447018b044bc67818d54fab57d8Yigit Boyar 2557f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec copyWriteSpan(Interval span) { 255887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return new Spec(startDefined, span, alignment, weight); 25593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2561f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec copyWriteAlignment(Alignment alignment) { 256287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return new Spec(startDefined, span, alignment, weight); 25635125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 25645125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 2565f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final int getFlexibility() { 256687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return (alignment == UNDEFINED_ALIGNMENT && weight == 0) ? INFLEXIBLE : CAN_STRETCH; 25673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 25693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 257093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Returns {@code true} if the {@code class}, {@code alignment} and {@code span} 257193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * properties of this Spec and the supplied parameter are pairwise equal, 25727fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false} otherwise. 25733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 257493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param that the object to compare this spec with 25753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 25763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return {@code true} if the specified object is equal to this 257793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@code Spec}; {@code false} otherwise 25783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 25793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 25803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean equals(Object that) { 25813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (this == that) { 25823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 25833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (that == null || getClass() != that.getClass()) { 25853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 25863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 258893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = (Spec) that; 25893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 259093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne if (!alignment.equals(spec.alignment)) { 25913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 25923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25934c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne //noinspection RedundantIfStatement 259493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne if (!span.equals(spec.span)) { 25953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 25963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 25983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 25993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 26003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 26013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 26023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int hashCode() { 26033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int result = span.hashCode(); 26043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result = 31 * result + alignment.hashCode(); 26053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 26063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 26073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 26083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 26093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 261093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Return a Spec, {@code spec}, where: 261193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <ul> 261293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.span = [start, start + size]} </li> 261393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.alignment = alignment} </li> 261487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * <li> {@code spec.weight = weight} </li> 261593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * </ul> 26167b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * <p> 26177b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * To leave the start index undefined, use the value {@link #UNDEFINED}. 261893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * 261993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param start the start 262093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param size the size 262193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param alignment the alignment 262287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param weight the weight 262387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne */ 262487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne public static Spec spec(int start, int size, Alignment alignment, float weight) { 262587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return new Spec(start != UNDEFINED, start, size, alignment, weight); 262687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 262787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne 262887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne /** 262987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * Equivalent to: {@code spec(start, 1, alignment, weight)}. 263087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * 263187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param start the start 263287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param alignment the alignment 263387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param weight the weight 263487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne */ 263587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne public static Spec spec(int start, Alignment alignment, float weight) { 263687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return spec(start, 1, alignment, weight); 263787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 263887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne 263987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne /** 264087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * Equivalent to: {@code spec(start, 1, default_alignment, weight)} - 264187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * where {@code default_alignment} is specified in 264287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * {@link android.widget.GridLayout.LayoutParams}. 264387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * 264487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param start the start 264587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param size the size 264687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param weight the weight 264787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne */ 264887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne public static Spec spec(int start, int size, float weight) { 264987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return spec(start, size, UNDEFINED_ALIGNMENT, weight); 265087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 265187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne 265287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne /** 265387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * Equivalent to: {@code spec(start, 1, weight)}. 265487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * 265587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param start the start 265687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param weight the weight 265787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne */ 265887260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne public static Spec spec(int start, float weight) { 265987260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return spec(start, 1, weight); 266087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne } 266187260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne 266287260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne /** 266387260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * Equivalent to: {@code spec(start, size, alignment, 0f)}. 266487260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * 266587260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param start the start 266687260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param size the size 266787260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne * @param alignment the alignment 266893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne */ 266993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public static Spec spec(int start, int size, Alignment alignment) { 267087260844afc3ff2adf63b156c052e15a2f8c68f0Philip Milne return spec(start, size, alignment, Spec.DEFAULT_WEIGHT); 267193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne } 267293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne 267393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne /** 267493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Return a Spec, {@code spec}, where: 267593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <ul> 267693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.span = [start, start + 1]} </li> 267793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.alignment = alignment} </li> 267893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * </ul> 26797b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * <p> 26807b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * To leave the start index undefined, use the value {@link #UNDEFINED}. 268193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * 268293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param start the start index 268393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param alignment the alignment 26847b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * 26857b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * @see #spec(int, int, Alignment) 268693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne */ 268793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public static Spec spec(int start, Alignment alignment) { 268893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne return spec(start, 1, alignment); 268993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne } 269093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne 269193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne /** 26925125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * Return a Spec, {@code spec}, where: 26935125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <ul> 26945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <li> {@code spec.span = [start, start + size]} </li> 26955125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * </ul> 26967b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * <p> 26977b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * To leave the start index undefined, use the value {@link #UNDEFINED}. 26985125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * 26995125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * @param start the start 27005125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * @param size the size 27017b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * 27027b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * @see #spec(int, Alignment) 27035125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne */ 27045125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public static Spec spec(int start, int size) { 27055125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return spec(start, size, UNDEFINED_ALIGNMENT); 27065125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 27075125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 27085125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne /** 27095125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * Return a Spec, {@code spec}, where: 27105125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <ul> 27115125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <li> {@code spec.span = [start, start + 1]} </li> 27125125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * </ul> 27137b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * <p> 27147b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * To leave the start index undefined, use the value {@link #UNDEFINED}. 27155125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * 27165125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * @param start the start index 27177b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * 27187b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * @see #spec(int, int) 27195125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne */ 27205125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public static Spec spec(int start) { 27215125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return spec(start, 1); 27225125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 27235125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 27245125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne /** 27253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Alignments specify where a view should be placed within a cell group and 27263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * what size it should be. 27273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 272893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec} 272993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an 273093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@code alignment}. Overall placement of the view in the cell 27313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * group is specified by the two alignments which act along each axis independently. 27323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 2733a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne * The GridLayout class defines the most common alignments used in general layout: 27346216e87fe8ad3273855233965b34049d22763e94Philip Milne * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #START}, 27356216e87fe8ad3273855233965b34049d22763e94Philip Milne * {@link #END}, {@link #CENTER}, {@link #BASELINE} and {@link #FILL}. 2736a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne */ 2737a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne /* 2738c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)}, 27393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to return the appropriate value for the type of alignment being defined. 27403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The enclosing algorithms position the children 27411e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * so that the locations defined by the alignment values 27423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * are the same for all of the views in a group. 27433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 27443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2745c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public static abstract class Alignment { 274648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Alignment() { 2747a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2748a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 27496216e87fe8ad3273855233965b34049d22763e94Philip Milne abstract int getGravityOffset(View view, int cellDelta); 27506216e87fe8ad3273855233965b34049d22763e94Philip Milne 27513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 27523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns an alignment value. In the case of vertical alignments the value 27533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * returned should indicate the distance from the top of the view to the 27543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * alignment location. 27553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * For horizontal alignments measurement is made from the left edge of the component. 27563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 2757c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param view the view to which this alignment should be applied 2758c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param viewSize the measured size of the view 27597a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne * @param mode the basis of alignment: CLIP or OPTICAL 2760b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne * @return the alignment value 27613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 27627a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne abstract int getAlignmentValue(View view, int viewSize, int mode); 27633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 27643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 27653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the size of the view specified by this alignment. 27663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * In the case of vertical alignments this method should return a height; for 27673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * horizontal alignments this method should return the width. 2768c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * <p> 2769c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * The default implementation returns {@code viewSize}. 2770c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * 2771c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param view the view to which this alignment should be applied 2772c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param viewSize the measured size of the view 2773c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param cellSize the size of the cell into which this view will be placed 2774b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne * @return the aligned size 27753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 27766216e87fe8ad3273855233965b34049d22763e94Philip Milne int getSizeInCell(View view, int viewSize, int cellSize) { 27773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return viewSize; 27783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2779a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 278048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Bounds getBounds() { 2781a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne return new Bounds(); 2782a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 27833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 27843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2785f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final Alignment UNDEFINED_ALIGNMENT = new Alignment() { 278647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 27876216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 27886216e87fe8ad3273855233965b34049d22763e94Philip Milne return UNDEFINED; 27896216e87fe8ad3273855233965b34049d22763e94Philip Milne } 27906216e87fe8ad3273855233965b34049d22763e94Philip Milne 27916216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 27927a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 27935125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return UNDEFINED; 27945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 27955125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne }; 27965125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 279747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio /** 279847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>start</em> 279947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * edges of the other views in its cell group. 280047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio */ 2801c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne private static final Alignment LEADING = new Alignment() { 280247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 28036216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 28046216e87fe8ad3273855233965b34049d22763e94Philip Milne return 0; 28056216e87fe8ad3273855233965b34049d22763e94Philip Milne } 28066216e87fe8ad3273855233965b34049d22763e94Philip Milne 28076216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 28087a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 28093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return 0; 28103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 28113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 28123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 281347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio /** 281447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>end</em> 281547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * edges of the other views in its cell group. 281647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio */ 2817c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne private static final Alignment TRAILING = new Alignment() { 281847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 28196216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 28206216e87fe8ad3273855233965b34049d22763e94Philip Milne return cellDelta; 28216216e87fe8ad3273855233965b34049d22763e94Philip Milne } 28226216e87fe8ad3273855233965b34049d22763e94Philip Milne 28236216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 28247a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 28253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return viewSize; 28263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 28273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 28283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 28293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 28303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>top</em> 28313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 28323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 28333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment TOP = LEADING; 28343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 28353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 28363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>bottom</em> 28373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 28383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 28393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment BOTTOM = TRAILING; 28403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 28413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 284247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>start</em> 28433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 28443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 284547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio public static final Alignment START = LEADING; 284647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio 284747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio /** 284847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>end</em> 284947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * edges of the other views in its cell group. 285047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio */ 285147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio public static final Alignment END = TRAILING; 285247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio 28536216e87fe8ad3273855233965b34049d22763e94Philip Milne private static Alignment createSwitchingAlignment(final Alignment ltr, final Alignment rtl) { 285447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio return new Alignment() { 285547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 28566216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 28576216e87fe8ad3273855233965b34049d22763e94Philip Milne return (!view.isLayoutRtl() ? ltr : rtl).getGravityOffset(view, cellDelta); 28586216e87fe8ad3273855233965b34049d22763e94Philip Milne } 28596216e87fe8ad3273855233965b34049d22763e94Philip Milne 28606216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 28617a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 28627a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne return (!view.isLayoutRtl() ? ltr : rtl).getAlignmentValue(view, viewSize, mode); 286347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio } 286447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio }; 286547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio } 28663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 28673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 28683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>left</em> 28693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 28703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 28716216e87fe8ad3273855233965b34049d22763e94Philip Milne public static final Alignment LEFT = createSwitchingAlignment(START, END); 287247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio 287347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio /** 287447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>right</em> 287547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * edges of the other views in its cell group. 287647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio */ 28776216e87fe8ad3273855233965b34049d22763e94Philip Milne public static final Alignment RIGHT = createSwitchingAlignment(END, START); 28783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 28793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 28803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be <em>centered</em> with the other views in its cell group. 288193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link 288293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * LayoutParams#columnSpec columnSpecs}. 28833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2884c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public static final Alignment CENTER = new Alignment() { 288547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 28866216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 28876216e87fe8ad3273855233965b34049d22763e94Philip Milne return cellDelta >> 1; 28886216e87fe8ad3273855233965b34049d22763e94Philip Milne } 28896216e87fe8ad3273855233965b34049d22763e94Philip Milne 28906216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 28917a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 28923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return viewSize >> 1; 28933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 28943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 28953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 28963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 28973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>baselines</em> 28983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * of the other views in its cell group. 289993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}. 29003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 29013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see View#getBaseline() 29023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2903c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public static final Alignment BASELINE = new Alignment() { 290447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 29056216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 29066216e87fe8ad3273855233965b34049d22763e94Philip Milne return 0; // baseline gravity is top 29076216e87fe8ad3273855233965b34049d22763e94Philip Milne } 29086216e87fe8ad3273855233965b34049d22763e94Philip Milne 29096216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 29107a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 2911a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne if (view.getVisibility() == GONE) { 2912a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne return 0; 2913a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne } 29143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int baseline = view.getBaseline(); 29157b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne return baseline == -1 ? UNDEFINED : baseline; 2916a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2917a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2918a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 2919a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne public Bounds getBounds() { 2920a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne return new Bounds() { 2921a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne /* 2922a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne In a baseline aligned row in which some components define a baseline 2923a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne and some don't, we need a third variable to properly account for all 2924a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne the sizes. This tracks the maximum size of all the components - 2925a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne including those that don't define a baseline. 2926a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne */ 2927a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne private int size; 2928a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2929a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 2930a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void reset() { 2931a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne super.reset(); 293248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne size = Integer.MIN_VALUE; 2933a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2934a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2935a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 2936a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void include(int before, int after) { 2937a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne super.include(before, after); 2938a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne size = max(size, before + after); 2939a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2940a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2941a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 294248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne protected int size(boolean min) { 294348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return max(super.size(min), size); 2944a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2945a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2946a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 29471557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) { 29481557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne return max(0, super.getOffset(gl, c, a, size, hrz)); 2949a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2950a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne }; 29513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 29523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 29533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 29543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 29553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should expanded to fit the boundaries of its cell group. 295693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and 295793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@link LayoutParams#columnSpec columnSpecs}. 29583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 29593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment FILL = new Alignment() { 296047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 29616216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 29626216e87fe8ad3273855233965b34049d22763e94Philip Milne return 0; 29636216e87fe8ad3273855233965b34049d22763e94Philip Milne } 29646216e87fe8ad3273855233965b34049d22763e94Philip Milne 29656216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 29667a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 29673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return UNDEFINED; 29683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 29693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2970c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne @Override 29716216e87fe8ad3273855233965b34049d22763e94Philip Milne public int getSizeInCell(View view, int viewSize, int cellSize) { 29723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return cellSize; 29733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 29743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 297548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 2976f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static boolean canStretch(int flexibility) { 29775d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne return (flexibility & CAN_STRETCH) != 0; 29785d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 29795d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 29805125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne private static final int INFLEXIBLE = 0; 29814c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne private static final int CAN_STRETCH = 2; 2982452eec33d667f9e705b57e60948b070536fbc1b4Jim Miller} 2983