1e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet/* 2e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Copyright (C) 2011 The Android Open Source Project 3e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 4e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License"); 5e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * you may not use this file except in compliance with the License. 6e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * You may obtain a copy of the License at 7e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 8e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * http://www.apache.org/licenses/LICENSE-2.0 9e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 10e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software 11e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS, 12e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * See the License for the specific language governing permissions and 14e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * limitations under the License. 15e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 16e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 17e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetpackage android.support.v7.widget; 18e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 19e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.content.Context; 20e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.content.res.TypedArray; 21e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.graphics.Canvas; 22e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.graphics.Paint; 23b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powellimport android.support.v4.view.GravityCompat; 24b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powellimport android.support.v4.view.ViewCompat; 25b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powellimport android.support.v4.view.ViewGroupCompat; 26e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.util.AttributeSet; 27e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.util.Log; 282c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglioimport android.util.LogPrinter; 29e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.util.Pair; 302c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglioimport android.util.Printer; 31e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.view.Gravity; 32e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.view.View; 33e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.view.ViewGroup; 34e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.widget.LinearLayout; 35e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 36e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport android.support.v7.gridlayout.R; 37e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 38e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.lang.reflect.Array; 39e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.ArrayList; 40e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.Arrays; 41e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.HashMap; 42e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.List; 43e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport java.util.Map; 44e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 45e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static android.view.Gravity.*; 46e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static android.view.View.MeasureSpec.EXACTLY; 47e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static android.view.View.MeasureSpec.makeMeasureSpec; 48e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static java.lang.Math.max; 49e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohetimport static java.lang.Math.min; 50e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 51e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet/** 52e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * A layout that places its children in a rectangular <em>grid</em>. 53e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 54e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The grid is composed of a set of infinitely thin lines that separate the 55e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced 56e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * by grid <em>indices</em>. A grid with {@code N} columns 57e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * has {@code N + 1} grid indices that run from {@code 0} 58e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * through {@code N} inclusive. Regardless of how GridLayout is 59e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * configured, grid index {@code 0} is fixed to the leading edge of the 60e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * container and grid index {@code N} is fixed to its trailing edge 61e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * (after padding is taken into account). 62e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 63e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Row and Column Specs</h4> 64e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 65e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Children occupy one or more contiguous cells, as defined 66e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and 67e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters. 68e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Each spec defines the set of rows or columns that are to be 69e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * occupied; and how children should be aligned within the resulting group of cells. 70e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Although cells do not normally overlap in a GridLayout, GridLayout does 71e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * not prevent children being defined to occupy the same cell or group of cells. 72e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * In this case however, there is no guarantee that children will not themselves 73e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * overlap after the layout operation completes. 74e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 75e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Default Cell Assignment</h4> 76e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 77e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * If a child does not specify the row and column indices of the cell it 78e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * wishes to occupy, GridLayout assigns cell locations automatically using its: 79e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setOrientation(int) orientation}, 80e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setRowCount(int) rowCount} and 81e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setColumnCount(int) columnCount} properties. 82e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 83e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Space</h4> 84e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 85e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Space between children may be specified either by using instances of the 86b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell * dedicated {@link android.support.v7.widget.Space} view or by setting the 87e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 88e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup.MarginLayoutParams#leftMargin leftMargin}, 89e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup.MarginLayoutParams#topMargin topMargin}, 90e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup.MarginLayoutParams#rightMargin rightMargin} and 91e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup.MarginLayoutParams#bottomMargin bottomMargin} 92e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 93e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * layout parameters. When the 94e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} 95e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * property is set, default margins around children are automatically 96e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * allocated based on the prevailing UI style guide for the platform. 97e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Each of the margins so defined may be independently overridden by an assignment 98e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * to the appropriate layout parameter. 99e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Default values will generally produce a reasonable spacing between components 100e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * but values may change between different releases of the platform. 101e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 102e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Excess Space Distribution</h4> 103e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 104e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * GridLayout's distribution of excess space accommodates the principle of weight. 105e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * In the event that no weights are specified, columns and rows are taken as 106e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * flexible if their views specify some form of alignment within their groups. 107e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 108e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * The flexibility of a view is therefore influenced by its alignment which is, 109e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * in turn, typically defined by setting the 110e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters. 111e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * If either a weight or alignment were defined along a given axis then the component 112e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * is taken as <em>flexible</em> in that direction. If no weight or alignment was set, 113e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * the component is instead assumed to be <em>inflexible</em>. 114e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 115e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Multiple components in the same row or column group are 116e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * considered to act in <em>parallel</em>. Such a 117e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * group is flexible only if <em>all</em> of the components 118e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * within it are flexible. Row and column groups that sit either side of a common boundary 119e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * are instead considered to act in <em>series</em>. The composite group made of these two 120e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * elements is flexible if <em>one</em> of its elements is flexible. 121e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 122e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * To make a column stretch, make sure all of the components inside it define a 123e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * weight or a gravity. To prevent a column from stretching, ensure that one of the components 124e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * in the column does not define a weight or a gravity. 125e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 126e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When the principle of flexibility does not provide complete disambiguation, 127e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em> 128e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * and <em>bottom</em> edges. To be more precise, GridLayout treats each of its layout 129e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * parameters as a constraint in the a set of variables that define the grid-lines along a 130e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * given axis. During layout, GridLayout solves the constraints so as to return the unique 131e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * solution to those constraints for which all variables are less-than-or-equal-to 132e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * the corresponding value in any other valid solution. 133e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1342c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <h4>Interpretation of GONE</h4> 1352c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 1362c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * For layout purposes, GridLayout treats views whose visibility status is 1372c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * {@link View#GONE GONE}, as having zero width and height. This is subtly different from 1382c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * the policy of ignoring views that are marked as GONE outright. If, for example, a gone-marked 1392c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * view was alone in a column, that column would itself collapse to zero width if and only if 1402c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * no gravity was defined on the view. If gravity was defined, then the gone-marked 1412c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * view has no effect on the layout and the container should be laid out as if the view 142aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar * had never been added to it. GONE views are taken to have zero weight during excess space 143aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar * distribution. 144aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar * <p> 1452c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * These statements apply equally to rows as well as columns, and to groups of rows or columns. 1462c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 147aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar * 148e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 149e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * See {@link GridLayout.LayoutParams} for a full description of the 150e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * layout parameters used by GridLayout. 151e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 152929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:orientation 153929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:rowCount 154929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:columnCount 155929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:useDefaultMargins 156929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:rowOrderPreserved 157929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:columnOrderPreserved 158e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 159e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milnepublic class GridLayout extends ViewGroup { 160e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 161e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Public constants 162e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 163e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 164e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The horizontal orientation. 165e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 166e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final int HORIZONTAL = LinearLayout.HORIZONTAL; 167e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 168e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 169e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The vertical orientation. 170e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 171e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final int VERTICAL = LinearLayout.VERTICAL; 172e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 173e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 174e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The constant used to indicate that a value is undefined. 175e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Fields can use this value to indicate that their values 176e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * have not yet been set. Similarly, methods can return this value 177e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * to indicate that there is no suitable value that the implementation 178e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * can return. 179e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The value used for the constant (currently {@link Integer#MIN_VALUE}) is 180e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * intended to avoid confusion between valid values whose sign may not be known. 181e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 182e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final int UNDEFINED = Integer.MIN_VALUE; 183e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 184e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 185e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * This constant is an {@link #setAlignmentMode(int) alignmentMode}. 186e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When the {@code alignmentMode} is set to {@link #ALIGN_BOUNDS}, alignment 187e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * is made between the edges of each component's raw 188e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * view boundary: i.e. the area delimited by the component's: 189e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link android.view.View#getTop() top}, 190e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link android.view.View#getLeft() left}, 191e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link android.view.View#getBottom() bottom} and 192e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link android.view.View#getRight() right} properties. 193e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 194e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * For example, when {@code GridLayout} is in {@link #ALIGN_BOUNDS} mode, 195e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * children that belong to a row group that uses {@link #TOP} alignment will 196e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * all return the same value when their {@link android.view.View#getTop()} 197e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * method is called. 198e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 199e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setAlignmentMode(int) 200e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 201e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final int ALIGN_BOUNDS = 0; 202e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 203e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 204e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * This constant is an {@link #setAlignmentMode(int) alignmentMode}. 205e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When the {@code alignmentMode} is set to {@link #ALIGN_MARGINS}, 206e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * the bounds of each view are extended outwards, according 207e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * to their margins, before the edges of the resulting rectangle are aligned. 208e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 209e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * For example, when {@code GridLayout} is in {@link #ALIGN_MARGINS} mode, 210e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * the quantity {@code top - layoutParams.topMargin} is the same for all children that 211e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * belong to a row group that uses {@link #TOP} alignment. 212e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 213e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setAlignmentMode(int) 214e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 215e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final int ALIGN_MARGINS = 1; 216e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 217e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Misc constants 218e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 219e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static final int MAX_SIZE = 100000; 220e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static final int DEFAULT_CONTAINER_MARGIN = 0; 221e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static final int UNINITIALIZED_HASH = 0; 2222c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio static final Printer LOG_PRINTER = new LogPrinter(Log.DEBUG, GridLayout.class.getName()); 2232c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio static final Printer NO_PRINTER = new Printer() { 2242c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio @Override 2252c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public void println(String x) { 2262c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 2272c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio }; 228e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 229e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Defaults 230e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 231e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int DEFAULT_ORIENTATION = HORIZONTAL; 232e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int DEFAULT_COUNT = UNDEFINED; 233e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false; 234e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final boolean DEFAULT_ORDER_PRESERVED = true; 235e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS; 236e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 237e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // TypedArray indices 238e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 239e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int ORIENTATION = R.styleable.GridLayout_orientation; 240e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int ROW_COUNT = R.styleable.GridLayout_rowCount; 241e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount; 242e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins; 243e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode; 244e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved; 245e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved; 246e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 247e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Instance variables 248e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 249b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell final Axis mHorizontalAxis = new Axis(true); 250b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell final Axis mVerticalAxis = new Axis(false); 251b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell int mOrientation = DEFAULT_ORIENTATION; 252b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS; 253b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell int mAlignmentMode = DEFAULT_ALIGNMENT_MODE; 254b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell int mDefaultGap; 255b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell int mLastLayoutParamsHashCode = UNINITIALIZED_HASH; 256b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell Printer mPrinter = LOG_PRINTER; 257e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 258e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Constructors 259e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 260e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 261e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@inheritDoc} 262e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 263e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public GridLayout(Context context, AttributeSet attrs, int defStyle) { 264e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet super(context, attrs, defStyle); 265b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap); 266e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout); 267e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet try { 268e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT)); 269e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT)); 270e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setOrientation(a.getInt(ORIENTATION, DEFAULT_ORIENTATION)); 271e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setUseDefaultMargins(a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS)); 272e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setAlignmentMode(a.getInt(ALIGNMENT_MODE, DEFAULT_ALIGNMENT_MODE)); 273e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); 274e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); 275e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } finally { 276e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet a.recycle(); 277e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 278e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 279e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 280e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 281e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@inheritDoc} 282e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 283e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public GridLayout(Context context, AttributeSet attrs) { 284e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this(context, attrs, 0); 285e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 286e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 287e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 288e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@inheritDoc} 289e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 290e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public GridLayout(Context context) { 291e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet //noinspection NullableProblems 292e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this(context, null); 293e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 294e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 295e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Implementation 296e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 297e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 298e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns the current orientation. 299e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 300e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return either {@link #HORIZONTAL} or {@link #VERTICAL} 301e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 302e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setOrientation(int) 303e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 304929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:orientation 305e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 306e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int getOrientation() { 307b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return mOrientation; 308e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 309e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 310e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 3112c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 3122c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * GridLayout uses the orientation property for two purposes: 3132c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <ul> 3142c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <li> 3152c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * To control the 'direction' in which default row/column indices are generated 3162c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * when they are not specified in a component's layout parameters. 3172c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * </li> 3182c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <li> 3192c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * To control which axis should be processed first during the layout operation: 3202c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * when orientation is {@link #HORIZONTAL} the horizontal axis is laid out first. 3212c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * </li> 3222c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * </ul> 3232c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 3242c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * The order in which axes are laid out is important if, for example, the height of 3252c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * one of GridLayout's children is dependent on its width - and its width is, in turn, 3262c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * dependent on the widths of other components. 3272c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <p> 3282c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * If your layout contains a {@link android.widget.TextView} (or derivative: 3292c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * {@code Button}, {@code EditText}, {@code CheckBox}, etc.) which is 3302c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * in multi-line mode (the default) it is normally best to leave GridLayout's 3312c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * orientation as {@code HORIZONTAL} - because {@code TextView} is capable of 3322c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * deriving its height for a given width, but not the other way around. 3332c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <p> 3342c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * Other than the effects above, orientation does not affect the actual layout operation of 3352c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * GridLayout, so it's fine to leave GridLayout in {@code HORIZONTAL} mode even if 3362c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * the height of the intended layout greatly exceeds its width. 337e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 338e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The default value of this property is {@link #HORIZONTAL}. 339e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 340e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param orientation either {@link #HORIZONTAL} or {@link #VERTICAL} 341e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 342e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #getOrientation() 343e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 344929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:orientation 345e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 346e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setOrientation(int orientation) { 347b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (this.mOrientation != orientation) { 348b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell this.mOrientation = orientation; 349e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateStructure(); 350e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet requestLayout(); 351e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 352e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 353e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 354e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 355e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns the current number of rows. This is either the last value that was set 356e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * with {@link #setRowCount(int)} or, if no such value was set, the maximum 357e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * value of each the upper bounds defined in {@link LayoutParams#rowSpec}. 358e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 359e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return the current number of rows 360e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 361e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setRowCount(int) 362e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see LayoutParams#rowSpec 363e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 364929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:rowCount 365e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 366e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int getRowCount() { 367b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return mVerticalAxis.getCount(); 368e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 369e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 370e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 371e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * RowCount is used only to generate default row/column indices when 372e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * they are not specified by a component's layout parameters. 373e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 374e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param rowCount the number of rows 375e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 376e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #getRowCount() 377e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see LayoutParams#rowSpec 378e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 379929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:rowCount 380e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 381e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setRowCount(int rowCount) { 382b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mVerticalAxis.setCount(rowCount); 383e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateStructure(); 384e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet requestLayout(); 385e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 386e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 387e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 388e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns the current number of columns. This is either the last value that was set 389e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * with {@link #setColumnCount(int)} or, if no such value was set, the maximum 390e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * value of each the upper bounds defined in {@link LayoutParams#columnSpec}. 391e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 392e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return the current number of columns 393e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 394e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setColumnCount(int) 395e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see LayoutParams#columnSpec 396e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 397929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:columnCount 398e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 399e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int getColumnCount() { 400b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return mHorizontalAxis.getCount(); 401e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 402e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 403e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 404e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * ColumnCount is used only to generate default column/column indices when 405e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * they are not specified by a component's layout parameters. 406e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 407e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param columnCount the number of columns. 408e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 409e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #getColumnCount() 410e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see LayoutParams#columnSpec 411e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 412929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:columnCount 413e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 414e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setColumnCount(int columnCount) { 415b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mHorizontalAxis.setCount(columnCount); 416e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateStructure(); 417e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet requestLayout(); 418e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 419e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 420e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 421e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns whether or not this GridLayout will allocate default margins when no 422e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * corresponding layout parameters are defined. 423e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 424e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return {@code true} if default margins should be allocated 425e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 426e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setUseDefaultMargins(boolean) 427e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 428929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:useDefaultMargins 429e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 430e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean getUseDefaultMargins() { 431b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return mUseDefaultMargins; 432e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 433e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 434e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 435e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When {@code true}, GridLayout allocates default margins around children 436e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * based on the child's visual characteristics. Each of the 437e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * margins so defined may be independently overridden by an assignment 438e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * to the appropriate layout parameter. 439e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 440e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When {@code false}, the default value of all margins is zero. 441e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 442e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When setting to {@code true}, consider setting the value of the 443e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link #setAlignmentMode(int) alignmentMode} 444e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * property to {@link #ALIGN_BOUNDS}. 445e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 446e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The default value of this property is {@code false}. 447e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 448e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins 449e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 450e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #getUseDefaultMargins() 451e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setAlignmentMode(int) 452e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 453e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see MarginLayoutParams#leftMargin 454e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see MarginLayoutParams#topMargin 455e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see MarginLayoutParams#rightMargin 456e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see MarginLayoutParams#bottomMargin 457e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 458929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:useDefaultMargins 459e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 460e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setUseDefaultMargins(boolean useDefaultMargins) { 461b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell this.mUseDefaultMargins = useDefaultMargins; 462e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet requestLayout(); 463e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 464e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 465e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 466e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns the alignment mode. 467e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 468e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return the alignment mode; either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS} 469e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 470e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #ALIGN_BOUNDS 471e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #ALIGN_MARGINS 472e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 473e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setAlignmentMode(int) 474e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 475929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:alignmentMode 476e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 477e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int getAlignmentMode() { 478b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return mAlignmentMode; 479e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 480e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 481e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 482e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Sets the alignment mode to be used for all of the alignments between the 483e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * children of this container. 484e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 485e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The default value of this property is {@link #ALIGN_MARGINS}. 486e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 487e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param alignmentMode either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS} 488e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 489e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #ALIGN_BOUNDS 490e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #ALIGN_MARGINS 491e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 492e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #getAlignmentMode() 493e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 494929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:alignmentMode 495e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 496e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setAlignmentMode(int alignmentMode) { 497b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell this.mAlignmentMode = alignmentMode; 498e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet requestLayout(); 499e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 500e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 501e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 502e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns whether or not row boundaries are ordered by their grid indices. 503e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 504e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return {@code true} if row boundaries must appear in the order of their indices, 505e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code false} otherwise 506e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 507e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setRowOrderPreserved(boolean) 508e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 509929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:rowOrderPreserved 510e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 511e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean isRowOrderPreserved() { 512b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return mVerticalAxis.isOrderPreserved(); 513e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 514e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 515e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 516e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When this property is {@code true}, GridLayout is forced to place the row boundaries 517e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * so that their associated grid indices are in ascending order in the view. 518e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 519e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When this property is {@code false} GridLayout is at liberty to place the vertical row 520e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * boundaries in whatever order best fits the given constraints. 521e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 522e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The default value of this property is {@code true}. 523e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 524e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param rowOrderPreserved {@code true} to force GridLayout to respect the order 525e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * of row boundaries 526e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 527e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #isRowOrderPreserved() 528e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 529929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:rowOrderPreserved 530e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 531e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setRowOrderPreserved(boolean rowOrderPreserved) { 532b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mVerticalAxis.setOrderPreserved(rowOrderPreserved); 533e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateStructure(); 534e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet requestLayout(); 535e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 536e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 537e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 538e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns whether or not column boundaries are ordered by their grid indices. 539e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 540e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return {@code true} if column boundaries must appear in the order of their indices, 541e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code false} otherwise 542e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 543e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #setColumnOrderPreserved(boolean) 544e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 545929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:columnOrderPreserved 546e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 547e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean isColumnOrderPreserved() { 548b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return mHorizontalAxis.isOrderPreserved(); 549e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 550e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 551e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 552e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When this property is {@code true}, GridLayout is forced to place the column boundaries 553e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * so that their associated grid indices are in ascending order in the view. 554e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 555e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * When this property is {@code false} GridLayout is at liberty to place the horizontal column 556e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * boundaries in whatever order best fits the given constraints. 557e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 558e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The default value of this property is {@code true}. 559e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 560e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param columnOrderPreserved use {@code true} to force GridLayout to respect the order 561e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * of column boundaries. 562e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 563e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see #isColumnOrderPreserved() 564e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 565929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:columnOrderPreserved 566e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 567e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setColumnOrderPreserved(boolean columnOrderPreserved) { 568b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mHorizontalAxis.setOrderPreserved(columnOrderPreserved); 569e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateStructure(); 570e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet requestLayout(); 571e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 572e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 5732c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio /** 5742c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * Return the printer that will log diagnostics from this layout. 5752c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 5762c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * @see #setPrinter(android.util.Printer) 5772c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 5782c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * @return the printer associated with this view 5792c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio */ 5802c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public Printer getPrinter() { 581b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return mPrinter; 5822c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 5832c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 5842c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio /** 5852c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * Set the printer that will log diagnostics from this layout. 5862c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * The default value is created by {@link android.util.LogPrinter}. 5872c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 5882c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * @param printer the printer associated with this layout 5892c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 5902c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * @see #getPrinter() 5912c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio */ 5922c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public void setPrinter(Printer printer) { 593b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell this.mPrinter = (printer == null) ? NO_PRINTER : printer; 5942c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 5952c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 596e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Static utility methods 597e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 598e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static int max2(int[] a, int valueIfEmpty) { 599e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int result = valueIfEmpty; 600e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = a.length; i < N; i++) { 601e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result = Math.max(result, a[i]); 602e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 603e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 604e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 605e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 606e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @SuppressWarnings("unchecked") 607e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static <T> T[] append(T[] a, T[] b) { 608e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length); 609e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet System.arraycopy(a, 0, result, 0, a.length); 610e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet System.arraycopy(b, 0, result, a.length, b.length); 611e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 612e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 613e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 614e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static Alignment getAlignment(int gravity, boolean horizontal) { 615e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK; 616e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT; 617e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int flags = (gravity & mask) >> shift; 618e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet switch (flags) { 619e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case (AXIS_SPECIFIED | AXIS_PULL_BEFORE): 6202c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return horizontal ? LEFT : TOP; 621e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case (AXIS_SPECIFIED | AXIS_PULL_AFTER): 6222c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return horizontal ? RIGHT : BOTTOM; 623e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER): 624e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return FILL; 625e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case AXIS_SPECIFIED: 626e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return CENTER; 627b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | GravityCompat.RELATIVE_LAYOUT_DIRECTION): 628e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return START; 629b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell case (AXIS_SPECIFIED | AXIS_PULL_AFTER | GravityCompat.RELATIVE_LAYOUT_DIRECTION): 630e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return END; 631e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet default: 632e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return UNDEFINED_ALIGNMENT; 633e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 634e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 635e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 636e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** @noinspection UnusedParameters*/ 637e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int getDefaultMargin(View c, boolean horizontal, boolean leading) { 638b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (c.getClass() == android.support.v7.widget.Space.class) { 639e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return 0; 640e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 641b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return mDefaultGap / 2; 642e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 643e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 644e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) { 6452c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return /*isAtEdge ? DEFAULT_CONTAINER_MARGIN :*/ getDefaultMargin(c, horizontal, leading); 646e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 647e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 6482c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) { 649b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (!mUseDefaultMargins) { 650e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return 0; 651e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 652e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec spec = horizontal ? p.columnSpec : p.rowSpec; 653b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 654e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval span = spec.span; 655b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell boolean leading1 = (horizontal && isLayoutRtlCompat()) ? !leading : leading; 656e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount()); 657e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 658e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return getDefaultMargin(c, isAtEdge, horizontal, leading); 659e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 660e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 661e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int getMargin1(View view, boolean horizontal, boolean leading) { 662e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams lp = getLayoutParams(view); 663e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int margin = horizontal ? 664e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet (leading ? lp.leftMargin : lp.rightMargin) : 665e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet (leading ? lp.topMargin : lp.bottomMargin); 6662c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return margin == UNDEFINED ? getDefaultMargin(view, lp, horizontal, leading) : margin; 667e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 668e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 669b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell private boolean isLayoutRtlCompat() { 670b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL; 671b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell } 672b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell 673e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int getMargin(View view, boolean horizontal, boolean leading) { 674b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (mAlignmentMode == ALIGN_MARGINS) { 675e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return getMargin1(view, horizontal, leading); 676e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } else { 677b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 678e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins(); 679e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams lp = getLayoutParams(view); 680e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 681e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int index = leading ? spec.span.min : spec.span.max; 682e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return margins[index]; 683e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 684e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 685e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 686e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int getTotalMargin(View child, boolean horizontal) { 687e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return getMargin(child, horizontal, true) + getMargin(child, horizontal, false); 688e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 689e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 690e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static boolean fits(int[] a, int value, int start, int end) { 691e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (end > a.length) { 692e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 693e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 694e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = start; i < end; i++) { 695e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (a[i] > value) { 696e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 697e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 698e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 699e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return true; 700e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 701e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 702e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static void procrusteanFill(int[] a, int start, int end, int value) { 703e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int length = a.length; 704e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arrays.fill(a, Math.min(start, length), Math.min(end, length), value); 705e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 706e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 707e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static void setCellGroup(LayoutParams lp, int row, int rowSpan, int col, int colSpan) { 708e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet lp.setRowSpecSpan(new Interval(row, row + rowSpan)); 709e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet lp.setColumnSpecSpan(new Interval(col, col + colSpan)); 710e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 711e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 712e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Logic to avert infinite loops by ensuring that the cells can be placed somewhere. 713e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static int clip(Interval minorRange, boolean minorWasDefined, int count) { 714e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int size = minorRange.size(); 715e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (count == 0) { 716e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return size; 717e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 718e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int min = minorWasDefined ? min(minorRange.min, count) : 0; 719e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return min(size, count - min); 720e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 721e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 722e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // install default indices for cells that don't define them 723e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void validateLayoutParams() { 724b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell final boolean horizontal = (mOrientation == HORIZONTAL); 725b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell final Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 726e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0; 727e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 728e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int major = 0; 729e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int minor = 0; 730e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int[] maxSizes = new int[count]; 731e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 732e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = getChildCount(); i < N; i++) { 733e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); 734e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 735e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec; 736e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final Interval majorRange = majorSpec.span; 737e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final boolean majorWasDefined = majorSpec.startDefined; 738e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final int majorSpan = majorRange.size(); 739e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (majorWasDefined) { 740e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet major = majorRange.min; 741e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 742e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 743e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec; 744e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final Interval minorRange = minorSpec.span; 745e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final boolean minorWasDefined = minorSpec.startDefined; 746e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final int minorSpan = clip(minorRange, minorWasDefined, count); 747e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (minorWasDefined) { 748e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet minor = minorRange.min; 749e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 750e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 751e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (count != 0) { 752e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Find suitable row/col values when at least one is undefined. 753e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!majorWasDefined || !minorWasDefined) { 754e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet while (!fits(maxSizes, major, minor, minor + minorSpan)) { 755e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (minorWasDefined) { 756e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet major++; 757e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } else { 758e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (minor + minorSpan <= count) { 759e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet minor++; 760e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } else { 761e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet minor = 0; 762e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet major++; 763e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 764e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 765e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 766e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 767e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet procrusteanFill(maxSizes, minor, minor + minorSpan, major + majorSpan); 768e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 769e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 770e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (horizontal) { 771e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setCellGroup(lp, major, majorSpan, minor, minorSpan); 772e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } else { 773e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setCellGroup(lp, minor, minorSpan, major, majorSpan); 774e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 775e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 776e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet minor = minor + minorSpan; 777e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 778e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 779e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 780e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void invalidateStructure() { 781b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mLastLayoutParamsHashCode = UNINITIALIZED_HASH; 782b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (mHorizontalAxis != null) mHorizontalAxis.invalidateStructure(); 783b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (mVerticalAxis != null) mVerticalAxis.invalidateStructure(); 784e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // This can end up being done twice. Better twice than not at all. 785e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateValues(); 786e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 787e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 788e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void invalidateValues() { 789e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Need null check because requestLayout() is called in View's initializer, 790e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // before we are set up. 791b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (mHorizontalAxis != null && mVerticalAxis != null) { 792b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mHorizontalAxis.invalidateValues(); 793b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mVerticalAxis.invalidateValues(); 7942c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 795e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 796e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 797e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final LayoutParams getLayoutParams(View c) { 798e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return (LayoutParams) c.getLayoutParams(); 799e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 800e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 8012c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio private static void handleInvalidParams(String msg) { 8022c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio throw new IllegalArgumentException(msg + ". "); 8032c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 8042c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 8052c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio private void checkLayoutParams(LayoutParams lp, boolean horizontal) { 8062c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio String groupName = horizontal ? "column" : "row"; 8072c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 8082c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio Interval span = spec.span; 8092c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio if (span.min != UNDEFINED && span.min < 0) { 8102c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio handleInvalidParams(groupName + " indices must be positive"); 8112c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 812b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 8132c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int count = axis.definedCount; 8142c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio if (count != UNDEFINED) { 8152c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio if (span.max > count) { 8162c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio handleInvalidParams(groupName + 8172c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio " indices (start + span) mustn't exceed the " + groupName + " count"); 8182c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 8192c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio if (span.size() > count) { 8202c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio handleInvalidParams(groupName + " span mustn't exceed the " + groupName + " count"); 8212c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 8222c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 8232c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 8242c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 8252c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio @Override 8262c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 8272c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio if (!(p instanceof LayoutParams)) { 8282c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return false; 8292c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 8302c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio LayoutParams lp = (LayoutParams) p; 8312c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 8322c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio checkLayoutParams(lp, true); 8332c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio checkLayoutParams(lp, false); 8342c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 8352c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return true; 8362c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 8372c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 838e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 839e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected LayoutParams generateDefaultLayoutParams() { 840e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return new LayoutParams(); 841e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 842e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 843e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 844e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public LayoutParams generateLayoutParams(AttributeSet attrs) { 845e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return new LayoutParams(getContext(), attrs); 846e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 847e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 848e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 84970d141daa825e7443df4aa149acddbfdb0bab64aYigit Boyar protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { 85070d141daa825e7443df4aa149acddbfdb0bab64aYigit Boyar if (lp instanceof LayoutParams) { 85170d141daa825e7443df4aa149acddbfdb0bab64aYigit Boyar return new LayoutParams((LayoutParams) lp); 85270d141daa825e7443df4aa149acddbfdb0bab64aYigit Boyar } else if (lp instanceof MarginLayoutParams) { 85370d141daa825e7443df4aa149acddbfdb0bab64aYigit Boyar return new LayoutParams((MarginLayoutParams) lp); 85470d141daa825e7443df4aa149acddbfdb0bab64aYigit Boyar } else { 85570d141daa825e7443df4aa149acddbfdb0bab64aYigit Boyar return new LayoutParams(lp); 85670d141daa825e7443df4aa149acddbfdb0bab64aYigit Boyar } 857e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 858e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 859e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Draw grid 860e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 861e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) { 862b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (isLayoutRtlCompat()) { 863e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int width = getWidth(); 8642c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio graphics.drawLine(width - x1, y1, width - x2, y2, paint); 865e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } else { 8662c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio graphics.drawLine(x1, y1, x2, y2, paint); 867e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 868e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 869e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 870e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int computeLayoutParamsHashCode() { 871e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int result = 1; 872e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = getChildCount(); i < N; i++) { 873e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet View c = getChildAt(i); 874e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (c.getVisibility() == View.GONE) continue; 875e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams lp = (LayoutParams) c.getLayoutParams(); 876e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result = 31 * result + lp.hashCode(); 877e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 878e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 879e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 880e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 8812c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio private void consistencyCheck() { 882b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (mLastLayoutParamsHashCode == UNINITIALIZED_HASH) { 8832c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio validateLayoutParams(); 884b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mLastLayoutParamsHashCode = computeLayoutParamsHashCode(); 885b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell } else if (mLastLayoutParamsHashCode != computeLayoutParamsHashCode()) { 886b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mPrinter.println("The fields of some layout parameters were modified in between " 8872c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio + "layout operations. Check the javadoc for GridLayout.LayoutParams#rowSpec."); 888e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateStructure(); 8892c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio consistencyCheck(); 890e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 891e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 892e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 893e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Measurement 894e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 8952c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio // Note: padding has already been removed from the supplied specs 896e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec, 897e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int childWidth, int childHeight) { 898e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int childWidthSpec = getChildMeasureSpec(parentWidthSpec, 8992c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio getTotalMargin(child, true), childWidth); 900e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int childHeightSpec = getChildMeasureSpec(parentHeightSpec, 9012c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio getTotalMargin(child, false), childHeight); 902e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet child.measure(childWidthSpec, childHeightSpec); 903e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 904e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 9052c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio // Note: padding has already been removed from the supplied specs 906e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) { 907e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = getChildCount(); i < N; i++) { 908e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet View c = getChildAt(i); 909e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (c.getVisibility() == View.GONE) continue; 910e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams lp = getLayoutParams(c); 911e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (firstPass) { 912e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height); 913e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } else { 914b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell boolean horizontal = (mOrientation == HORIZONTAL); 915e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 916aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar if (spec.getAbsoluteAlignment(horizontal) == FILL) { 917e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval span = spec.span; 918b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 919e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int[] locations = axis.getLocations(); 920e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int cellSize = locations[span.max] - locations[span.min]; 921e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int viewSize = cellSize - getTotalMargin(c, horizontal); 922e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (horizontal) { 923e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet measureChildWithMargins2(c, widthSpec, heightSpec, viewSize, lp.height); 924e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } else { 925e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, viewSize); 926e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 927e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 928e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 929e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 930e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 931e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 9322c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio static int adjust(int measureSpec, int delta) { 9332c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return makeMeasureSpec( 9342c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio MeasureSpec.getSize(measureSpec + delta), MeasureSpec.getMode(measureSpec)); 9352c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 9362c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 937e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 938e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected void onMeasure(int widthSpec, int heightSpec) { 9392c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio consistencyCheck(); 940e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 941e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** If we have been called by {@link View#measure(int, int)}, one of width or height 942e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * is likely to have changed. We must invalidate if so. */ 943e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateValues(); 944e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 9452c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int hPadding = getPaddingLeft() + getPaddingRight(); 9462c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int vPadding = getPaddingTop() + getPaddingBottom(); 9472c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 9482c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int widthSpecSansPadding = adjust( widthSpec, -hPadding); 9492c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int heightSpecSansPadding = adjust(heightSpec, -vPadding); 950e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 9512c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, true); 9522c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 9532c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int widthSansPadding; 9542c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int heightSansPadding; 955e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 956e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Use the orientation property to decide which axis should be laid out first. 957b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell if (mOrientation == HORIZONTAL) { 958b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding); 9592c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false); 960b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding); 961e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } else { 962b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding); 9632c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false); 964b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding); 965e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 966e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 9672c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int measuredWidth = Math.max(widthSansPadding + hPadding, getSuggestedMinimumWidth()); 9682c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int measuredHeight = Math.max(heightSansPadding + vPadding, getSuggestedMinimumHeight()); 969e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 970e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setMeasuredDimension( 971b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell ViewCompat.resolveSizeAndState(measuredWidth, widthSpec, 0), 972b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell ViewCompat.resolveSizeAndState(measuredHeight, heightSpec, 0)); 973e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 974e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 975e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int getMeasurement(View c, boolean horizontal) { 976e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight(); 977e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 978e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 979e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final int getMeasurementIncludingMargin(View c, boolean horizontal) { 980e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (c.getVisibility() == View.GONE) { 981e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return 0; 982e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 983e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal); 984e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 985e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 986e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 987e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void requestLayout() { 988e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet super.requestLayout(); 989b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell invalidateStructure(); 990e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 991e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 992e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Layout container 993e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 994e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 995e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@inheritDoc} 996e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 997e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 998e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet The layout operation is implemented by delegating the heavy lifting to the 999e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet to the mHorizontalAxis and mVerticalAxis instances of the internal Axis class. 1000e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Together they compute the locations of the vertical and horizontal lines of 1001e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet the grid (respectively!). 1002e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1003e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet This method is then left with the simpler task of applying margins, gravity 1004e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet and sizing to each child view and then placing it in its cell. 1005e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1006e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 1007e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 10082c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio consistencyCheck(); 1009e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1010e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int targetWidth = right - left; 1011e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int targetHeight = bottom - top; 1012e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1013e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int paddingLeft = getPaddingLeft(); 1014e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int paddingTop = getPaddingTop(); 1015e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int paddingRight = getPaddingRight(); 1016e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int paddingBottom = getPaddingBottom(); 1017e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1018b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight); 1019b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom); 1020e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1021b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell int[] hLocations = mHorizontalAxis.getLocations(); 1022b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell int[] vLocations = mVerticalAxis.getLocations(); 1023e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1024e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = getChildCount(); i < N; i++) { 1025e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet View c = getChildAt(i); 1026e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (c.getVisibility() == View.GONE) continue; 1027e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams lp = getLayoutParams(c); 1028e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec columnSpec = lp.columnSpec; 1029e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec rowSpec = lp.rowSpec; 1030e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1031e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval colSpan = columnSpec.span; 1032e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval rowSpan = rowSpec.span; 1033e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1034e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int x1 = hLocations[colSpan.min]; 1035e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int y1 = vLocations[rowSpan.min]; 1036e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1037e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int x2 = hLocations[colSpan.max]; 1038e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int y2 = vLocations[rowSpan.max]; 1039e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1040e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int cellWidth = x2 - x1; 1041e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int cellHeight = y2 - y1; 1042e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1043e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int pWidth = getMeasurement(c, true); 1044e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int pHeight = getMeasurement(c, false); 1045e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1046aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar Alignment hAlign = columnSpec.getAbsoluteAlignment(true); 1047aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar Alignment vAlign = rowSpec.getAbsoluteAlignment(false); 1048e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1049b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i); 1050b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i); 1051e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1052e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Gravity offsets: the location of the alignment group relative to its cell group. 1053e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true)); 1054e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int gravityOffsetY = vAlign.getGravityOffset(c, cellHeight - boundsY.size(true)); 1055e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1056e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int leftMargin = getMargin(c, true, true); 1057e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int topMargin = getMargin(c, false, true); 1058e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int rightMargin = getMargin(c, true, false); 1059e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int bottomMargin = getMargin(c, false, false); 1060e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 10612c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int sumMarginsX = leftMargin + rightMargin; 10622c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int sumMarginsY = topMargin + bottomMargin; 10632c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio 1064e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Alignment offsets: the location of the view relative to its alignment group. 10652c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true); 10662c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false); 1067e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 10682c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX); 10692c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY); 1070e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1071e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int dx = x1 + gravityOffsetX + alignmentOffsetX; 1072e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1073b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell int cx = !isLayoutRtlCompat() ? paddingLeft + leftMargin + dx : 1074e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet targetWidth - width - paddingRight - rightMargin - dx; 1075e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin; 1076e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1077e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) { 1078e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY)); 1079e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1080e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet c.layout(cx, cy, cx + width, cy + height); 1081e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1082e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1083e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1084e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Inner classes 1085e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1086e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 1087e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet This internal class houses the algorithm for computing the locations of grid lines; 1088e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet along either the horizontal or vertical axis. A GridLayout uses two instances of this class - 1089e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet distinguished by the "horizontal" flag which is true for the horizontal axis and false 1090e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for the vertical one. 1091e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1092e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final class Axis { 1093e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int NEW = 0; 1094e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int PENDING = 1; 1095e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int COMPLETE = 2; 1096e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1097e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public final boolean horizontal; 1098e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1099e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int definedCount = UNDEFINED; 1100e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int maxIndex = UNDEFINED; 1101e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1102e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet PackedMap<Spec, Bounds> groupBounds; 1103e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean groupBoundsValid = false; 1104e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1105e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet PackedMap<Interval, MutableInt> forwardLinks; 1106e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean forwardLinksValid = false; 1107e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1108e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet PackedMap<Interval, MutableInt> backwardLinks; 1109e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean backwardLinksValid = false; 1110e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1111e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int[] leadingMargins; 1112e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean leadingMarginsValid = false; 1113e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1114e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int[] trailingMargins; 1115e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean trailingMarginsValid = false; 1116e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1117e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public Arc[] arcs; 1118e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean arcsValid = false; 1119e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1120e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int[] locations; 1121e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean locationsValid = false; 1122e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1123e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne public boolean hasWeights; 1124e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne public boolean hasWeightsValid = false; 1125e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne public int[] deltas; 1126e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 1127e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet boolean orderPreserved = DEFAULT_ORDER_PRESERVED; 1128e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1129e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private MutableInt parentMin = new MutableInt(0); 1130e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private MutableInt parentMax = new MutableInt(-MAX_SIZE); 1131e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1132e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private Axis(boolean horizontal) { 1133e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.horizontal = horizontal; 1134e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1135e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1136e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int calculateMaxIndex() { 1137e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // the number Integer.MIN_VALUE + 1 comes up in undefined cells 1138e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int result = -1; 1139e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = getChildCount(); i < N; i++) { 1140e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet View c = getChildAt(i); 1141e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams params = getLayoutParams(c); 1142e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec spec = horizontal ? params.columnSpec : params.rowSpec; 1143e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval span = spec.span; 1144e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result = max(result, span.min); 1145e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result = max(result, span.max); 11462c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio result = max(result, span.size()); 1147e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1148e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result == -1 ? UNDEFINED : result; 1149e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1150e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1151e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int getMaxIndex() { 1152e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (maxIndex == UNDEFINED) { 1153e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet maxIndex = max(0, calculateMaxIndex()); // use zero when there are no children 1154e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1155e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return maxIndex; 1156e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1157e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1158e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int getCount() { 1159e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return max(definedCount, getMaxIndex()); 1160e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1161e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1162e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setCount(int count) { 11632c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio if (count != UNDEFINED && count < getMaxIndex()) { 11642c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio handleInvalidParams((horizontal ? "column" : "row") + 11652c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio "Count must be greater than or equal to the maximum of all grid indices " + 11662c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio "(and spans) defined in the LayoutParams of each child"); 11672c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 1168e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.definedCount = count; 1169e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1170e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1171e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean isOrderPreserved() { 1172e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return orderPreserved; 1173e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1174e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1175e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setOrderPreserved(boolean orderPreserved) { 1176e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.orderPreserved = orderPreserved; 1177e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateStructure(); 1178e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1179e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1180e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private PackedMap<Spec, Bounds> createGroupBounds() { 1181e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class); 1182e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = getChildCount(); i < N; i++) { 1183e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet View c = getChildAt(i); 11842c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio // we must include views that are GONE here, see introductory javadoc 1185e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams lp = getLayoutParams(c); 1186e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 1187aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar Bounds bounds = spec.getAbsoluteAlignment(horizontal).getBounds(); 1188e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet assoc.put(spec, bounds); 1189e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1190e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return assoc.pack(); 1191e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1192e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1193e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void computeGroupBounds() { 1194e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Bounds[] values = groupBounds.values; 1195e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < values.length; i++) { 1196e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet values[i].reset(); 1197e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1198e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = getChildCount(); i < N; i++) { 1199e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet View c = getChildAt(i); 12002c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio // we must include views that are GONE here, see introductory javadoc 1201e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams lp = getLayoutParams(c); 1202e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 1203ee781a599830945fa4c3f78c8a7e99c971fe5524Yigit Boyar int size = getMeasurementIncludingMargin(c, horizontal) + 1204ee781a599830945fa4c3f78c8a7e99c971fe5524Yigit Boyar ((spec.weight == 0) ? 0 : getDeltas()[i]); 1205e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size); 1206e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1207e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1208e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1209e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public PackedMap<Spec, Bounds> getGroupBounds() { 1210e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (groupBounds == null) { 1211e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet groupBounds = createGroupBounds(); 1212e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1213e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!groupBoundsValid) { 1214e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet computeGroupBounds(); 1215e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet groupBoundsValid = true; 1216e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1217e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return groupBounds; 1218e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1219e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1220e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Add values computed by alignment - taking the max of all alignments in each span 1221e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private PackedMap<Interval, MutableInt> createLinks(boolean min) { 1222e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class); 1223e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec[] keys = getGroupBounds().keys; 1224e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = keys.length; i < N; i++) { 1225e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval span = min ? keys[i].span : keys[i].span.inverse(); 1226e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result.put(span, new MutableInt()); 1227e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1228e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result.pack(); 1229e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1230e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1231e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) { 1232e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet MutableInt[] spans = links.values; 1233e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < spans.length; i++) { 1234e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet spans[i].reset(); 1235e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1236e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1237e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Use getter to trigger a re-evaluation 1238e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Bounds[] bounds = getGroupBounds().values; 1239e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < bounds.length; i++) { 1240e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int size = bounds[i].size(min); 1241e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet MutableInt valueHolder = links.getValue(i); 1242e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // this effectively takes the max() of the minima and the min() of the maxima 1243e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet valueHolder.value = max(valueHolder.value, min ? size : -size); 1244e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1245e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1246e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1247e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private PackedMap<Interval, MutableInt> getForwardLinks() { 1248e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (forwardLinks == null) { 1249e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet forwardLinks = createLinks(true); 1250e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1251e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!forwardLinksValid) { 1252e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet computeLinks(forwardLinks, true); 1253e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet forwardLinksValid = true; 1254e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1255e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return forwardLinks; 1256e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1257e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1258e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private PackedMap<Interval, MutableInt> getBackwardLinks() { 1259e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (backwardLinks == null) { 1260e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet backwardLinks = createLinks(false); 1261e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1262e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!backwardLinksValid) { 1263e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet computeLinks(backwardLinks, false); 1264e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet backwardLinksValid = true; 1265e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1266e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return backwardLinks; 1267e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1268e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1269e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void include(List<Arc> arcs, Interval key, MutableInt size, 1270e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet boolean ignoreIfAlreadyPresent) { 1271e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 1272e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Remove self referential links. 1273e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet These appear: 1274e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet . as parental constraints when GridLayout has no children 1275e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet . when components have been marked as GONE 1276e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1277e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (key.size() == 0) { 1278e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return; 1279e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1280e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // this bit below should really be computed outside here - 1281e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // its just to stop default (row/col > 0) constraints obliterating valid entries 1282e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (ignoreIfAlreadyPresent) { 1283e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (Arc arc : arcs) { 1284e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval span = arc.span; 1285e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (span.equals(key)) { 1286e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return; 1287e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1288e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1289e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1290e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet arcs.add(new Arc(key, size)); 1291e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1292e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1293e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void include(List<Arc> arcs, Interval key, MutableInt size) { 1294e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet include(arcs, key, size, true); 1295e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1296e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1297e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Group arcs by their first vertex, returning an array of arrays. 1298e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // This is linear in the number of arcs. 1299e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arc[][] groupArcsByFirstVertex(Arc[] arcs) { 1300e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int N = getCount() + 1; // the number of vertices 1301e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arc[][] result = new Arc[N][]; 1302e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int[] sizes = new int[N]; 1303e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (Arc arc : arcs) { 1304e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet sizes[arc.span.min]++; 1305e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1306e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < sizes.length; i++) { 1307e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result[i] = new Arc[sizes[i]]; 1308e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1309e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // reuse the sizes array to hold the current last elements as we insert each arc 1310e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arrays.fill(sizes, 0); 1311e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (Arc arc : arcs) { 1312e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int i = arc.span.min; 1313e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result[i][sizes[i]++] = arc; 1314e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1315e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1316e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 1317e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1318e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1319e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private Arc[] topologicalSort(final Arc[] arcs) { 1320e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return new Object() { 1321e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arc[] result = new Arc[arcs.length]; 1322e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int cursor = result.length - 1; 1323e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs); 1324e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int[] visited = new int[getCount() + 1]; 1325e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1326e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet void walk(int loc) { 1327e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet switch (visited[loc]) { 1328e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case NEW: { 1329e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet visited[loc] = PENDING; 1330e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (Arc arc : arcsByVertex[loc]) { 1331e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet walk(arc.span.max); 1332e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result[cursor--] = arc; 1333e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1334e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet visited[loc] = COMPLETE; 1335e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet break; 1336e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1337e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case PENDING: { 13382c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio // le singe est dans l'arbre 1339e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet assert false; 1340e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet break; 1341e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1342e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case COMPLETE: { 1343e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet break; 1344e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1345e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1346e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1347e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1348e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arc[] sort() { 1349e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) { 1350e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet walk(loc); 1351e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1352e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet assert cursor == -1; 1353e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 1354e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1355e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet }.sort(); 1356e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1357e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1358e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private Arc[] topologicalSort(List<Arc> arcs) { 1359e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return topologicalSort(arcs.toArray(new Arc[arcs.size()])); 1360e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1361e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1362e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) { 1363e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < links.keys.length; i++) { 1364e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval key = links.keys[i]; 1365e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet include(result, key, links.values[i], false); 1366e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1367e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1368e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1369e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private Arc[] createArcs() { 1370e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet List<Arc> mins = new ArrayList<Arc>(); 1371e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet List<Arc> maxs = new ArrayList<Arc>(); 1372e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1373e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Add the minimum values from the components. 1374e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet addComponentSizes(mins, getForwardLinks()); 1375e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Add the maximum values from the components. 1376e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet addComponentSizes(maxs, getBackwardLinks()); 1377e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1378e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Add ordering constraints to prevent row/col sizes from going negative 1379e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (orderPreserved) { 1380e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Add a constraint for every row/col 1381e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < getCount(); i++) { 1382e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet include(mins, new Interval(i, i + 1), new MutableInt(0)); 1383e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1384e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1385e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1386e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Add the container constraints. Use the version of include that allows 1387e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // duplicate entries in case a child spans the entire grid. 1388e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int N = getCount(); 1389e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet include(mins, new Interval(0, N), parentMin, false); 1390e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet include(maxs, new Interval(N, 0), parentMax, false); 1391e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1392e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Sort 1393e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arc[] sMins = topologicalSort(mins); 1394e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arc[] sMaxs = topologicalSort(maxs); 1395e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1396e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return append(sMins, sMaxs); 1397e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1398e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1399e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void computeArcs() { 1400e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // getting the links validates the values that are shared by the arc list 1401e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet getForwardLinks(); 1402e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet getBackwardLinks(); 1403e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1404e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1405e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public Arc[] getArcs() { 1406e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (arcs == null) { 1407e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet arcs = createArcs(); 1408e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1409e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!arcsValid) { 1410e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet computeArcs(); 1411e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet arcsValid = true; 1412e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1413e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return arcs; 1414e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1415e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1416e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private boolean relax(int[] locations, Arc entry) { 1417e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!entry.valid) { 1418e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 1419e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1420e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval span = entry.span; 1421e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int u = span.min; 1422e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int v = span.max; 1423e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int value = entry.value.value; 1424e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int candidate = locations[u] + value; 1425e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (candidate > locations[v]) { 1426e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet locations[v] = candidate; 1427e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return true; 1428e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1429e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 1430e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1431e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1432e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void init(int[] locations) { 1433e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arrays.fill(locations, 0); 1434e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1435e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1436e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private String arcsToString(List<Arc> arcs) { 1437e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet String var = horizontal ? "x" : "y"; 1438e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet StringBuilder result = new StringBuilder(); 1439e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet boolean first = true; 1440e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (Arc arc : arcs) { 1441e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (first) { 1442e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet first = false; 1443e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } else { 1444e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result = result.append(", "); 1445e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1446e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int src = arc.span.min; 1447e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int dst = arc.span.max; 1448e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int value = arc.value.value; 1449e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result.append((src < dst) ? 14502c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio var + dst + "-" + var + src + ">=" + value : 14512c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio var + src + "-" + var + dst + "<=" + -value); 1452e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1453e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1454e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result.toString(); 1455e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1456e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1457e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void logError(String axisName, Arc[] arcs, boolean[] culprits0) { 1458e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet List<Arc> culprits = new ArrayList<Arc>(); 1459e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet List<Arc> removed = new ArrayList<Arc>(); 1460e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int c = 0; c < arcs.length; c++) { 1461e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arc arc = arcs[c]; 1462e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (culprits0[c]) { 1463e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet culprits.add(arc); 1464e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1465e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!arc.valid) { 1466e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet removed.add(arc); 1467e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1468e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1469b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell mPrinter.println(axisName + " constraints: " + arcsToString(culprits) + 14702c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio " are inconsistent; permanently removing: " + arcsToString(removed) + ". "); 1471e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1472e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1473e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 1474e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N) 1475e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1476e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet GridLayout converts its requirements into a system of linear constraints of the 1477e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet form: 1478e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1479e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet x[i] - x[j] < a[k] 1480e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1481e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Where the x[i] are variables and the a[k] are constants. 1482e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1483e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet For example, if the variables were instead labeled x, y, z we might have: 1484e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1485e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet x - y < 17 1486e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet y - z < 23 1487e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet z - x < 42 1488e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1489e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet This is a special case of the Linear Programming problem that is, in turn, 1490e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet equivalent to the single-source shortest paths problem on a digraph, for 1491e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet which the O(n^2) Bellman-Ford algorithm the most commonly used general solution. 1492e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 14935f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar private boolean solve(Arc[] arcs, int[] locations) { 14945f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar return solve(arcs, locations, true); 14955f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar } 14965f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar 14975f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar private boolean solve(Arc[] arcs, int[] locations, boolean modifyOnError) { 1498e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet String axisName = horizontal ? "horizontal" : "vertical"; 1499e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1. 1500e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet boolean[] originalCulprits = null; 1501e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1502e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int p = 0; p < arcs.length; p++) { 1503e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet init(locations); 1504e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1505e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // We take one extra pass over traditional Bellman-Ford (and omit their final step) 1506e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < N; i++) { 1507e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet boolean changed = false; 1508e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int j = 0, length = arcs.length; j < length; j++) { 1509e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet changed |= relax(locations, arcs[j]); 1510e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1511e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!changed) { 1512e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (originalCulprits != null) { 1513e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet logError(axisName, arcs, originalCulprits); 1514e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 15155f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar return true; 1516e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1517e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1518e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 15195f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar if (!modifyOnError) { 15205f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar return false; // cannot solve with these constraints 15215f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar } 15225f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar 1523e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet boolean[] culprits = new boolean[arcs.length]; 1524e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < N; i++) { 1525e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int j = 0, length = arcs.length; j < length; j++) { 1526e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet culprits[j] |= relax(locations, arcs[j]); 1527e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1528e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1529e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1530e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (p == 0) { 1531e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet originalCulprits = culprits; 1532e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1533e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1534e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < arcs.length; i++) { 1535e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (culprits[i]) { 1536e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Arc arc = arcs[i]; 1537e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Only remove max values, min values alone cannot be inconsistent 1538e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (arc.span.min < arc.span.max) { 1539e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet continue; 1540e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1541e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet arc.valid = false; 1542e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet break; 1543e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1544e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1545e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 15465f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar return true; 1547e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1548e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1549e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void computeMargins(boolean leading) { 1550e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int[] margins = leading ? leadingMargins : trailingMargins; 1551e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = getChildCount(); i < N; i++) { 1552e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet View c = getChildAt(i); 1553e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (c.getVisibility() == View.GONE) continue; 1554e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams lp = getLayoutParams(c); 1555e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 1556e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval span = spec.span; 1557e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int index = leading ? span.min : span.max; 1558e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet margins[index] = max(margins[index], getMargin1(c, horizontal, leading)); 1559e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1560e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1561e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1562e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // External entry points 1563e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1564e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int[] getLeadingMargins() { 1565e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (leadingMargins == null) { 1566e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet leadingMargins = new int[getCount() + 1]; 1567e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1568e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!leadingMarginsValid) { 1569e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet computeMargins(true); 1570e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet leadingMarginsValid = true; 1571e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1572e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return leadingMargins; 1573e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1574e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1575e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int[] getTrailingMargins() { 1576e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (trailingMargins == null) { 1577e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet trailingMargins = new int[getCount() + 1]; 1578e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1579e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!trailingMarginsValid) { 1580e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet computeMargins(false); 1581e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet trailingMarginsValid = true; 1582e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1583e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return trailingMargins; 1584e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1585e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 15865f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar private boolean solve(int[] a) { 15875f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar return solve(getArcs(), a); 1588e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1589e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 1590e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne private boolean computeHasWeights() { 1591e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1592aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar final View child = getChildAt(i); 1593aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar if (child.getVisibility() == View.GONE) { 1594aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar continue; 1595aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 1596aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar LayoutParams lp = getLayoutParams(child); 1597e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 1598e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne if (spec.weight != 0) { 1599e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return true; 1600e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1601e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1602e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return false; 1603e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1604e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 1605e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne private boolean hasWeights() { 1606e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne if (!hasWeightsValid) { 1607e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne hasWeights = computeHasWeights(); 1608e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne hasWeightsValid = true; 1609e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1610e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return hasWeights; 1611e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1612e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 1613e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne public int[] getDeltas() { 1614e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne if (deltas == null) { 1615e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne deltas = new int[getChildCount()]; 1616e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1617e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return deltas; 1618e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1619e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 16205f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar private void shareOutDelta(int totalDelta, float totalWeight) { 16215f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar Arrays.fill(deltas, 0); 1622e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1623aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar final View c = getChildAt(i); 1624aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar if (c.getVisibility() == View.GONE) { 1625aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar continue; 1626aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 1627e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne LayoutParams lp = getLayoutParams(c); 1628e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 1629e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne float weight = spec.weight; 1630e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne if (weight != 0) { 1631e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne int delta = Math.round((weight * totalDelta / totalWeight)); 1632e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne deltas[i] = delta; 16335f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar // the two adjustments below are to counter the above rounding and avoid 16345f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar // off-by-ones at the end 1635e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne totalDelta -= delta; 1636e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne totalWeight -= weight; 1637e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1638e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1639e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1640e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 1641e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne private void solveAndDistributeSpace(int[] a) { 1642e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne Arrays.fill(getDeltas(), 0); 1643e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne solve(a); 16445f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar int deltaMax = parentMin.value * getChildCount() + 1; //exclusive 16455f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar if (deltaMax < 2) { 16465f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar return; //don't have any delta to distribute 16475f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar } 16485f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar int deltaMin = 0; //inclusive 16495f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar 16505f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar float totalWeight = calculateTotalWeight(); 16515f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar 16525f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar int validDelta = -1; //delta for which a solution exists 16535f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar boolean validSolution = true; 16545f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar // do a binary search to find the max delta that won't conflict with constraints 16555f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar while(deltaMin < deltaMax) { 16564145a44a9160898dcf9fee1f59caf91151ab0283Deepanshu Gupta // cast to long to prevent overflow. 16574145a44a9160898dcf9fee1f59caf91151ab0283Deepanshu Gupta final int delta = (int)(((long)deltaMin + deltaMax) / 2); 16585f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar invalidateValues(); 16595f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar shareOutDelta(delta, totalWeight); 16605f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar validSolution = solve(getArcs(), a, false); 16615f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar if (validSolution) { 16625f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar validDelta = delta; 16635f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar deltaMin = delta + 1; 16645f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar } else { 16655f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar deltaMax = delta; 16665f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar } 16675f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar } 16685f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar if (validDelta > 0 && !validSolution) { 16695f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar // last solution was not successful but we have a successful one. Use it. 16705f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar invalidateValues(); 16715f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar shareOutDelta(validDelta, totalWeight); 16725f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar solve(a); 16735f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar } 16745f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar } 16755f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar 16765f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar private float calculateTotalWeight() { 16775f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar float totalWeight = 0f; 16785f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar for (int i = 0, N = getChildCount(); i < N; i++) { 16795f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar View c = getChildAt(i); 1680aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar if (c.getVisibility() == View.GONE) { 1681aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar continue; 1682aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 16835f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar LayoutParams lp = getLayoutParams(c); 16845f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 16855f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar totalWeight += spec.weight; 16865f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar } 16875f355e700d63f67b1641f023d95e18c69c596ecbYigit Boyar return totalWeight; 1688e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1689e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 1690e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne private void computeLocations(int[] a) { 1691e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne if (!hasWeights()) { 1692e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne solve(a); 1693e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } else { 1694e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne solveAndDistributeSpace(a); 1695e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 1696e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!orderPreserved) { 1697e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Solve returns the smallest solution to the constraint system for which all 1698e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // values are positive. One value is therefore zero - though if the row/col 1699e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // order is not preserved this may not be the first vertex. For consistency, 1700e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // translate all the values so that they measure the distance from a[0]; the 1701e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // leading edge of the parent. After this transformation some values may be 1702e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // negative. 1703e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int a0 = a[0]; 1704e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0, N = a.length; i < N; i++) { 1705e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet a[i] = a[i] - a0; 1706e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1707e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1708e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1709e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1710e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int[] getLocations() { 1711e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (locations == null) { 1712e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int N = getCount() + 1; 1713e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet locations = new int[N]; 1714e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1715e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!locationsValid) { 1716e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet computeLocations(locations); 1717e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet locationsValid = true; 1718e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1719e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return locations; 1720e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1721e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1722e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int size(int[] locations) { 1723e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // The parental edges are attached to vertices 0 and N - even when order is not 1724e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // being preserved and other vertices fall outside this range. Measure the distance 1725e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // between vertices 0 and N, assuming that locations[0] = 0. 1726e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return locations[getCount()]; 1727e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1728e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1729e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void setParentConstraints(int min, int max) { 1730e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet parentMin.value = min; 1731e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet parentMax.value = -max; 1732e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet locationsValid = false; 1733e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1734e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1735e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int getMeasure(int min, int max) { 1736e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setParentConstraints(min, max); 1737e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return size(getLocations()); 1738e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1739e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1740e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int getMeasure(int measureSpec) { 1741e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int mode = MeasureSpec.getMode(measureSpec); 1742e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int size = MeasureSpec.getSize(measureSpec); 1743e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet switch (mode) { 1744e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case MeasureSpec.UNSPECIFIED: { 1745e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return getMeasure(0, MAX_SIZE); 1746e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1747e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case MeasureSpec.EXACTLY: { 1748e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return getMeasure(size, size); 1749e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1750e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet case MeasureSpec.AT_MOST: { 1751e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return getMeasure(0, size); 1752e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1753e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet default: { 1754e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet assert false; 1755e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return 0; 1756e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1757e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1758e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1759e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1760e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void layout(int size) { 1761e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setParentConstraints(size, size); 1762e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet getLocations(); 1763e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1764e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1765e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void invalidateStructure() { 1766e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet maxIndex = UNDEFINED; 1767e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1768e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet groupBounds = null; 1769e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet forwardLinks = null; 1770e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet backwardLinks = null; 1771e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1772e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet leadingMargins = null; 1773e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet trailingMargins = null; 1774e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet arcs = null; 1775e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1776e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet locations = null; 1777e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1778e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne deltas = null; 1779e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne hasWeightsValid = false; 1780e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 1781e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet invalidateValues(); 1782e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1783e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1784e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void invalidateValues() { 1785e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet groupBoundsValid = false; 1786e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet forwardLinksValid = false; 1787e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet backwardLinksValid = false; 1788e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1789e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet leadingMarginsValid = false; 1790e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet trailingMarginsValid = false; 1791e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet arcsValid = false; 1792e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1793e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet locationsValid = false; 1794e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1795e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1796e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1797e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 1798e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Layout information associated with each of the children of a GridLayout. 1799e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 1800e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * GridLayout supports both row and column spanning and arbitrary forms of alignment within 1801e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * each cell group. The fundamental parameters associated with each cell group are 1802e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * gathered into their vertical and horizontal components and stored 1803e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * in the {@link #rowSpec} and {@link #columnSpec} layout parameters. 1804e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout.Spec Specs} are immutable structures 1805e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * and may be shared between the layout parameters of different children. 1806e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 1807e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The row and column specs contain the leading and trailing indices along each axis 1808e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * and together specify the four grid indices that delimit the cells of this cell group. 1809e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 1810e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The alignment properties of the row and column specs together specify 1811e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * both aspects of alignment within the cell group. It is also possible to specify a child's 1812e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)} 1813e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * method. 1814e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * <p> 1815e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * The weight property is also included in Spec and specifies the proportion of any 1816e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * excess space that is due to the associated view. 1817e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1818e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>WRAP_CONTENT and MATCH_PARENT</h4> 1819e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1820e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Because the default values of the {@link #width} and {@link #height} 1821e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly 1822e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * declared in the layout parameters of GridLayout's children. In addition, 1823e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from 1824e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is 1825e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * instead controlled by the principle of <em>flexibility</em>, 1826e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * as discussed in {@link GridLayout}. 1827e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1828e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Summary</h4> 1829e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1830e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * You should not need to use either of the special size values: 1831e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of 1832e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * a GridLayout. 1833e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1834e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <h4>Default values</h4> 1835e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1836e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <ul> 1837e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #width} = {@link #WRAP_CONTENT}</li> 1838e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #height} = {@link #WRAP_CONTENT}</li> 1839e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #topMargin} = 0 when 1840e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 1841e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code false}; otherwise {@link #UNDEFINED}, to 1842e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * indicate that a default value should be computed on demand. </li> 1843e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #leftMargin} = 0 when 1844e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 1845e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code false}; otherwise {@link #UNDEFINED}, to 1846e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * indicate that a default value should be computed on demand. </li> 1847e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #bottomMargin} = 0 when 1848e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 1849e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code false}; otherwise {@link #UNDEFINED}, to 1850e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * indicate that a default value should be computed on demand. </li> 1851e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #rightMargin} = 0 when 1852e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 1853e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code false}; otherwise {@link #UNDEFINED}, to 1854e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * indicate that a default value should be computed on demand. </li> 1855e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li> 1856e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li> 1857e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li> 1858e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * <li>{@link #rowSpec}<code>.weight</code> = 0 </li> 1859e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li> 1860e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li> 1861e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li> 1862e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * <li>{@link #columnSpec}<code>.weight</code> = 0 </li> 1863e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * </ul> 1864e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1865e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * See {@link GridLayout} for a more complete description of the conventions 1866e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * used by GridLayout in the interpretation of the properties of this class. 1867e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1868929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:row 1869929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:rowSpan 1870929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:rowWeight 1871929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:column 1872929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:columnSpan 1873929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:columnWeight 1874929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:gravity 1875e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1876e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static class LayoutParams extends MarginLayoutParams { 1877e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1878e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Default values 1879e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1880e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int DEFAULT_WIDTH = WRAP_CONTENT; 1881e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int DEFAULT_HEIGHT = WRAP_CONTENT; 1882e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int DEFAULT_MARGIN = UNDEFINED; 1883e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int DEFAULT_ROW = UNDEFINED; 1884e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int DEFAULT_COLUMN = UNDEFINED; 1885e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final Interval DEFAULT_SPAN = new Interval(UNDEFINED, UNDEFINED + 1); 1886e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size(); 1887e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1888e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // TypedArray indices 1889e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1890e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int MARGIN = R.styleable.GridLayout_Layout_android_layout_margin; 1891e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int LEFT_MARGIN = R.styleable.GridLayout_Layout_android_layout_marginLeft; 1892e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int TOP_MARGIN = R.styleable.GridLayout_Layout_android_layout_marginTop; 1893e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int RIGHT_MARGIN = R.styleable.GridLayout_Layout_android_layout_marginRight; 1894e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int BOTTOM_MARGIN = R.styleable.GridLayout_Layout_android_layout_marginBottom; 1895e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1896e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column; 1897e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan; 1898e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight; 1899e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1900e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int ROW = R.styleable.GridLayout_Layout_layout_row; 1901e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan; 1902e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne private static final int ROW_WEIGHT = R.styleable.GridLayout_Layout_layout_rowWeight; 1903e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1904e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity; 1905e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1906e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Instance variables 1907e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1908e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 1909e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The spec that defines the vertical characteristics of the cell group 1910e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * described by these layout parameters. 1911e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * If an assignment is made to this field after a measurement or layout operation 1912e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * has already taken place, a call to 1913e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)} 1914e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * must be made to notify GridLayout of the change. GridLayout is normally able 1915e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * to detect when code fails to observe this rule, issue a warning and take steps to 1916e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * compensate for the omission. This facility is implemented on a best effort basis 1917e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * and should not be relied upon in production code - so it is best to include the above 1918e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * calls to remove the warnings as soon as it is practical. 1919e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1920e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public Spec rowSpec = Spec.UNDEFINED; 1921e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1922e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 1923e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The spec that defines the horizontal characteristics of the cell group 1924e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * described by these layout parameters. 1925e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * If an assignment is made to this field after a measurement or layout operation 1926e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * has already taken place, a call to 1927e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)} 1928e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * must be made to notify GridLayout of the change. GridLayout is normally able 1929e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * to detect when code fails to observe this rule, issue a warning and take steps to 1930e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * compensate for the omission. This facility is implemented on a best effort basis 1931e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * and should not be relied upon in production code - so it is best to include the above 1932e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * calls to remove the warnings as soon as it is practical. 1933e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1934e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public Spec columnSpec = Spec.UNDEFINED; 1935e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1936e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Constructors 1937e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1938e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private LayoutParams( 1939e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int width, int height, 1940e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int left, int top, int right, int bottom, 1941e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec rowSpec, Spec columnSpec) { 1942e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet super(width, height); 1943e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet setMargins(left, top, right, bottom); 1944e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.rowSpec = rowSpec; 1945e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.columnSpec = columnSpec; 1946e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1947e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1948e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 1949e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Constructs a new LayoutParams instance for this <code>rowSpec</code> 1950e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * and <code>columnSpec</code>. All other fields are initialized with 1951e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * default values as defined in {@link LayoutParams}. 1952e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 1953e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param rowSpec the rowSpec 1954e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param columnSpec the columnSpec 1955e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1956e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public LayoutParams(Spec rowSpec, Spec columnSpec) { 1957e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this(DEFAULT_WIDTH, DEFAULT_HEIGHT, 1958e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, 1959e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet rowSpec, columnSpec); 1960e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1961e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1962e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 1963e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}. 1964e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1965e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public LayoutParams() { 1966e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this(Spec.UNDEFINED, Spec.UNDEFINED); 1967e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1968e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1969e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Copying constructors 1970e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1971e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 1972e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@inheritDoc} 1973e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1974e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public LayoutParams(ViewGroup.LayoutParams params) { 1975e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet super(params); 1976e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1977e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1978e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 1979e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@inheritDoc} 1980e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1981e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public LayoutParams(MarginLayoutParams params) { 1982e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet super(params); 1983e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1984e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1985e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 1986e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * Copy constructor. Clones the width, height, margin values, row spec, 1987e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * and column spec of the source. 1988e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * 1989e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param source The layout params to copy from. 1990e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 1991e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne public LayoutParams(LayoutParams source) { 1992e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne super(source); 1993e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 1994e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne this.rowSpec = source.rowSpec; 1995e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne this.columnSpec = source.columnSpec; 1996e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 1997e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 1998e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // AttributeSet constructors 1999e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2000e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2001e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@inheritDoc} 2002e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2003e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Values not defined in the attribute set take the default values 2004e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * defined in {@link LayoutParams}. 2005e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2006e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public LayoutParams(Context context, AttributeSet attrs) { 2007e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet super(context, attrs); 2008e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet reInitSuper(context, attrs); 2009e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet init(context, attrs); 2010e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2011e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2012e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Implementation 2013e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2014e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Reinitialise the margins using a different default policy than MarginLayoutParams. 2015e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // Here we use the value UNDEFINED (as distinct from zero) to represent the undefined state 2016e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // so that a layout manager default can be accessed post set up. We need this as, at the 2017e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // point of installation, we do not know how many rows/cols there are and therefore 2018e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // which elements are positioned next to the container's trailing edges. We need to 2019e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // know this as margins around the container's boundary should have different 2020e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // defaults to those between peers. 2021e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2022e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // This method could be parametrized and moved into MarginLayout. 2023e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void reInitSuper(Context context, AttributeSet attrs) { 2024e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet TypedArray a = 2025e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout); 2026e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet try { 2027e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN); 2028e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2029e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.leftMargin = a.getDimensionPixelSize(LEFT_MARGIN, margin); 2030e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.topMargin = a.getDimensionPixelSize(TOP_MARGIN, margin); 2031e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.rightMargin = a.getDimensionPixelSize(RIGHT_MARGIN, margin); 2032e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.bottomMargin = a.getDimensionPixelSize(BOTTOM_MARGIN, margin); 2033e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } finally { 2034e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet a.recycle(); 2035e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2036e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2037e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2038e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private void init(Context context, AttributeSet attrs) { 2039e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout); 2040e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet try { 2041e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int gravity = a.getInt(GRAVITY, Gravity.NO_GRAVITY); 2042e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2043e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int column = a.getInt(COLUMN, DEFAULT_COLUMN); 2044e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE); 2045e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne float colWeight = a.getFloat(COLUMN_WEIGHT, Spec.DEFAULT_WEIGHT); 2046e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne this.columnSpec = spec(column, colSpan, getAlignment(gravity, true), colWeight); 2047e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2048e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int row = a.getInt(ROW, DEFAULT_ROW); 2049e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE); 2050e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne float rowWeight = a.getFloat(ROW_WEIGHT, Spec.DEFAULT_WEIGHT); 2051e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false), rowWeight); 2052e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } finally { 2053e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet a.recycle(); 2054e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2055e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2056e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2057e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2058e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}. 2059e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * See {@link Gravity}. 2060e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2061e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param gravity the new gravity value 2062e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2063929f27aab7ac7231f3734c988d5ee7201627d535Alan Viverette * @attr name android:gravity 2064e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2065e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void setGravity(int gravity) { 2066e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet rowSpec = rowSpec.copyWriteAlignment(getAlignment(gravity, false)); 2067e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet columnSpec = columnSpec.copyWriteAlignment(getAlignment(gravity, true)); 2068e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2069e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2070e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2071e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected void setBaseAttributes(TypedArray attributes, int widthAttr, int heightAttr) { 2072e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.width = attributes.getLayoutDimension(widthAttr, DEFAULT_WIDTH); 2073e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT); 2074e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2075e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2076e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final void setRowSpecSpan(Interval span) { 2077e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet rowSpec = rowSpec.copyWriteSpan(span); 2078e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2079e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2080e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final void setColumnSpecSpan(Interval span) { 2081e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet columnSpec = columnSpec.copyWriteSpan(span); 2082e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2083e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2084e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2085e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean equals(Object o) { 2086e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (this == o) return true; 2087e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (o == null || getClass() != o.getClass()) return false; 2088e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2089e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet LayoutParams that = (LayoutParams) o; 2090e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2091e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!columnSpec.equals(that.columnSpec)) return false; 2092e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!rowSpec.equals(that.rowSpec)) return false; 2093e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2094e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return true; 2095e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2096e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2097e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2098e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int hashCode() { 2099e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int result = rowSpec.hashCode(); 2100e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result = 31 * result + columnSpec.hashCode(); 2101e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 2102e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2103e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2104e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2105e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 2106e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs. 2107e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles. 2108e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2109e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final static class Arc { 2110e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public final Interval span; 2111e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public final MutableInt value; 2112e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean valid = true; 2113e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2114e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public Arc(Interval span, MutableInt value) { 2115e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.span = span; 2116e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.value = value; 2117e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2118e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2119e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2120e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public String toString() { 2121e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return span + " " + (!valid ? "+>" : "->") + " " + value; 2122e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2123e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2124e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2125e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // A mutable Integer - used to avoid heap allocation during the layout operation 2126e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2127e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final static class MutableInt { 2128e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int value; 2129e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2130e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public MutableInt() { 2131e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet reset(); 2132e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2133e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2134e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public MutableInt(int value) { 2135e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.value = value; 2136e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2137e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2138e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void reset() { 2139e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet value = Integer.MIN_VALUE; 2140e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2141e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2142e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2143e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public String toString() { 2144e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return Integer.toString(value); 2145e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2146e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2147e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2148e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final static class Assoc<K, V> extends ArrayList<Pair<K, V>> { 2149e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private final Class<K> keyType; 2150e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private final Class<V> valueType; 2151e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2152e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private Assoc(Class<K> keyType, Class<V> valueType) { 2153e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.keyType = keyType; 2154e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.valueType = valueType; 2155e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2156e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2157e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) { 2158e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return new Assoc<K, V>(keyType, valueType); 2159e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2160e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2161e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public void put(K key, V value) { 2162e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet add(Pair.create(key, value)); 2163e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2164e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2165e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @SuppressWarnings(value = "unchecked") 2166e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public PackedMap<K, V> pack() { 2167e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int N = size(); 2168e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet K[] keys = (K[]) Array.newInstance(keyType, N); 2169e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet V[] values = (V[]) Array.newInstance(valueType, N); 2170e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < N; i++) { 2171e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet keys[i] = get(i).first; 2172e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet values[i] = get(i).second; 2173e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2174e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return new PackedMap<K, V>(keys, values); 2175e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2176e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2177e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2178e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 2179e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet This data structure is used in place of a Map where we have an index that refers to the order 2180e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet in which each key/value pairs were added to the map. In this case we store keys and values 2181e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet in arrays of a length that is equal to the number of unique keys. We also maintain an 2182e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet array of indexes from insertion order to the compacted arrays of keys and values. 2183e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2184e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Note that behavior differs from that of a LinkedHashMap in that repeated entries 2185e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet *do* get added multiples times. So the length of index is equals to the number of 2186e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet items added. 2187e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2188e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet This is useful in the GridLayout class where we can rely on the order of children not 2189e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet changing during layout - to use integer-based lookup for our internal structures 2190e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet rather than using (and storing) an implementation of Map<Key, ?>. 2191e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2192e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @SuppressWarnings(value = "unchecked") 2193e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final static class PackedMap<K, V> { 2194e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public final int[] index; 2195e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public final K[] keys; 2196e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public final V[] values; 2197e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2198e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private PackedMap(K[] keys, V[] values) { 2199e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.index = createIndex(keys); 2200e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2201e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.keys = compact(keys, index); 2202e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.values = compact(values, index); 2203e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2204e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2205e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public V getValue(int i) { 2206e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return values[index[i]]; 2207e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2208e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2209e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static <K> int[] createIndex(K[] keys) { 2210e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int size = keys.length; 2211e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int[] result = new int[size]; 2212e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2213e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Map<K, Integer> keyToIndex = new HashMap<K, Integer>(); 2214e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < size; i++) { 2215e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet K key = keys[i]; 2216e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Integer index = keyToIndex.get(key); 2217e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (index == null) { 2218e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet index = keyToIndex.size(); 2219e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet keyToIndex.put(key, index); 2220e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2221e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result[i] = index; 2222e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2223e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 2224e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2225e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2226e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 2227e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Create a compact array of keys or values using the supplied index. 2228e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2229e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static <K> K[] compact(K[] a, int[] index) { 2230e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int size = a.length; 2231e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Class<?> componentType = a.getClass().getComponentType(); 2232e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1); 2233e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2234e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // this overwrite duplicates, retaining the last equivalent entry 2235e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet for (int i = 0; i < size; i++) { 2236e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result[index[i]] = a[i]; 2237e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2238e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 2239e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2240e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2241e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2242e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 2243e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet For each group (with a given alignment) we need to store the amount of space required 2244e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet before the alignment point and the amount of space required after it. One side of this 2245e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet calculation is always 0 for START and END alignments but we don't make use of this. 2246e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no 2247e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet simple optimisations are possible. 2248e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2249e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet The general algorithm therefore is to create a Map (actually a PackedMap) from 2250e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet group to Bounds and to loop through all Views in the group taking the maximum 2251e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet of the values for each View. 2252e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2253e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static class Bounds { 2254e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int before; 2255e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int after; 2256e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int flexibility; // we're flexible iff all included specs are flexible 2257e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2258e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private Bounds() { 2259e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet reset(); 2260e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2261e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2262e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected void reset() { 2263e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet before = Integer.MIN_VALUE; 2264e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet after = Integer.MIN_VALUE; 2265e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet flexibility = CAN_STRETCH; // from the above, we're flexible when empty 2266e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2267e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2268e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected void include(int before, int after) { 2269e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.before = max(this.before, before); 2270e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.after = max(this.after, after); 2271e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2272e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2273e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected int size(boolean min) { 2274e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!min) { 2275e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (canStretch(flexibility)) { 2276e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return MAX_SIZE; 2277e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2278e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2279e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return before + after; 2280e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2281e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 22822c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) { 2283b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return before - a.getAlignmentValue(c, size, ViewGroupCompat.getLayoutMode(gl)); 2284e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2285e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2286e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) { 2287e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.flexibility &= spec.getFlexibility(); 22882c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio boolean horizontal = axis.horizontal; 2289aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar Alignment alignment = spec.getAbsoluteAlignment(horizontal); 2290e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet // todo test this works correctly when the returned value is UNDEFINED 2291b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell int before = alignment.getAlignmentValue(c, size, ViewGroupCompat.getLayoutMode(gl)); 2292e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet include(before, size - before); 2293e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2294e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2295e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2296e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public String toString() { 2297e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return "Bounds{" + 2298e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet "before=" + before + 2299e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet ", after=" + after + 2300e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet '}'; 2301e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2302e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2303e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2304e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2305e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * An Interval represents a contiguous range of values that lie between 2306e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * the interval's {@link #min} and {@link #max} values. 2307e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 2308e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Intervals are immutable so may be passed as values and used as keys in hash tables. 2309e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * It is not necessary to have multiple instances of Intervals which have the same 2310e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link #min} and {@link #max} values. 2311e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 2312e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Intervals are often written as {@code [min, max]} and represent the set of values 2313e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code x} such that {@code min <= x < max}. 2314e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2315e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final static class Interval { 2316e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2317e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The minimum value. 2318e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2319e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public final int min; 2320e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2321e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2322e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The maximum value. 2323e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2324e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public final int max; 2325e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2326e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2327e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Construct a new Interval, {@code interval}, where: 2328e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <ul> 2329e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li> {@code interval.min = min} </li> 2330e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li> {@code interval.max = max} </li> 2331e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * </ul> 2332e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2333e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param min the minimum value. 2334e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param max the maximum value. 2335e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2336e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public Interval(int min, int max) { 2337e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.min = min; 2338e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.max = max; 2339e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2340e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2341e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int size() { 2342e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return max - min; 2343e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2344e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2345e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval inverse() { 2346e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return new Interval(max, min); 2347e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2348e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2349e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2350e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns {@code true} if the {@link #getClass class}, 2351e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link #min} and {@link #max} properties of this Interval and the 2352e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * supplied parameter are pairwise equal; {@code false} otherwise. 2353e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2354e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param that the object to compare this interval with 2355e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2356e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return {@code true} if the specified object is equal to this 2357e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code Interval}, {@code false} otherwise. 2358e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2359e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2360e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean equals(Object that) { 2361e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (this == that) { 2362e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return true; 2363e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2364e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (that == null || getClass() != that.getClass()) { 2365e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 2366e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2367e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2368e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Interval interval = (Interval) that; 2369e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2370e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (max != interval.max) { 2371e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 2372e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2373e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet //noinspection RedundantIfStatement 2374e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (min != interval.min) { 2375e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 2376e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2377e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2378e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return true; 2379e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2380e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2381e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2382e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int hashCode() { 2383e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int result = min; 2384e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result = 31 * result + max; 2385e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 2386e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2387e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2388e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2389e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public String toString() { 2390e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return "[" + min + ", " + max + "]"; 2391e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2392e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2393e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2394e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2395e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * A Spec defines the horizontal or vertical characteristics of a group of 2396e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * cells. Each spec. defines the <em>grid indices</em> and <em>alignment</em> 2397e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * along the appropriate axis. 2398e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 2399e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The <em>grid indices</em> are the leading and trailing edges of this cell group. 2400e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * See {@link GridLayout} for a description of the conventions used by GridLayout 2401e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * for grid indices. 2402e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 2403e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The <em>alignment</em> property specifies how cells should be aligned in this group. 2404e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * For row groups, this specifies the vertical alignment. 2405e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * For column groups, this specifies the horizontal alignment. 2406e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 2407e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Use the following static methods to create specs: 2408e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <ul> 2409e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #spec(int)}</li> 2410e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #spec(int, int)}</li> 2411e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #spec(int, Alignment)}</li> 2412e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li>{@link #spec(int, int, Alignment)}</li> 2413e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * <li>{@link #spec(int, float)}</li> 2414e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * <li>{@link #spec(int, int, float)}</li> 2415e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * <li>{@link #spec(int, Alignment, float)}</li> 2416e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * <li>{@link #spec(int, int, Alignment, float)}</li> 2417e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * </ul> 2418e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2419e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2420e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static class Spec { 2421e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static final Spec UNDEFINED = spec(GridLayout.UNDEFINED); 2422e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne static final float DEFAULT_WEIGHT = 0; 2423e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2424e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final boolean startDefined; 2425e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final Interval span; 2426e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final Alignment alignment; 2427e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne final float weight; 2428e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2429e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne private Spec(boolean startDefined, Interval span, Alignment alignment, float weight) { 2430e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.startDefined = startDefined; 2431e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.span = span; 2432e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet this.alignment = alignment; 2433e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne this.weight = weight; 2434e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2435e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2436e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne private Spec(boolean startDefined, int start, int size, Alignment alignment, float weight) { 2437e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne this(startDefined, new Interval(start, start + size), alignment, weight); 2438e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2439e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2440aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar public Alignment getAbsoluteAlignment(boolean horizontal) { 2441aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar if (alignment != UNDEFINED_ALIGNMENT) { 2442aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return alignment; 2443aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2444aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar if (weight == 0f) { 2445aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return horizontal ? START : BASELINE; 2446aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2447aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return FILL; 2448aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2449aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2450e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final Spec copyWriteSpan(Interval span) { 2451e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return new Spec(startDefined, span, alignment, weight); 2452e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2453e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2454e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final Spec copyWriteAlignment(Alignment alignment) { 2455e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return new Spec(startDefined, span, alignment, weight); 2456e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2457e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2458e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet final int getFlexibility() { 2459e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return (alignment == UNDEFINED_ALIGNMENT && weight == 0) ? INFLEXIBLE : CAN_STRETCH; 2460e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2461e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2462e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2463e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns {@code true} if the {@code class}, {@code alignment} and {@code span} 2464e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * properties of this Spec and the supplied parameter are pairwise equal, 2465e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code false} otherwise. 2466e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2467e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param that the object to compare this spec with 2468e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2469e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return {@code true} if the specified object is equal to this 2470e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code Spec}; {@code false} otherwise 2471e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2472e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2473e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public boolean equals(Object that) { 2474e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (this == that) { 2475e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return true; 2476e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2477e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (that == null || getClass() != that.getClass()) { 2478e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 2479e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2480e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2481e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Spec spec = (Spec) that; 2482e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2483e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!alignment.equals(spec.alignment)) { 2484e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 2485e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2486e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet //noinspection RedundantIfStatement 2487e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet if (!span.equals(spec.span)) { 2488e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return false; 2489e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2490e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2491e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return true; 2492e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2493e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2494e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2495e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int hashCode() { 2496e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int result = span.hashCode(); 2497e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet result = 31 * result + alignment.hashCode(); 2498e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return result; 2499e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2500e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2501e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2502e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2503e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Return a Spec, {@code spec}, where: 2504e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <ul> 2505e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li> {@code spec.span = [start, start + size]} </li> 2506e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li> {@code spec.alignment = alignment} </li> 2507e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * <li> {@code spec.weight = weight} </li> 2508e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * </ul> 25092c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <p> 25102c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * To leave the start index undefined, use the value {@link #UNDEFINED}. 2511e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2512e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param start the start 2513e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param size the size 2514e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param alignment the alignment 2515e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param weight the weight 2516e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne */ 2517e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne public static Spec spec(int start, int size, Alignment alignment, float weight) { 2518e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return new Spec(start != UNDEFINED, start, size, alignment, weight); 2519e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 2520e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 2521e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne /** 2522e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * Equivalent to: {@code spec(start, 1, alignment, weight)}. 2523e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * 2524e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param start the start 2525e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param alignment the alignment 2526e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param weight the weight 2527e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne */ 2528e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne public static Spec spec(int start, Alignment alignment, float weight) { 2529e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return spec(start, 1, alignment, weight); 2530e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 2531e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 2532e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne /** 2533e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * Equivalent to: {@code spec(start, 1, default_alignment, weight)} - 2534e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * where {@code default_alignment} is specified in 2535e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * {@link android.widget.GridLayout.LayoutParams}. 2536e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * 2537e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param start the start 2538e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param size the size 2539e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param weight the weight 2540e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne */ 2541e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne public static Spec spec(int start, int size, float weight) { 2542e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return spec(start, size, UNDEFINED_ALIGNMENT, weight); 2543e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 2544e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 2545e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne /** 2546e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * Equivalent to: {@code spec(start, 1, weight)}. 2547e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * 2548e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param start the start 2549e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param weight the weight 2550e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne */ 2551e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne public static Spec spec(int start, float weight) { 2552e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return spec(start, 1, weight); 2553e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne } 2554e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne 2555e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne /** 2556e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * Equivalent to: {@code spec(start, size, alignment, 0f)}. 2557e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * 2558e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param start the start 2559e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param size the size 2560e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne * @param alignment the alignment 2561e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2562e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static Spec spec(int start, int size, Alignment alignment) { 2563e0e021449dbe556c4b775a8dcaf486e1d3f361e7Philip Milne return spec(start, size, alignment, Spec.DEFAULT_WEIGHT); 2564e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2565e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2566e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2567e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Return a Spec, {@code spec}, where: 2568e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <ul> 2569e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li> {@code spec.span = [start, start + 1]} </li> 2570e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li> {@code spec.alignment = alignment} </li> 2571e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * </ul> 25722c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <p> 25732c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * To leave the start index undefined, use the value {@link #UNDEFINED}. 2574e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2575e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param start the start index 2576e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param alignment the alignment 25772c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 25782c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * @see #spec(int, int, Alignment) 2579e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2580e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static Spec spec(int start, Alignment alignment) { 2581e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return spec(start, 1, alignment); 2582e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2583e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2584e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2585e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Return a Spec, {@code spec}, where: 2586e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <ul> 2587e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li> {@code spec.span = [start, start + size]} </li> 2588e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * </ul> 25892c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <p> 25902c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * To leave the start index undefined, use the value {@link #UNDEFINED}. 2591e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2592e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param start the start 2593e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param size the size 25942c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 25952c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * @see #spec(int, Alignment) 2596e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2597e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static Spec spec(int start, int size) { 2598e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return spec(start, size, UNDEFINED_ALIGNMENT); 2599e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2600e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2601e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2602e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Return a Spec, {@code spec}, where: 2603e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <ul> 2604e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <li> {@code spec.span = [start, start + 1]} </li> 2605e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * </ul> 26062c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * <p> 26072c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * To leave the start index undefined, use the value {@link #UNDEFINED}. 2608e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2609e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param start the start index 26102c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * 26112c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * @see #spec(int, int) 2612e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2613e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static Spec spec(int start) { 2614e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return spec(start, 1); 2615e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2616e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2617e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2618e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Alignments specify where a view should be placed within a cell group and 2619e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * what size it should be. 2620e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 2621e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec} 2622e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an 2623e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@code alignment}. Overall placement of the view in the cell 2624e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * group is specified by the two alignments which act along each axis independently. 2625e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 2626e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The GridLayout class defines the most common alignments used in general layout: 2627e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #START}, 2628e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link #END}, {@link #CENTER}, {@link #BASELINE} and {@link #FILL}. 2629e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2630e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 2631e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)}, 2632e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * to return the appropriate value for the type of alignment being defined. 2633e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The enclosing algorithms position the children 2634e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * so that the locations defined by the alignment values 2635e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * are the same for all of the views in a group. 2636e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 2637e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2638e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static abstract class Alignment { 2639e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Alignment() { 2640e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2641e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2642e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet abstract int getGravityOffset(View view, int cellDelta); 2643e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2644e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2645e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns an alignment value. In the case of vertical alignments the value 2646e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * returned should indicate the distance from the top of the view to the 2647e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * alignment location. 2648e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * For horizontal alignments measurement is made from the left edge of the component. 2649e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2650e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param view the view to which this alignment should be applied 2651e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param viewSize the measured size of the view 26522c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio * @param mode the basis of alignment: CLIP or OPTICAL 2653e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return the alignment value 2654e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 26552c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio abstract int getAlignmentValue(View view, int viewSize, int mode); 2656e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2657e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2658e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Returns the size of the view specified by this alignment. 2659e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * In the case of vertical alignments this method should return a height; for 2660e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * horizontal alignments this method should return the width. 2661e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * <p> 2662e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * The default implementation returns {@code viewSize}. 2663e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2664e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param view the view to which this alignment should be applied 2665e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param viewSize the measured size of the view 2666e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @param cellSize the size of the cell into which this view will be placed 2667e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @return the aligned size 2668e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2669e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int getSizeInCell(View view, int viewSize, int cellSize) { 2670e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return viewSize; 2671e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2672e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2673e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet Bounds getBounds() { 2674e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return new Bounds(); 2675e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2676aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2677aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar abstract String getDebugString(); 2678aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2679aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar @Override 2680aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar public String toString() { 2681aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return "Alignment:" + getDebugString(); 2682aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2683e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2684e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2685e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static final Alignment UNDEFINED_ALIGNMENT = new Alignment() { 2686e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2687e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int getGravityOffset(View view, int cellDelta) { 2688e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return UNDEFINED; 2689e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2690e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2691e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 26922c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public int getAlignmentValue(View view, int viewSize, int mode) { 2693e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return UNDEFINED; 2694e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2695aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2696aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar @Override 2697aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar String getDebugString() { 2698aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return "UNDEFINED"; 2699aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2700e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet }; 2701e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2702e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2703e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be aligned with the <em>start</em> 2704e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * edges of the other views in its cell group. 2705e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2706e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final Alignment LEADING = new Alignment() { 2707e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2708e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int getGravityOffset(View view, int cellDelta) { 2709e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return 0; 2710e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2711e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2712e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 27132c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public int getAlignmentValue(View view, int viewSize, int mode) { 2714e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return 0; 2715e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2716aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2717aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar @Override 2718aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar String getDebugString() { 2719aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return "LEADING"; 2720aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2721e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet }; 2722e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2723e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2724e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be aligned with the <em>end</em> 2725e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * edges of the other views in its cell group. 2726e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2727e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final Alignment TRAILING = new Alignment() { 2728e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2729e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int getGravityOffset(View view, int cellDelta) { 2730e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return cellDelta; 2731e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2732e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2733e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 27342c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public int getAlignmentValue(View view, int viewSize, int mode) { 2735e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return viewSize; 2736e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2737aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2738aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar @Override 2739aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar String getDebugString() { 2740aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return "TRAILING"; 2741aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2742e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet }; 2743e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2744e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2745e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be aligned with the <em>top</em> 2746e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * edges of the other views in its cell group. 2747e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2748e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final Alignment TOP = LEADING; 2749e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2750e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2751e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be aligned with the <em>bottom</em> 2752e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * edges of the other views in its cell group. 2753e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2754e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final Alignment BOTTOM = TRAILING; 2755e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2756e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2757e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be aligned with the <em>start</em> 2758e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * edges of the other views in its cell group. 2759e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2760e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final Alignment START = LEADING; 2761e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2762e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2763e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be aligned with the <em>end</em> 2764e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * edges of the other views in its cell group. 2765e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2766e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final Alignment END = TRAILING; 2767e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2768e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static Alignment createSwitchingAlignment(final Alignment ltr, final Alignment rtl) { 2769e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return new Alignment() { 2770e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2771e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int getGravityOffset(View view, int cellDelta) { 2772b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell boolean isLayoutRtl = ViewCompat.getLayoutDirection(view) == 2773b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell ViewCompat.LAYOUT_DIRECTION_RTL; 2774b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return (!isLayoutRtl ? ltr : rtl).getGravityOffset(view, cellDelta); 2775e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2776e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2777e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 27782c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public int getAlignmentValue(View view, int viewSize, int mode) { 2779b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell boolean isLayoutRtl = ViewCompat.getLayoutDirection(view) == 2780b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell ViewCompat.LAYOUT_DIRECTION_RTL; 2781b12ba0547b2fad1c4dfc12dec36c5e7893974e67Adam Powell return (!isLayoutRtl ? ltr : rtl).getAlignmentValue(view, viewSize, mode); 2782e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2783aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2784aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar @Override 2785aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar String getDebugString() { 2786aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return "SWITCHING[L:" + ltr.getDebugString() + ", R:" + rtl.getDebugString() + "]"; 2787aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2788e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet }; 2789e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2790e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2791e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2792e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be aligned with the <em>left</em> 2793e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * edges of the other views in its cell group. 2794e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2795e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final Alignment LEFT = createSwitchingAlignment(START, END); 2796e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2797e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2798e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be aligned with the <em>right</em> 2799e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * edges of the other views in its cell group. 2800e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2801e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final Alignment RIGHT = createSwitchingAlignment(END, START); 2802e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2803e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2804e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be <em>centered</em> with the other views in its cell group. 2805e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link 2806e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * LayoutParams#columnSpec columnSpecs}. 2807e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2808e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final Alignment CENTER = new Alignment() { 2809e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2810e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int getGravityOffset(View view, int cellDelta) { 2811e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return cellDelta >> 1; 2812e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2813e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2814e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 28152c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public int getAlignmentValue(View view, int viewSize, int mode) { 2816e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return viewSize >> 1; 2817e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2818aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2819aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar @Override 2820aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar String getDebugString() { 2821aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return "CENTER"; 2822aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2823e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet }; 2824e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2825e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2826e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should be aligned with the <em>baselines</em> 2827e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * of the other views in its cell group. 2828e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}. 2829e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * 2830e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * @see View#getBaseline() 2831e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2832e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final Alignment BASELINE = new Alignment() { 2833e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2834e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int getGravityOffset(View view, int cellDelta) { 2835e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return 0; // baseline gravity is top 2836e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2837e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2838e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 28392c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public int getAlignmentValue(View view, int viewSize, int mode) { 28402c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio if (view.getVisibility() == GONE) { 28412c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return 0; 28422c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio } 2843e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int baseline = view.getBaseline(); 28442c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return baseline == -1 ? UNDEFINED : baseline; 2845e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2846e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2847e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2848e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public Bounds getBounds() { 2849e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return new Bounds() { 2850e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /* 2851e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet In a baseline aligned row in which some components define a baseline 2852e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet and some don't, we need a third variable to properly account for all 2853e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet the sizes. This tracks the maximum size of all the components - 2854e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet including those that don't define a baseline. 2855e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2856e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private int size; 2857e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2858e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2859e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected void reset() { 2860e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet super.reset(); 2861e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet size = Integer.MIN_VALUE; 2862e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2863e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2864e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2865e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected void include(int before, int after) { 2866e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet super.include(before, after); 2867e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet size = max(size, before + after); 2868e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2869e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2870e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2871e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet protected int size(boolean min) { 2872e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return max(super.size(min), size); 2873e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2874e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2875e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 28762c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) { 28772c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio return max(0, super.getOffset(gl, c, a, size, hrz)); 2878e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2879e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet }; 2880e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2881aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2882aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar @Override 2883aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar String getDebugString() { 2884aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return "BASELINE"; 2885aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2886e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet }; 2887e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2888e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet /** 2889e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * Indicates that a view should expanded to fit the boundaries of its cell group. 2890e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and 2891e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet * {@link LayoutParams#columnSpec columnSpecs}. 2892e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet */ 2893e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public static final Alignment FILL = new Alignment() { 2894e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2895e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet int getGravityOffset(View view, int cellDelta) { 2896e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return 0; 2897e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2898e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2899e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 29002c78c295c13866c37e778375d1b37d6ff6016190Fabrice Di Meglio public int getAlignmentValue(View view, int viewSize, int mode) { 2901e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return UNDEFINED; 2902e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2903e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2904e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet @Override 2905e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet public int getSizeInCell(View view, int viewSize, int cellSize) { 2906e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return cellSize; 2907e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2908aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar 2909aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar @Override 2910aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar String getDebugString() { 2911aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar return "FILL"; 2912aba8d47bf2f26c657a83ab3fbd24f531df5b0510Yigit Boyar } 2913e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet }; 2914e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2915e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet static boolean canStretch(int flexibility) { 2916e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet return (flexibility & CAN_STRETCH) != 0; 2917e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet } 2918e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet 2919e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int INFLEXIBLE = 0; 2920e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet private static final int CAN_STRETCH = 2; 2921e1feb53bd8abfa46613fdd0abcf7a015c7e706c1Xavier Ducrohet} 2922