GridLayout.java revision 0d29936ec3b5545a415e8d032150ea987aab36e3
13f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/* 23f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Copyright (C) 2011 The Android Open Source Project 33f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 43f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Licensed under the Apache License, Version 2.0 (the "License"); 53f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * you may not use this file except in compliance with the License. 63f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * You may obtain a copy of the License at 73f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 83f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * http://www.apache.org/licenses/LICENSE-2.0 93f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Unless required by applicable law or agreed to in writing, software 113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * distributed under the License is distributed on an "AS IS" BASIS, 123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See the License for the specific language governing permissions and 143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * limitations under the License. 153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepackage android.widget; 183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.Context; 203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.content.res.TypedArray; 213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Canvas; 223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Color; 233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Paint; 243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.AttributeSet; 253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.Log; 2648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milneimport android.util.Pair; 273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.Gravity; 283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.View; 293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.ViewGroup; 308a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 318a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 328a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 33b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milneimport com.android.internal.R; 343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.lang.reflect.Array; 363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.ArrayList; 373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Arrays; 383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.HashMap; 393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.List; 403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Map; 413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 425125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milneimport static android.view.Gravity.*; 43899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.EXACTLY; 44899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.makeMeasureSpec; 453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.max; 463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.min; 473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/** 493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * A layout that places its children in a rectangular <em>grid</em>. 503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The grid is composed of a set of infinitely thin lines that separate the 523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced 537fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * by grid <em>indices</em>. A grid with {@code N} columns 547fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * has {@code N + 1} grid indices that run from {@code 0} 557fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * through {@code N} inclusive. Regardless of how GridLayout is 567fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * configured, grid index {@code 0} is fixed to the leading edge of the 577fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * container and grid index {@code N} is fixed to its trailing edge 583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * (after padding is taken into account). 593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 6093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <h4>Row and Column Specs</h4> 613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Children occupy one or more contiguous cells, as defined 6393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and 6493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters. 6593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Each spec defines the set of rows or columns that are to be 663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * occupied; and how children should be aligned within the resulting group of cells. 673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Although cells do not normally overlap in a GridLayout, GridLayout does 683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * not prevent children being defined to occupy the same cell or group of cells. 693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * In this case however, there is no guarantee that children will not themselves 703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * overlap after the layout operation completes. 713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Default Cell Assignment</h4> 733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 7448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne * If a child does not specify the row and column indices of the cell it 753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * wishes to occupy, GridLayout assigns cell locations automatically using its: 763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setOrientation(int) orientation}, 773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setRowCount(int) rowCount} and 783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setColumnCount(int) columnCount} properties. 793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Space</h4> 813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Space between children may be specified either by using instances of the 833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * dedicated {@link Space} view or by setting the 843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#leftMargin leftMargin}, 863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#topMargin topMargin}, 873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#rightMargin rightMargin} and 883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#bottomMargin bottomMargin} 893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters. When the 913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} 923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * property is set, default margins around children are automatically 93f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * allocated based on the prevailing UI style guide for the platform. 94f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Each of the margins so defined may be independently overridden by an assignment 953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to the appropriate layout parameter. 96f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Default values will generally produce a reasonable spacing between components 97f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * but values may change between different releases of the platform. 983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Excess Space Distribution</h4> 1003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 101f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's distribution of excess space is based on <em>priority</em> 102f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * rather than <em>weight</em>. 103f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p> 104899d5922870c78e0e663bc5661849eb468afc984Philip Milne * A child's ability to stretch is inferred from the alignment properties of 105899d5922870c78e0e663bc5661849eb468afc984Philip Milne * its row and column groups (which are typically set by setting the 106899d5922870c78e0e663bc5661849eb468afc984Philip Milne * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters). 107899d5922870c78e0e663bc5661849eb468afc984Philip Milne * If alignment was defined along a given axis then the component 108f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * is taken as <em>flexible</em> in that direction. If no alignment was set, 109f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * the component is instead assumed to be <em>inflexible</em>. 110f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p> 111f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Multiple components in the same row or column group are 112f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * considered to act in <em>parallel</em>. Such a 113899d5922870c78e0e663bc5661849eb468afc984Philip Milne * group is flexible only if <em>all</em> of the components 114899d5922870c78e0e663bc5661849eb468afc984Philip Milne * within it are flexible. Row and column groups that sit either side of a common boundary 115899d5922870c78e0e663bc5661849eb468afc984Philip Milne * are instead considered to act in <em>series</em>. The composite group made of these two 116899d5922870c78e0e663bc5661849eb468afc984Philip Milne * elements is flexible if <em>one</em> of its elements is flexible. 117899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p> 118899d5922870c78e0e663bc5661849eb468afc984Philip Milne * To make a column stretch, make sure all of the components inside it define a 119899d5922870c78e0e663bc5661849eb468afc984Philip Milne * gravity. To prevent a column from stretching, ensure that one of the components 120899d5922870c78e0e663bc5661849eb468afc984Philip Milne * in the column does not define a gravity. 1213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 122f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When the principle of flexibility does not provide complete disambiguation, 123f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em> 124f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * and <em>bottom</em> edges. 125f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 126f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h5>Limitations</h5> 127f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 128f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout does not provide support for the principle of <em>weight</em>, as defined in 129f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible 130f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * to configure a GridLayout to distribute excess space in non-trivial proportions between 131f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * multiple rows or columns. 132f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p> 133f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Some common use-cases may nevertheless be accommodated as follows. 134f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * To place equal amounts of space around a component in a cell group; 135f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * use {@link #CENTER} alignment (or {@link LayoutParams#setGravity(int) gravity}). 136f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * For complete control over excess space distribution in a row or column; 137f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * use a {@link LinearLayout} subview to hold the components in the associated cell group. 138f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When using either of these techniques, bear in mind that cell groups may be defined to overlap. 1393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 1403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See {@link GridLayout.LayoutParams} for a full description of the 1413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters used by GridLayout. 1423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 1433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation 1443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount 1453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount 1463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins 1473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved 1483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved 1493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepublic class GridLayout extends ViewGroup { 1513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Public constants 1533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The horizontal orientation. 1563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final int HORIZONTAL = LinearLayout.HORIZONTAL; 158aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The vertical orientation. 1613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final int VERTICAL = LinearLayout.VERTICAL; 1633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 164aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 165aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * The constant used to indicate that a value is undefined. 166aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * Fields can use this value to indicate that their values 167aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * have not yet been set. Similarly, methods can return this value 168aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * to indicate that there is no suitable value that the implementation 169aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * can return. 170aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * The value used for the constant (currently {@link Integer#MIN_VALUE}) is 171aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * intended to avoid confusion between valid values whose sign may not be known. 172aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 173aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public static final int UNDEFINED = Integer.MIN_VALUE; 174aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1751e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne /** 1761e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * This constant is an {@link #setAlignmentMode(int) alignmentMode}. 1771e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * When the {@code alignmentMode} is set to {@link #ALIGN_BOUNDS}, alignment 1781e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * is made between the edges of each component's raw 1791e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * view boundary: i.e. the area delimited by the component's: 1801e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getTop() top}, 1811e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getLeft() left}, 1821e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getBottom() bottom} and 1831e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getRight() right} properties. 1841e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * <p> 1851e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * For example, when {@code GridLayout} is in {@link #ALIGN_BOUNDS} mode, 1861e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * children that belong to a row group that uses {@link #TOP} alignment will 1871e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * all return the same value when their {@link android.view.View#getTop()} 1881e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * method is called. 1891e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 1901e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 1911e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne */ 1921e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public static final int ALIGN_BOUNDS = 0; 1931e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne 1941e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne /** 1951e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * This constant is an {@link #setAlignmentMode(int) alignmentMode}. 1961e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * When the {@code alignmentMode} is set to {@link #ALIGN_MARGINS}, 1971e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * the bounds of each view are extended outwards, according 1981e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * to their margins, before the edges of the resulting rectangle are aligned. 1991e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * <p> 2001e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * For example, when {@code GridLayout} is in {@link #ALIGN_MARGINS} mode, 2011e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * the quantity {@code top - layoutParams.topMargin} is the same for all children that 2021e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * belong to a row group that uses {@link #TOP} alignment. 2031e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 2041e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 2051e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne */ 2061e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public static final int ALIGN_MARGINS = 1; 2071e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne 2083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Misc constants 2093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 210f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final String TAG = GridLayout.class.getName(); 211f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final boolean DEBUG = false; 212f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final int PRF = 1; 213f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final int MAX_SIZE = 100000; 214f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final int DEFAULT_CONTAINER_MARGIN = 0; 2153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Defaults 2173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_ORIENTATION = HORIZONTAL; 2193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_COUNT = UNDEFINED; 2203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false; 221899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static final boolean DEFAULT_ORDER_PRESERVED = true; 2221e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS; 2233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // TypedArray indices 2253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 226b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ORIENTATION = R.styleable.GridLayout_orientation; 227b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW_COUNT = R.styleable.GridLayout_rowCount; 228b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount; 229b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins; 230b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode; 231b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved; 232b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved; 2333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Instance variables 2353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 236f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Axis horizontalAxis = new Axis(true); 237f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Axis verticalAxis = new Axis(false); 238f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean layoutParamsValid = false; 239f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int orientation = DEFAULT_ORIENTATION; 240f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS; 241f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int alignmentMode = DEFAULT_ALIGNMENT_MODE; 242f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int defaultGap; 243aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Constructors 2453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 2473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 2483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public GridLayout(Context context, AttributeSet attrs, int defStyle) { 2503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(context, attrs, defStyle); 251c655ba5e467090eb4f839f148ac31b50c389ffb2Jim Miller if (DEBUG) { 252c655ba5e467090eb4f839f148ac31b50c389ffb2Jim Miller setWillNotDraw(false); 253c655ba5e467090eb4f839f148ac31b50c389ffb2Jim Miller } 254f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne defaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap); 255b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout); 2563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne try { 2571e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT)); 2581e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT)); 2595125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne setOrientation(a.getInt(ORIENTATION, DEFAULT_ORIENTATION)); 2605125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne setUseDefaultMargins(a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS)); 2615125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne setAlignmentMode(a.getInt(ALIGNMENT_MODE, DEFAULT_ALIGNMENT_MODE)); 2623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); 2633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); 2643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } finally { 2653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne a.recycle(); 2663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 26948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne /** 27048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne * {@inheritDoc} 27148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne */ 27248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public GridLayout(Context context, AttributeSet attrs) { 27348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne this(context, attrs, 0); 27448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 27548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 27648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne /** 27748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne * {@inheritDoc} 27848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne */ 27948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public GridLayout(Context context) { 2804c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne //noinspection NullableProblems 28148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne this(context, null); 28248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 28348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 2843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Implementation 2853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 2873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the current orientation. 2883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 2897fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return either {@link #HORIZONTAL} or {@link #VERTICAL} 2903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 2913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setOrientation(int) 2923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 2933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation 2943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int getOrientation() { 296f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return orientation; 2973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 300f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Orientation is used only to generate default row/column indices when 301f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * they are not specified by a component's layout parameters. 3027fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 3037fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * The default value of this property is {@link #HORIZONTAL}. 3043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3057fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param orientation either {@link #HORIZONTAL} or {@link #VERTICAL} 3063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getOrientation() 3083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation 3103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setOrientation(int orientation) { 312f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (this.orientation != orientation) { 313f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.orientation = orientation; 314f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne invalidateStructure(); 3153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne requestLayout(); 3163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 3203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the current number of rows. This is either the last value that was set 3213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * with {@link #setRowCount(int)} or, if no such value was set, the maximum 32293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * value of each the upper bounds defined in {@link LayoutParams#rowSpec}. 3233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return the current number of rows 3253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setRowCount(int) 32793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#rowSpec 3283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount 3303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int getRowCount() { 332f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return verticalAxis.getCount(); 3333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 336f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * RowCount is used only to generate default row/column indices when 337f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * they are not specified by a component's layout parameters. 3383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3397fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param rowCount the number of rows 3403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getRowCount() 34293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#rowSpec 3433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount 3453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setRowCount(int rowCount) { 347f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne verticalAxis.setCount(rowCount); 348f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne invalidateStructure(); 349f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne requestLayout(); 3503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 3533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the current number of columns. This is either the last value that was set 3543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * with {@link #setColumnCount(int)} or, if no such value was set, the maximum 35593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * value of each the upper bounds defined in {@link LayoutParams#columnSpec}. 3563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return the current number of columns 3583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setColumnCount(int) 36093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#columnSpec 3613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount 3633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int getColumnCount() { 365f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return horizontalAxis.getCount(); 3663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 369f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * ColumnCount is used only to generate default column/column indices when 370f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * they are not specified by a component's layout parameters. 3713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @param columnCount the number of columns. 3733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getColumnCount() 37593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#columnSpec 3763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount 3783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setColumnCount(int columnCount) { 380f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne horizontalAxis.setCount(columnCount); 381f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne invalidateStructure(); 382f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne requestLayout(); 3833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 3863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns whether or not this GridLayout will allocate default margins when no 3873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * corresponding layout parameters are defined. 3883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3897fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return {@code true} if default margins should be allocated 3903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setUseDefaultMargins(boolean) 3923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins 3943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean getUseDefaultMargins() { 396f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return useDefaultMargins; 3973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 4007fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When {@code true}, GridLayout allocates default margins around children 4013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * based on the child's visual characteristics. Each of the 4023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * margins so defined may be independently overridden by an assignment 4033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to the appropriate layout parameter. 4043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 4057fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When {@code false}, the default value of all margins is zero. 406aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * <p> 4077fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When setting to {@code true}, consider setting the value of the 4081e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link #setAlignmentMode(int) alignmentMode} 4091e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * property to {@link #ALIGN_BOUNDS}. 4107fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 4117fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * The default value of this property is {@code false}. 4123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4137fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins 4143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getUseDefaultMargins() 4161e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 4173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#leftMargin 4193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#topMargin 4203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#rightMargin 4213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#bottomMargin 4223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins 4243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setUseDefaultMargins(boolean useDefaultMargins) { 426f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.useDefaultMargins = useDefaultMargins; 427aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 428aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 429aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 430aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 4311e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * Returns the alignment mode. 4321e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 4331e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @return the alignment mode; either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS} 434aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4351e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_BOUNDS 4361e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_MARGINS 437aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4381e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 439aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4401e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @attr ref android.R.styleable#GridLayout_alignmentMode 441aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 4421e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public int getAlignmentMode() { 443f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return alignmentMode; 444aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 445aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 446aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 4471e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * Sets the alignment mode to be used for all of the alignments between the 4481e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * children of this container. 4497fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 4501e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * The default value of this property is {@link #ALIGN_MARGINS}. 4511e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 4521e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @param alignmentMode either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS} 453aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4541e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_BOUNDS 4551e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_MARGINS 456aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4571e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #getAlignmentMode() 458aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4591e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @attr ref android.R.styleable#GridLayout_alignmentMode 460aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 4611e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public void setAlignmentMode(int alignmentMode) { 462f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.alignmentMode = alignmentMode; 463aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 4643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 4653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 4663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 4673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns whether or not row boundaries are ordered by their grid indices. 4683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4697fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return {@code true} if row boundaries must appear in the order of their indices, 4707fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false} otherwise 4713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setRowOrderPreserved(boolean) 4733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved 4753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean isRowOrderPreserved() { 477f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return verticalAxis.isOrderPreserved(); 4783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 4793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 4803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 4817fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When this property is {@code true}, GridLayout is forced to place the row boundaries 482aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * so that their associated grid indices are in ascending order in the view. 4833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 484899d5922870c78e0e663bc5661849eb468afc984Philip Milne * When this property is {@code false} GridLayout is at liberty to place the vertical row 485899d5922870c78e0e663bc5661849eb468afc984Philip Milne * boundaries in whatever order best fits the given constraints. 4867fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 487899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The default value of this property is {@code true}. 4887fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 4897fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param rowOrderPreserved {@code true} to force GridLayout to respect the order 4907fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * of row boundaries 4913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #isRowOrderPreserved() 4933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved 4953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setRowOrderPreserved(boolean rowOrderPreserved) { 497f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne verticalAxis.setOrderPreserved(rowOrderPreserved); 498aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne invalidateStructure(); 499aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 5003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns whether or not column boundaries are ordered by their grid indices. 5043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5057fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return {@code true} if column boundaries must appear in the order of their indices, 5067fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false} otherwise 5073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setColumnOrderPreserved(boolean) 5093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved 5113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean isColumnOrderPreserved() { 513f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return horizontalAxis.isOrderPreserved(); 5143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5177fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When this property is {@code true}, GridLayout is forced to place the column boundaries 518aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * so that their associated grid indices are in ascending order in the view. 5193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 520899d5922870c78e0e663bc5661849eb468afc984Philip Milne * When this property is {@code false} GridLayout is at liberty to place the horizontal column 521899d5922870c78e0e663bc5661849eb468afc984Philip Milne * boundaries in whatever order best fits the given constraints. 5227fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 523899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The default value of this property is {@code true}. 5243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5257fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param columnOrderPreserved use {@code true} to force GridLayout to respect the order 5263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * of column boundaries. 5273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #isColumnOrderPreserved() 5293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved 5313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setColumnOrderPreserved(boolean columnOrderPreserved) { 533f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne horizontalAxis.setOrderPreserved(columnOrderPreserved); 534aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne invalidateStructure(); 535aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 5363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5385125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne // Static utility methods 5395125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 540f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static int max2(int[] a, int valueIfEmpty) { 54151f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne int result = valueIfEmpty; 54251f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne for (int i = 0, N = a.length; i < N; i++) { 54351f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne result = Math.max(result, a[i]); 54451f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne } 54551f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne return result; 54651f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne } 54751f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne 548899d5922870c78e0e663bc5661849eb468afc984Philip Milne @SuppressWarnings("unchecked") 549f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static <T> T[] append(T[] a, T[] b) { 55048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length); 55148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne System.arraycopy(a, 0, result, 0, a.length); 55248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne System.arraycopy(b, 0, result, a.length, b.length); 5533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 5543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 556f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static Alignment getAlignment(int gravity, boolean horizontal) { 5575125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK; 5585125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT; 5595125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int flags = (gravity & mask) >> shift; 5605125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne switch (flags) { 5615125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case (AXIS_SPECIFIED | AXIS_PULL_BEFORE): 5625125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return LEADING; 5635125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case (AXIS_SPECIFIED | AXIS_PULL_AFTER): 5645125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return TRAILING; 5655125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER): 5665125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return FILL; 5675125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case AXIS_SPECIFIED: 5685125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return CENTER; 5695125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne default: 5705125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return UNDEFINED_ALIGNMENT; 5715125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 5725125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 5735125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 5744c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne /** @noinspection UnusedParameters*/ 5751fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getDefaultMargin(View c, boolean horizontal, boolean leading) { 576899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (c.getClass() == Space.class) { 577899d5922870c78e0e663bc5661849eb468afc984Philip Milne return 0; 578899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 579f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return defaultGap / 2; 5803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5821fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) { 5831fd16378812792913a6aa6923acbec20037e09ffPhilip Milne return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading); 5843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5861fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getDefaultMarginValue(View c, LayoutParams p, boolean horizontal, boolean leading) { 587f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (!useDefaultMargins) { 5883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return 0; 5893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 59093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? p.columnSpec : p.rowSpec; 591f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Axis axis = horizontal ? horizontalAxis : verticalAxis; 59293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval span = spec.span; 593aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount()); 5943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5951fd16378812792913a6aa6923acbec20037e09ffPhilip Milne return getDefaultMargin(c, isAtEdge, horizontal, leading); 5963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 598f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int getMargin1(View view, boolean horizontal, boolean leading) { 5993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne LayoutParams lp = getLayoutParams(view); 6003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int margin = horizontal ? 601aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne (leading ? lp.leftMargin : lp.rightMargin) : 602aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne (leading ? lp.topMargin : lp.bottomMargin); 6031fd16378812792913a6aa6923acbec20037e09ffPhilip Milne return margin == UNDEFINED ? getDefaultMarginValue(view, lp, horizontal, leading) : margin; 6041fd16378812792913a6aa6923acbec20037e09ffPhilip Milne } 6051fd16378812792913a6aa6923acbec20037e09ffPhilip Milne 6064c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne private int getMargin(View view, boolean horizontal, boolean leading) { 607f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (alignmentMode == ALIGN_MARGINS) { 6084c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return getMargin1(view, horizontal, leading); 6094c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne } else { 610f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Axis axis = horizontal ? horizontalAxis : verticalAxis; 6114c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins(); 6124c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne LayoutParams lp = getLayoutParams(view); 6134c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 6144c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int index = leading ? spec.span.min : spec.span.max; 6154c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return margins[index]; 6164c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne } 6174c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne } 6184c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne 6191fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getTotalMargin(View child, boolean horizontal) { 6201fd16378812792913a6aa6923acbec20037e09ffPhilip Milne return getMargin(child, horizontal, true) + getMargin(child, horizontal, false); 6213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 623899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static boolean fits(int[] a, int value, int start, int end) { 624899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (end > a.length) { 625899d5922870c78e0e663bc5661849eb468afc984Philip Milne return false; 626899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 627899d5922870c78e0e663bc5661849eb468afc984Philip Milne for (int i = start; i < end; i++) { 628899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (a[i] > value) { 629899d5922870c78e0e663bc5661849eb468afc984Philip Milne return false; 6303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 631899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 632899d5922870c78e0e663bc5661849eb468afc984Philip Milne return true; 633899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 6343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 635899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static void procrusteanFill(int[] a, int start, int end, int value) { 636899d5922870c78e0e663bc5661849eb468afc984Philip Milne int length = a.length; 637899d5922870c78e0e663bc5661849eb468afc984Philip Milne Arrays.fill(a, Math.min(start, length), Math.min(end, length), value); 638899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 6393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 640899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static void setCellGroup(LayoutParams lp, int row, int rowSpan, int col, int colSpan) { 641899d5922870c78e0e663bc5661849eb468afc984Philip Milne lp.setRowSpecSpan(new Interval(row, row + rowSpan)); 642899d5922870c78e0e663bc5661849eb468afc984Philip Milne lp.setColumnSpecSpan(new Interval(col, col + colSpan)); 643899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 6443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 645899d5922870c78e0e663bc5661849eb468afc984Philip Milne // Logic to avert infinite loops by ensuring that the cells can be placed somewhere. 646899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static int clip(Interval minorRange, boolean minorWasDefined, int count) { 647899d5922870c78e0e663bc5661849eb468afc984Philip Milne int size = minorRange.size(); 648899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (count == 0) { 649899d5922870c78e0e663bc5661849eb468afc984Philip Milne return size; 650899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 651899d5922870c78e0e663bc5661849eb468afc984Philip Milne int min = minorWasDefined ? min(minorRange.min, count) : 0; 652899d5922870c78e0e663bc5661849eb468afc984Philip Milne return min(size, count - min); 653899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 654f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne 655899d5922870c78e0e663bc5661849eb468afc984Philip Milne // install default indices for cells that don't define them 656899d5922870c78e0e663bc5661849eb468afc984Philip Milne private void validateLayoutParams() { 657f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean horizontal = (orientation == HORIZONTAL); 658f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Axis axis = horizontal ? horizontalAxis : verticalAxis; 659f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0; 660f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne 661899d5922870c78e0e663bc5661849eb468afc984Philip Milne int major = 0; 662899d5922870c78e0e663bc5661849eb468afc984Philip Milne int minor = 0; 663899d5922870c78e0e663bc5661849eb468afc984Philip Milne int[] maxSizes = new int[count]; 664f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne 665899d5922870c78e0e663bc5661849eb468afc984Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 666899d5922870c78e0e663bc5661849eb468afc984Philip Milne LayoutParams lp = getLayoutParams1(getChildAt(i)); 667899d5922870c78e0e663bc5661849eb468afc984Philip Milne 668f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec; 669f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Interval majorRange = majorSpec.span; 670f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean majorWasDefined = majorSpec.startDefined; 671899d5922870c78e0e663bc5661849eb468afc984Philip Milne final int majorSpan = majorRange.size(); 672899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (majorWasDefined) { 673899d5922870c78e0e663bc5661849eb468afc984Philip Milne major = majorRange.min; 674899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 675899d5922870c78e0e663bc5661849eb468afc984Philip Milne 676f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec; 677f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Interval minorRange = minorSpec.span; 678f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean minorWasDefined = minorSpec.startDefined; 679899d5922870c78e0e663bc5661849eb468afc984Philip Milne final int minorSpan = clip(minorRange, minorWasDefined, count); 680899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (minorWasDefined) { 681899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor = minorRange.min; 682899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 683899d5922870c78e0e663bc5661849eb468afc984Philip Milne 684899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (count != 0) { 685899d5922870c78e0e663bc5661849eb468afc984Philip Milne // Find suitable row/col values when at least one is undefined. 686899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (!majorWasDefined || !minorWasDefined) { 687899d5922870c78e0e663bc5661849eb468afc984Philip Milne while (!fits(maxSizes, major, minor, minor + minorSpan)) { 688899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (minorWasDefined) { 689899d5922870c78e0e663bc5661849eb468afc984Philip Milne major++; 690899d5922870c78e0e663bc5661849eb468afc984Philip Milne } else { 691899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (minor + minorSpan <= count) { 692899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor++; 693899d5922870c78e0e663bc5661849eb468afc984Philip Milne } else { 694899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor = 0; 695899d5922870c78e0e663bc5661849eb468afc984Philip Milne major++; 696899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 697f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne } 698f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne } 6993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 700899d5922870c78e0e663bc5661849eb468afc984Philip Milne procrusteanFill(maxSizes, minor, minor + minorSpan, major + majorSpan); 7013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 702899d5922870c78e0e663bc5661849eb468afc984Philip Milne 703899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (horizontal) { 704899d5922870c78e0e663bc5661849eb468afc984Philip Milne setCellGroup(lp, major, majorSpan, minor, minorSpan); 705899d5922870c78e0e663bc5661849eb468afc984Philip Milne } else { 706899d5922870c78e0e663bc5661849eb468afc984Philip Milne setCellGroup(lp, minor, minorSpan, major, majorSpan); 707899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 708899d5922870c78e0e663bc5661849eb468afc984Philip Milne 709899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor = minor + minorSpan; 710899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 711f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne invalidateStructure(); 7123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void invalidateStructure() { 715f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne layoutParamsValid = false; 716f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne horizontalAxis.invalidateStructure(); 717f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne verticalAxis.invalidateStructure(); 718899d5922870c78e0e663bc5661849eb468afc984Philip Milne // This can end up being done twice. Better twice than not at all. 7193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateValues(); 7203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void invalidateValues() { 723aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne // Need null check because requestLayout() is called in View's initializer, 724aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne // before we are set up. 725f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (horizontalAxis != null && verticalAxis != null) { 726f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne horizontalAxis.invalidateValues(); 727f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne verticalAxis.invalidateValues(); 728aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 7293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private LayoutParams getLayoutParams1(View c) { 7323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return (LayoutParams) c.getLayoutParams(); 7333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 735f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final LayoutParams getLayoutParams(View c) { 736f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (!layoutParamsValid) { 7373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne validateLayoutParams(); 738f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne layoutParamsValid = true; 7393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return getLayoutParams1(c); 7413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 7443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected LayoutParams generateDefaultLayoutParams() { 7453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return new LayoutParams(); 7463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 7493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams generateLayoutParams(AttributeSet attrs) { 7505125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return new LayoutParams(getContext(), attrs); 7513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 7543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 7553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return new LayoutParams(p); 7563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Draw grid 7593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) { 7613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int dx = getPaddingLeft(); 7623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int dy = getPaddingTop(); 7633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint); 7643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 766b559976a50c34848d602cc7138859507a379893cPhilip Milne private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) { 767b559976a50c34848d602cc7138859507a379893cPhilip Milne canvas.drawRect(x1, y1, x2 - 1, y2 - 1, paint); 768b559976a50c34848d602cc7138859507a379893cPhilip Milne } 769b559976a50c34848d602cc7138859507a379893cPhilip Milne 7703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 7713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected void onDraw(Canvas canvas) { 7723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super.onDraw(canvas); 7733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (DEBUG) { 7753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int height = getHeight() - getPaddingTop() - getPaddingBottom(); 7763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int width = getWidth() - getPaddingLeft() - getPaddingRight(); 7773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 778b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne Paint paint = new Paint(); 7794c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne paint.setStyle(Paint.Style.STROKE); 780b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne paint.setColor(Color.argb(50, 255, 255, 255)); 781b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 782f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int[] xs = horizontalAxis.locations; 783b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne if (xs != null) { 784b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, length = xs.length; i < length; i++) { 785b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne int x = xs[i]; 786b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne drawLine(canvas, x, 0, x, height - 1, paint); 787b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 7883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 789b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 790f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int[] ys = verticalAxis.locations; 791b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne if (ys != null) { 792b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, length = ys.length; i < length; i++) { 793b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne int y = ys[i]; 794b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne drawLine(canvas, 0, y, width - 1, y, paint); 795b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 796b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 79748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 798b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne // Draw bounds 799b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne paint.setColor(Color.BLUE); 800b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0; i < getChildCount(); i++) { 801b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 802b559976a50c34848d602cc7138859507a379893cPhilip Milne drawRect(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(), paint); 803b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 804b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 805b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne // Draw margins 80693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne paint.setColor(Color.MAGENTA); 807b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0; i < getChildCount(); i++) { 808b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 809b559976a50c34848d602cc7138859507a379893cPhilip Milne drawRect(canvas, 8104c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne c.getLeft() - getMargin1(c, true, true), 8114c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne c.getTop() - getMargin1(c, false, true), 8124c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne c.getRight() + getMargin1(c, true, false), 8134c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne c.getBottom() + getMargin1(c, false, false), paint); 8143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Add/remove 8193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 820e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne /** 821e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne * @hide 822e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne */ 8233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 824f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne protected void onViewAdded(View child) { 825f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne super.onViewAdded(child); 8263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateStructure(); 8273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 829e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne /** 830e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne * @hide 831e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne */ 8323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 833f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne protected void onViewRemoved(View child) { 834f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne super.onViewRemoved(child); 835b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne invalidateStructure(); 836350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne } 837350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne 838350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne /** 839350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * We need to call invalidateStructure() when a child's GONE flag changes state. 840350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * This implementation is a catch-all, invalidating on any change in the visibility flags. 841350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * 842350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * @hide 843350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne */ 844350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne @Override 8450d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) { 8460d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase super.onChildVisibilityChanged(child, oldVisibility, newVisibility); 8470d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase if (oldVisibility == GONE || newVisibility == GONE) { 8480d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase invalidateStructure(); 8490d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase } 850b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne } 851b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne 8523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Measurement 8533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 854f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean isGone(View c) { 855b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne return c.getVisibility() == View.GONE; 856b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 857b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 8584a145d72622772b920f60195e80942058984259cPhilip Milne private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec, 8594a145d72622772b920f60195e80942058984259cPhilip Milne int childWidth, int childHeight) { 8604a145d72622772b920f60195e80942058984259cPhilip Milne int childWidthSpec = getChildMeasureSpec(parentWidthSpec, 8614a145d72622772b920f60195e80942058984259cPhilip Milne mPaddingLeft + mPaddingRight + getTotalMargin(child, true), childWidth); 8624a145d72622772b920f60195e80942058984259cPhilip Milne int childHeightSpec = getChildMeasureSpec(parentHeightSpec, 8634a145d72622772b920f60195e80942058984259cPhilip Milne mPaddingTop + mPaddingBottom + getTotalMargin(child, false), childHeight); 8644a145d72622772b920f60195e80942058984259cPhilip Milne child.measure(childWidthSpec, childHeightSpec); 865b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 866b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 8674a145d72622772b920f60195e80942058984259cPhilip Milne private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) { 868b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 869b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 870b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne if (isGone(c)) continue; 8714a145d72622772b920f60195e80942058984259cPhilip Milne LayoutParams lp = getLayoutParams(c); 8724a145d72622772b920f60195e80942058984259cPhilip Milne if (firstPass) { 8734a145d72622772b920f60195e80942058984259cPhilip Milne measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height); 8744a145d72622772b920f60195e80942058984259cPhilip Milne } else { 875ecab1178648670f2c72b47faf250040fcded3d13Philip Milne boolean horizontal = (orientation == HORIZONTAL); 876ecab1178648670f2c72b47faf250040fcded3d13Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 8774a145d72622772b920f60195e80942058984259cPhilip Milne if (spec.alignment == FILL) { 8784a145d72622772b920f60195e80942058984259cPhilip Milne Interval span = spec.span; 879ecab1178648670f2c72b47faf250040fcded3d13Philip Milne Axis axis = horizontal ? horizontalAxis : verticalAxis; 8804a145d72622772b920f60195e80942058984259cPhilip Milne int[] locations = axis.getLocations(); 881ecab1178648670f2c72b47faf250040fcded3d13Philip Milne int cellSize = locations[span.max] - locations[span.min]; 882ecab1178648670f2c72b47faf250040fcded3d13Philip Milne int viewSize = cellSize - getTotalMargin(c, horizontal); 883ecab1178648670f2c72b47faf250040fcded3d13Philip Milne if (horizontal) { 884ecab1178648670f2c72b47faf250040fcded3d13Philip Milne measureChildWithMargins2(c, widthSpec, heightSpec, viewSize, lp.height); 8854a145d72622772b920f60195e80942058984259cPhilip Milne } else { 886ecab1178648670f2c72b47faf250040fcded3d13Philip Milne measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, viewSize); 8874a145d72622772b920f60195e80942058984259cPhilip Milne } 8884a145d72622772b920f60195e80942058984259cPhilip Milne } 8894a145d72622772b920f60195e80942058984259cPhilip Milne } 890b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 891b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 892b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 893aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne @Override 894aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne protected void onMeasure(int widthSpec, int heightSpec) { 8954a145d72622772b920f60195e80942058984259cPhilip Milne /** If we have been called by {@link View#measure(int, int)}, one of width or height 8964a145d72622772b920f60195e80942058984259cPhilip Milne * is likely to have changed. We must invalidate if so. */ 8974a145d72622772b920f60195e80942058984259cPhilip Milne invalidateValues(); 8984a145d72622772b920f60195e80942058984259cPhilip Milne 8994a145d72622772b920f60195e80942058984259cPhilip Milne measureChildrenWithMargins(widthSpec, heightSpec, true); 9004a145d72622772b920f60195e80942058984259cPhilip Milne 9014a145d72622772b920f60195e80942058984259cPhilip Milne int width, height; 9024a145d72622772b920f60195e80942058984259cPhilip Milne 9034a145d72622772b920f60195e80942058984259cPhilip Milne // Use the orientation property to decide which axis should be laid out first. 9044a145d72622772b920f60195e80942058984259cPhilip Milne if (orientation == HORIZONTAL) { 9054a145d72622772b920f60195e80942058984259cPhilip Milne width = horizontalAxis.getMeasure(widthSpec); 9064a145d72622772b920f60195e80942058984259cPhilip Milne measureChildrenWithMargins(widthSpec, heightSpec, false); 9074a145d72622772b920f60195e80942058984259cPhilip Milne height = verticalAxis.getMeasure(heightSpec); 9084a145d72622772b920f60195e80942058984259cPhilip Milne } else { 9094a145d72622772b920f60195e80942058984259cPhilip Milne height = verticalAxis.getMeasure(heightSpec); 9104a145d72622772b920f60195e80942058984259cPhilip Milne measureChildrenWithMargins(widthSpec, heightSpec, false); 9114a145d72622772b920f60195e80942058984259cPhilip Milne width = horizontalAxis.getMeasure(widthSpec); 9124a145d72622772b920f60195e80942058984259cPhilip Milne } 913aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 9144a145d72622772b920f60195e80942058984259cPhilip Milne int hPadding = getPaddingLeft() + getPaddingRight(); 9154a145d72622772b920f60195e80942058984259cPhilip Milne int vPadding = getPaddingTop() + getPaddingBottom(); 9163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 9174a145d72622772b920f60195e80942058984259cPhilip Milne int measuredWidth = Math.max(hPadding + width, getSuggestedMinimumWidth()); 9184a145d72622772b920f60195e80942058984259cPhilip Milne int measuredHeight = Math.max(vPadding + height, getSuggestedMinimumHeight()); 91909e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne 9203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setMeasuredDimension( 92109e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne resolveSizeAndState(measuredWidth, widthSpec, 0), 92209e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne resolveSizeAndState(measuredHeight, heightSpec, 0)); 9233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 9243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 9253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private int protect(int alignment) { 926aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return (alignment == UNDEFINED) ? 0 : alignment; 9273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 9283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 92948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private int getMeasurement(View c, boolean horizontal) { 930aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight(); 9313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 9323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 933f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final int getMeasurementIncludingMargin(View c, boolean horizontal) { 9345125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne if (isGone(c)) { 9355125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return 0; 9365125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 9374c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal); 938aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 9393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 940aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne @Override 941aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public void requestLayout() { 942aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne super.requestLayout(); 943aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne invalidateValues(); 944aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 945aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 946f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Alignment getAlignment(Alignment alignment, boolean horizontal) { 9475125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return (alignment != UNDEFINED_ALIGNMENT) ? alignment : 948899d5922870c78e0e663bc5661849eb468afc984Philip Milne (horizontal ? LEFT : BASELINE); 9495125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 9505125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 9513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Layout container 9523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 953aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 954aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * {@inheritDoc} 955aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 956aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 957aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne The layout operation is implemented by delegating the heavy lifting to the 958aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne to the mHorizontalAxis and mVerticalAxis instances of the internal Axis class. 959aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Together they compute the locations of the vertical and horizontal lines of 960aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne the grid (respectively!). 961aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 962aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This method is then left with the simpler task of applying margins, gravity 963aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne and sizing to each child view and then placing it in its cell. 964aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 9653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 96609e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 96709e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne int targetWidth = right - left; 96809e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne int targetHeight = bottom - top; 9693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 9703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingLeft = getPaddingLeft(); 9713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingTop = getPaddingTop(); 9723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingRight = getPaddingRight(); 9733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingBottom = getPaddingBottom(); 9743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 975f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne horizontalAxis.layout(targetWidth - paddingLeft - paddingRight); 976f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne verticalAxis.layout(targetHeight - paddingTop - paddingBottom); 9773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 978f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int[] hLocations = horizontalAxis.getLocations(); 979f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int[] vLocations = verticalAxis.getLocations(); 9804c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne 981b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 982b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 983b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne if (isGone(c)) continue; 984b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne LayoutParams lp = getLayoutParams(c); 98593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec columnSpec = lp.columnSpec; 98693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec rowSpec = lp.rowSpec; 987aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 98893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval colSpan = columnSpec.span; 98993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval rowSpan = rowSpec.span; 9903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 9914c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int x1 = hLocations[colSpan.min]; 9924c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int y1 = vLocations[rowSpan.min]; 9933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 9944c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int x2 = hLocations[colSpan.max]; 9954c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int y2 = vLocations[rowSpan.max]; 9963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 9973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int cellWidth = x2 - x1; 9983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int cellHeight = y2 - y1; 9993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 100048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int pWidth = getMeasurement(c, true); 100148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int pHeight = getMeasurement(c, false); 10023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 10035125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Alignment hAlign = getAlignment(columnSpec.alignment, true); 10045125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Alignment vAlign = getAlignment(rowSpec.alignment, false); 1005aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1006aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int dx, dy; 10073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1008f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Bounds colBounds = horizontalAxis.getGroupBounds().getValue(i); 1009f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Bounds rowBounds = verticalAxis.getGroupBounds().getValue(i); 10107fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 10117fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne // Gravity offsets: the location of the alignment group relative to its cell group. 10124c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne //noinspection NullableProblems 101348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(true))); 10144c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne //noinspection NullableProblems 101548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(true))); 10167fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 10174c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int leftMargin = getMargin(c, true, true); 10184c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int topMargin = getMargin(c, false, true); 10194c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int rightMargin = getMargin(c, true, false); 10204c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int bottomMargin = getMargin(c, false, false); 10217fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 10224c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne // Same calculation as getMeasurementIncludingMargin() 10234c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int mWidth = leftMargin + pWidth + rightMargin; 10244c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int mHeight = topMargin + pHeight + bottomMargin; 10253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 10264c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne // Alignment offsets: the location of the view relative to its alignment group. 10274c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int a2vx = colBounds.getOffset(c, hAlign, mWidth); 10284c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int a2vy = rowBounds.getOffset(c, vAlign, mHeight); 10297fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 10304c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne dx = c2ax + a2vx + leftMargin; 10314c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne dy = c2ay + a2vy + topMargin; 10327fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 10334c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne cellWidth -= leftMargin + rightMargin; 10344c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne cellHeight -= topMargin + bottomMargin; 10353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 103648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int type = PRF; 1037b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne int width = hAlign.getSizeInCell(c, pWidth, cellWidth, type); 1038b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne int height = vAlign.getSizeInCell(c, pHeight, cellHeight, type); 10393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 10403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int cx = paddingLeft + x1 + dx; 10413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int cy = paddingTop + y1 + dy; 1042899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) { 1043899d5922870c78e0e663bc5661849eb468afc984Philip Milne c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY)); 1044899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 1045b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne c.layout(cx, cy, cx + width, cy + height); 10463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 10473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 10483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 10498a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 10508a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 10518a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 10528a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(GridLayout.class.getName()); 10538a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 10548a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 10558a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 10568a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 10578a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(info); 10588a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov info.setClassName(GridLayout.class.getName()); 10598a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 10608a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 10613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Inner classes 10623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1063aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1064aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This internal class houses the algorithm for computing the locations of grid lines; 1065aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne along either the horizontal or vertical axis. A GridLayout uses two instances of this class - 1066aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne distinguished by the "horizontal" flag which is true for the horizontal axis and false 1067aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne for the vertical one. 1068aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 1069f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final class Axis { 107048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private static final int NEW = 0; 10713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int PENDING = 1; 10723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int COMPLETE = 2; 10733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 10743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final boolean horizontal; 10753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1076f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int definedCount = UNDEFINED; 10774a145d72622772b920f60195e80942058984259cPhilip Milne private int maxIndex = UNDEFINED; 10783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 107993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne PackedMap<Spec, Bounds> groupBounds; 10803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean groupBoundsValid = false; 10813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 108248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne PackedMap<Interval, MutableInt> forwardLinks; 108348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean forwardLinksValid = false; 108448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 108548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne PackedMap<Interval, MutableInt> backwardLinks; 108648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean backwardLinksValid = false; 10873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 10883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int[] leadingMargins; 1089aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public boolean leadingMarginsValid = false; 1090aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 10913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int[] trailingMargins; 1092aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public boolean trailingMarginsValid = false; 10933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 10943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public Arc[] arcs; 10953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean arcsValid = false; 10963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1097aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public int[] locations; 109848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean locationsValid = false; 1099aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1100f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean orderPreserved = DEFAULT_ORDER_PRESERVED; 11013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 110248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private MutableInt parentMin = new MutableInt(0); 110348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private MutableInt parentMax = new MutableInt(-MAX_SIZE); 110448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 11053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private Axis(boolean horizontal) { 11063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.horizontal = horizontal; 11073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11094a145d72622772b920f60195e80942058984259cPhilip Milne private int calculateMaxIndex() { 11104a145d72622772b920f60195e80942058984259cPhilip Milne // the number Integer.MIN_VALUE + 1 comes up in undefined cells 11114a145d72622772b920f60195e80942058984259cPhilip Milne int result = -1; 1112b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1113b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 1114b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne LayoutParams params = getLayoutParams(c); 111593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? params.columnSpec : params.rowSpec; 11164a145d72622772b920f60195e80942058984259cPhilip Milne Interval span = spec.span; 11174a145d72622772b920f60195e80942058984259cPhilip Milne result = max(result, span.min); 11184a145d72622772b920f60195e80942058984259cPhilip Milne result = max(result, span.max); 11193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11204a145d72622772b920f60195e80942058984259cPhilip Milne return result == -1 ? UNDEFINED : result; 11213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11234a145d72622772b920f60195e80942058984259cPhilip Milne private int getMaxIndex() { 11244a145d72622772b920f60195e80942058984259cPhilip Milne if (maxIndex == UNDEFINED) { 11254a145d72622772b920f60195e80942058984259cPhilip Milne maxIndex = max(0, calculateMaxIndex()); // use zero when there are no children 11263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11274a145d72622772b920f60195e80942058984259cPhilip Milne return maxIndex; 1128f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1129f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1130f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int getCount() { 11314a145d72622772b920f60195e80942058984259cPhilip Milne return max(definedCount, getMaxIndex()); 11323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setCount(int count) { 1135f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.definedCount = count; 11363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean isOrderPreserved() { 1139f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return orderPreserved; 11403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setOrderPreserved(boolean orderPreserved) { 1143f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.orderPreserved = orderPreserved; 11443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateStructure(); 11453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 114793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne private PackedMap<Spec, Bounds> createGroupBounds() { 114893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class); 114948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1150b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 11515125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne LayoutParams lp = getLayoutParams(c); 11525125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 11535125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds(); 11545125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne assoc.put(spec, bounds); 11553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 115648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return assoc.pack(); 11573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void computeGroupBounds() { 1160b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne Bounds[] values = groupBounds.values; 1161b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0; i < values.length; i++) { 1162b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne values[i].reset(); 11633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 1164aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 11653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne View c = getChildAt(i); 11663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne LayoutParams lp = getLayoutParams(c); 116793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 116893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne groupBounds.getValue(i).include(c, spec, GridLayout.this, this); 11693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1172f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public PackedMap<Spec, Bounds> getGroupBounds() { 11733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (groupBounds == null) { 11743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBounds = createGroupBounds(); 11753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (!groupBoundsValid) { 11773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne computeGroupBounds(); 11783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBoundsValid = true; 11793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return groupBounds; 11813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Add values computed by alignment - taking the max of all alignments in each span 118448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private PackedMap<Interval, MutableInt> createLinks(boolean min) { 118548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class); 118693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec[] keys = getGroupBounds().keys; 118748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0, N = keys.length; i < N; i++) { 118848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Interval span = min ? keys[i].span : keys[i].span.inverse(); 118948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne result.put(span, new MutableInt()); 11903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 119148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return result.pack(); 11923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 119448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) { 119548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne MutableInt[] spans = links.values; 11963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < spans.length; i++) { 11973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne spans[i].reset(); 11983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12005d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne // Use getter to trigger a re-evaluation 120148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Bounds[] bounds = getGroupBounds().values; 12023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < bounds.length; i++) { 120348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int size = bounds[i].size(min); 120448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne MutableInt valueHolder = links.getValue(i); 12055125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne // this effectively takes the max() of the minima and the min() of the maxima 12065125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne valueHolder.value = max(valueHolder.value, min ? size : -size); 12073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 121048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private PackedMap<Interval, MutableInt> getForwardLinks() { 121148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (forwardLinks == null) { 121248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinks = createLinks(true); 12133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 121448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!forwardLinksValid) { 121548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeLinks(forwardLinks, true); 121648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinksValid = true; 12173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 121848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return forwardLinks; 12193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 122148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private PackedMap<Interval, MutableInt> getBackwardLinks() { 122248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (backwardLinks == null) { 122348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinks = createLinks(false); 12243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 122548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!backwardLinksValid) { 122648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeLinks(backwardLinks, false); 122748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinksValid = true; 122848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 122948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return backwardLinks; 12303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 123248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void include(List<Arc> arcs, Interval key, MutableInt size, 12334a145d72622772b920f60195e80942058984259cPhilip Milne boolean ignoreIfAlreadyPresent) { 123448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne /* 123548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Remove self referential links. 123648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne These appear: 123748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne . as parental constraints when GridLayout has no children 123848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne . when components have been marked as GONE 123948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne */ 124048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (key.size() == 0) { 124148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return; 12423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 124348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // this bit below should really be computed outside here - 124448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // its just to stop default (row/col > 0) constraints obliterating valid entries 124548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (ignoreIfAlreadyPresent) { 124648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (Arc arc : arcs) { 124748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Interval span = arc.span; 124848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (span.equals(key)) { 124948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return; 125048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 125148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 125248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 125348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne arcs.add(new Arc(key, size)); 12543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 125648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void include(List<Arc> arcs, Interval key, MutableInt size) { 125748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(arcs, key, size, true); 12583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1260aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne // Group arcs by their first vertex, returning an array of arrays. 12613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // This is linear in the number of arcs. 1262f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Arc[][] groupArcsByFirstVertex(Arc[] arcs) { 126348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int N = getCount() + 1; // the number of vertices 12643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Arc[][] result = new Arc[N][]; 12653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int[] sizes = new int[N]; 12663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (Arc arc : arcs) { 12673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne sizes[arc.span.min]++; 12685d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 12693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < sizes.length; i++) { 12703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result[i] = new Arc[sizes[i]]; 12713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // reuse the sizes array to hold the current last elements as we insert each arc 12733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Arrays.fill(sizes, 0); 12743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (Arc arc : arcs) { 12753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int i = arc.span.min; 12763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result[i][sizes[i]++] = arc; 12773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 12803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 128248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private Arc[] topologicalSort(final Arc[] arcs) { 128348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return new Object() { 128448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] result = new Arc[arcs.length]; 128548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int cursor = result.length - 1; 128648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs); 12873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int[] visited = new int[getCount() + 1]; 12883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 128948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne void walk(int loc) { 129048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne switch (visited[loc]) { 129148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case NEW: { 129248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne visited[loc] = PENDING; 129348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (Arc arc : arcsByVertex[loc]) { 129448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne walk(arc.span.max); 129548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne result[cursor--] = arc; 12963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 129748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne visited[loc] = COMPLETE; 129848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne break; 129948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 130048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case PENDING: { 130148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne assert false; 130248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne break; 130348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 130448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case COMPLETE: { 130548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne break; 13063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 130948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 131048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] sort() { 131148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) { 131248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne walk(loc); 131348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 131448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne assert cursor == -1; 131548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return result; 131648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 131748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne }.sort(); 131848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 131948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 132048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private Arc[] topologicalSort(List<Arc> arcs) { 132148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return topologicalSort(arcs.toArray(new Arc[arcs.size()])); 13223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 132448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) { 132548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0; i < links.keys.length; i++) { 132648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Interval key = links.keys[i]; 132748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(result, key, links.values[i], false); 132848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 132948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 133048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1331aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private Arc[] createArcs() { 133248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne List<Arc> mins = new ArrayList<Arc>(); 133348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne List<Arc> maxs = new ArrayList<Arc>(); 13343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 133548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add the minimum values from the components. 133648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne addComponentSizes(mins, getForwardLinks()); 133748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add the maximum values from the components. 133848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne addComponentSizes(maxs, getBackwardLinks()); 13393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 134048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add ordering constraints to prevent row/col sizes from going negative 1341f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (orderPreserved) { 134248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add a constraint for every row/col 13433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < getCount(); i++) { 1344899d5922870c78e0e663bc5661849eb468afc984Philip Milne include(mins, new Interval(i, i + 1), new MutableInt(0)); 13453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 134748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 134848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add the container constraints. Use the version of include that allows 134948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // duplicate entries in case a child spans the entire grid. 135048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int N = getCount(); 135148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(mins, new Interval(0, N), parentMin, false); 135248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(maxs, new Interval(N, 0), parentMax, false); 135348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 135448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Sort 135548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] sMins = topologicalSort(mins); 135648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] sMaxs = topologicalSort(maxs); 135748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 135848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return append(sMins, sMaxs); 135948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 136048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 136148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void computeArcs() { 136248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // getting the links validates the values that are shared by the arc list 136348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne getForwardLinks(); 136448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne getBackwardLinks(); 13653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1367aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public Arc[] getArcs() { 13683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (arcs == null) { 1369aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne arcs = createArcs(); 13703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (!arcsValid) { 137248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeArcs(); 13733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne arcsValid = true; 13743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return arcs; 13763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1378aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private boolean relax(int[] locations, Arc entry) { 137948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!entry.valid) { 138048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return false; 138148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 13823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Interval span = entry.span; 13833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int u = span.min; 13843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int v = span.max; 13853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int value = entry.value.value; 13863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int candidate = locations[u] + value; 1387aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (candidate > locations[v]) { 13883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne locations[v] = candidate; 13893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 13903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 13923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1394f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private void init(int[] locations) { 13954a145d72622772b920f60195e80942058984259cPhilip Milne Arrays.fill(locations, 0); 1396f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1397f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1398f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private String arcsToString(List<Arc> arcs) { 13994a145d72622772b920f60195e80942058984259cPhilip Milne String var = horizontal ? "x" : "y"; 1400f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne StringBuilder result = new StringBuilder(); 14014a145d72622772b920f60195e80942058984259cPhilip Milne boolean first = true; 14024a145d72622772b920f60195e80942058984259cPhilip Milne for (Arc arc : arcs) { 14034a145d72622772b920f60195e80942058984259cPhilip Milne if (first) { 14044a145d72622772b920f60195e80942058984259cPhilip Milne first = false; 1405f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } else { 14064a145d72622772b920f60195e80942058984259cPhilip Milne result = result.append(", "); 1407f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1408f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int src = arc.span.min; 1409f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int dst = arc.span.max; 1410f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int value = arc.value.value; 1411f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne result.append((src < dst) ? 1412f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne var + dst + " - " + var + src + " > " + value : 1413f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne var + src + " - " + var + dst + " < " + -value); 1414f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1415f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1416f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return result.toString(); 1417f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1418f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1419f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private void logError(String axisName, Arc[] arcs, boolean[] culprits0) { 1420f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne List<Arc> culprits = new ArrayList<Arc>(); 1421f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne List<Arc> removed = new ArrayList<Arc>(); 1422f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int c = 0; c < arcs.length; c++) { 1423f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Arc arc = arcs[c]; 1424f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (culprits0[c]) { 1425f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne culprits.add(arc); 1426f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1427f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (!arc.valid) { 1428f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne removed.add(arc); 1429f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1430f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1431f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Log.d(TAG, axisName + " constraints: " + arcsToString(culprits) + " are inconsistent; " 1432f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne + "permanently removing: " + arcsToString(removed) + ". "); 1433f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1434f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1435aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1436aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N) 1437aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1438aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne GridLayout converts its requirements into a system of linear constraints of the 1439aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne form: 1440aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1441aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne x[i] - x[j] < a[k] 1442aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1443aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Where the x[i] are variables and the a[k] are constants. 1444aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1445aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne For example, if the variables were instead labeled x, y, z we might have: 1446aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1447aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne x - y < 17 1448aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne y - z < 23 1449aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne z - x < 42 1450aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1451aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This is a special case of the Linear Programming problem that is, in turn, 1452aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne equivalent to the single-source shortest paths problem on a digraph, for 1453aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne which the O(n^2) Bellman-Ford algorithm the most commonly used general solution. 1454aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1455aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Other algorithms are faster in the case where no arcs have negative weights 1456aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne but allowing negative weights turns out to be the same as accommodating maximum 1457aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne size requirements as well as minimum ones. 1458aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1459aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Bellman-Ford works by iteratively 'relaxing' constraints over all nodes (an O(N) 1460aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne process) and performing this step N times. Proof of correctness hinges on the 1461aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne fact that there can be no negative weight chains of length > N - unless a 1462aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 'negative weight loop' exists. The algorithm catches this case in a final 1463aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne checking phase that reports failure. 1464aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1465aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne By topologically sorting the nodes and checking this condition at each step 1466aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne typical layout problems complete after the first iteration and the algorithm 1467aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne completes in O(N) steps with very low constants. 1468aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 146948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void solve(Arc[] arcs, int[] locations) { 1470f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne String axisName = horizontal ? "horizontal" : "vertical"; 14713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1. 1472f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean[] originalCulprits = null; 14733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1474f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int p = 0; p < arcs.length; p++) { 1475f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne init(locations); 1476f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1477f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne // We take one extra pass over traditional Bellman-Ford (and omit their final step) 1478f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int i = 0; i < N; i++) { 1479f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean changed = false; 1480f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int j = 0, length = arcs.length; j < length; j++) { 1481f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne changed |= relax(locations, arcs[j]); 1482f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1483f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (!changed) { 1484f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (originalCulprits != null) { 1485f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne logError(axisName, arcs, originalCulprits); 1486f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1487f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return; 14883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 149048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1491f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean[] culprits = new boolean[arcs.length]; 1492f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int i = 0; i < N; i++) { 1493f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int j = 0, length = arcs.length; j < length; j++) { 1494f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne culprits[j] |= relax(locations, arcs[j]); 1495f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1496f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 149748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1498f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (p == 0) { 1499f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne originalCulprits = culprits; 150048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1501f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1502f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int i = 0; i < arcs.length; i++) { 1503f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (culprits[i]) { 1504f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Arc arc = arcs[i]; 1505f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne // Only remove max values, min values alone cannot be inconsistent 1506f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (arc.span.min < arc.span.max) { 1507f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne continue; 1508f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1509f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne arc.valid = false; 1510f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne break; 151148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 151248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 151348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 15143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1516aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private void computeMargins(boolean leading) { 1517aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int[] margins = leading ? leadingMargins : trailingMargins; 1518b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 15193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne View c = getChildAt(i); 1520b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne if (isGone(c)) continue; 15213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne LayoutParams lp = getLayoutParams(c); 152293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 152393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval span = spec.span; 15243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int index = leading ? span.min : span.max; 15254c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne margins[index] = max(margins[index], getMargin1(c, horizontal, leading)); 15263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1529f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne // External entry points 1530f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1531f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int[] getLeadingMargins() { 1532aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (leadingMargins == null) { 1533aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMargins = new int[getCount() + 1]; 1534aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1535aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (!leadingMarginsValid) { 1536aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne computeMargins(true); 1537aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMarginsValid = true; 1538aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1539aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return leadingMargins; 1540aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1541aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1542f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int[] getTrailingMargins() { 1543aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (trailingMargins == null) { 1544aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMargins = new int[getCount() + 1]; 1545aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1546aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (!trailingMarginsValid) { 1547aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne computeMargins(false); 1548aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMarginsValid = true; 1549aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1550aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return trailingMargins; 1551aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 15523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 155348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void computeLocations(int[] a) { 1554f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne solve(getArcs(), a); 15554a145d72622772b920f60195e80942058984259cPhilip Milne if (!orderPreserved) { 15564a145d72622772b920f60195e80942058984259cPhilip Milne // Solve returns the smallest solution to the constraint system for which all 15574a145d72622772b920f60195e80942058984259cPhilip Milne // values are positive. One value is therefore zero - though if the row/col 15584a145d72622772b920f60195e80942058984259cPhilip Milne // order is not preserved this may not be the first vertex. For consistency, 15594a145d72622772b920f60195e80942058984259cPhilip Milne // translate all the values so that they measure the distance from a[0]; the 15604a145d72622772b920f60195e80942058984259cPhilip Milne // leading edge of the parent. After this transformation some values may be 15614a145d72622772b920f60195e80942058984259cPhilip Milne // negative. 15624a145d72622772b920f60195e80942058984259cPhilip Milne int a0 = a[0]; 15634a145d72622772b920f60195e80942058984259cPhilip Milne for (int i = 0, N = a.length; i < N; i++) { 15644a145d72622772b920f60195e80942058984259cPhilip Milne a[i] = a[i] - a0; 15654a145d72622772b920f60195e80942058984259cPhilip Milne } 15664a145d72622772b920f60195e80942058984259cPhilip Milne } 15673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1569f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int[] getLocations() { 1570aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (locations == null) { 1571aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int N = getCount() + 1; 1572aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne locations = new int[N]; 1573aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 157448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!locationsValid) { 157548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeLocations(locations); 157648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne locationsValid = true; 157748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1578aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return locations; 15793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1581aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private int size(int[] locations) { 15824a145d72622772b920f60195e80942058984259cPhilip Milne // The parental edges are attached to vertices 0 and N - even when order is not 15834a145d72622772b920f60195e80942058984259cPhilip Milne // being preserved and other vertices fall outside this range. Measure the distance 15844a145d72622772b920f60195e80942058984259cPhilip Milne // between vertices 0 and N, assuming that locations[0] = 0. 15854a145d72622772b920f60195e80942058984259cPhilip Milne return locations[getCount()]; 1586aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1587aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 158848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void setParentConstraints(int min, int max) { 158948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne parentMin.value = min; 159048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne parentMax.value = -max; 159148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne locationsValid = false; 15923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 159448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private int getMeasure(int min, int max) { 159548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne setParentConstraints(min, max); 159648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return size(getLocations()); 159748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1598aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1599f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int getMeasure(int measureSpec) { 160048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int mode = MeasureSpec.getMode(measureSpec); 160148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int size = MeasureSpec.getSize(measureSpec); 160248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne switch (mode) { 160348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case MeasureSpec.UNSPECIFIED: { 160493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne return getMeasure(0, MAX_SIZE); 160548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 160648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case MeasureSpec.EXACTLY: { 160748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return getMeasure(size, size); 160848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 160948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case MeasureSpec.AT_MOST: { 161048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return getMeasure(0, size); 161148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 161248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne default: { 161348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne assert false; 161448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return 0; 161548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 16163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 161748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1618aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1619f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void layout(int size) { 162048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne setParentConstraints(size, size); 162148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne getLocations(); 16223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1624f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void invalidateStructure() { 16254a145d72622772b920f60195e80942058984259cPhilip Milne maxIndex = UNDEFINED; 1626aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 16273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBounds = null; 162848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinks = null; 162948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinks = null; 163048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1631aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMargins = null; 1632aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMargins = null; 1633c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne arcs = null; 163448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1635aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne locations = null; 16363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 16373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateValues(); 16383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1640f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void invalidateValues() { 16413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBoundsValid = false; 164248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinksValid = false; 164348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinksValid = false; 164448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1645aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMarginsValid = false; 1646aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMarginsValid = false; 164748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne arcsValid = false; 164848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 164948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne locationsValid = false; 16503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 16533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 16543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Layout information associated with each of the children of a GridLayout. 16553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 16563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * GridLayout supports both row and column spanning and arbitrary forms of alignment within 16573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * each cell group. The fundamental parameters associated with each cell group are 16583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * gathered into their vertical and horizontal components and stored 165993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * in the {@link #rowSpec} and {@link #columnSpec} layout parameters. 1660b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne * {@link android.widget.GridLayout.Spec Specs} are immutable structures 1661b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne * and may be shared between the layout parameters of different children. 16623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 166393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * The row and column specs contain the leading and trailing indices along each axis 1664aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * and together specify the four grid indices that delimit the cells of this cell group. 16653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 166693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * The alignment properties of the row and column specs together specify 16673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * both aspects of alignment within the cell group. It is also possible to specify a child's 16683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)} 16693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * method. 1670f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1671f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h4>WRAP_CONTENT and MATCH_PARENT</h4> 1672f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1673f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Because the default values of the {@link #width} and {@link #height} 1674f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly 1675f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * declared in the layout parameters of GridLayout's children. In addition, 1676f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from 1677f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is 1678f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * instead controlled by the principle of <em>flexibility</em>, 1679f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * as discussed in {@link GridLayout}. 1680f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1681f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h4>Summary</h4> 1682f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1683f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * You should not need to use either of the special size values: 1684f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of 1685f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * a GridLayout. 16863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 16873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Default values</h4> 16883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 16893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <ul> 16903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #width} = {@link #WRAP_CONTENT}</li> 16913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #height} = {@link #WRAP_CONTENT}</li> 16923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #topMargin} = 0 when 16933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 16947fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 16953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 16963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #leftMargin} = 0 when 16973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 16987fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 16993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 17003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #bottomMargin} = 0 when 17013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 17027fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 17033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 17043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #rightMargin} = 0 when 17053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 17067fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 17073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 1708f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li> 1709f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li> 1710f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li> 1711f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li> 1712f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li> 1713f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #columnSpec}<code>.alignment</code> = {@link #LEFT} </li> 17143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * </ul> 17153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 1716f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * See {@link GridLayout} for a more complete description of the conventions 1717f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * used by GridLayout in the interpretation of the properties of this class. 1718f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 17193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_row 17203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan 17213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_column 17223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan 17233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity 17243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 17253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static class LayoutParams extends MarginLayoutParams { 17263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Default values 17283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_WIDTH = WRAP_CONTENT; 17303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_HEIGHT = WRAP_CONTENT; 17313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_MARGIN = UNDEFINED; 17323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_ROW = UNDEFINED; 17333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_COLUMN = UNDEFINED; 1734f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne private static final Interval DEFAULT_SPAN = new Interval(UNDEFINED, UNDEFINED + 1); 17353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size(); 17363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // TypedArray indices 17383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1739b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin; 1740b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft; 1741b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop; 1742b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int RIGHT_MARGIN = 1743b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne R.styleable.ViewGroup_MarginLayout_layout_marginRight; 17443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int BOTTOM_MARGIN = 1745b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne R.styleable.ViewGroup_MarginLayout_layout_marginBottom; 17463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1747b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column; 1748b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan; 17495d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 1750b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW = R.styleable.GridLayout_Layout_layout_row; 1751b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan; 17525d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 1753b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity; 17543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Instance variables 17563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1758f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * The spec that defines the vertical characteristics of the cell group 17593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * described by these layout parameters. 17603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1761f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public Spec rowSpec = Spec.UNDEFINED; 1762f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 17633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1764f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * The spec that defines the horizontal characteristics of the cell group 17653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * described by these layout parameters. 17663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1767f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public Spec columnSpec = Spec.UNDEFINED; 17683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Constructors 17703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private LayoutParams( 17723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int width, int height, 17733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int left, int top, int right, int bottom, 177493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec rowSpec, Spec columnSpec) { 17753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(width, height); 17763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setMargins(left, top, right, bottom); 177793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne this.rowSpec = rowSpec; 177893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne this.columnSpec = columnSpec; 17793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 17803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 178293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Constructs a new LayoutParams instance for this <code>rowSpec</code> 178393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * and <code>columnSpec</code>. All other fields are initialized with 17843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * default values as defined in {@link LayoutParams}. 17853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 178693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param rowSpec the rowSpec 178793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param columnSpec the columnSpec 17883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 178993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public LayoutParams(Spec rowSpec, Spec columnSpec) { 17903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this(DEFAULT_WIDTH, DEFAULT_HEIGHT, 17913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, 179293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne rowSpec, columnSpec); 17933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 17943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 17963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}. 17973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 17983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams() { 1799f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this(Spec.UNDEFINED, Spec.UNDEFINED); 18003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Copying constructors 18033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 18053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 18063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 18073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(ViewGroup.LayoutParams params) { 18083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(params); 18093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 18123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 18133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 18143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(MarginLayoutParams params) { 18153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(params); 18163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 18193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 18203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 18213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(LayoutParams that) { 18223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(that); 1823f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.rowSpec = that.rowSpec; 1824f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.columnSpec = that.columnSpec; 18253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // AttributeSet constructors 18283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 18303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 18313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 18323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Values not defined in the attribute set take the default values 18333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * defined in {@link LayoutParams}. 18343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 18353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(Context context, AttributeSet attrs) { 18365125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne super(context, attrs); 18375125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne reInitSuper(context, attrs); 18385125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne init(context, attrs); 18393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Implementation 18423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Reinitialise the margins using a different default policy than MarginLayoutParams. 18443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Here we use the value UNDEFINED (as distinct from zero) to represent the undefined state 18453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // so that a layout manager default can be accessed post set up. We need this as, at the 18463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // point of installation, we do not know how many rows/cols there are and therefore 18473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // which elements are positioned next to the container's trailing edges. We need to 18483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // know this as margins around the container's boundary should have different 18493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // defaults to those between peers. 18503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // This method could be parametrized and moved into MarginLayout. 18523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void reInitSuper(Context context, AttributeSet attrs) { 1853b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne TypedArray a = 1854b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout); 18553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne try { 18563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN); 18573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.leftMargin = a.getDimensionPixelSize(LEFT_MARGIN, margin); 18593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.topMargin = a.getDimensionPixelSize(TOP_MARGIN, margin); 18603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.rightMargin = a.getDimensionPixelSize(RIGHT_MARGIN, margin); 18613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.bottomMargin = a.getDimensionPixelSize(BOTTOM_MARGIN, margin); 18623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } finally { 18633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne a.recycle(); 18643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18675125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne private void init(Context context, AttributeSet attrs) { 1868b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout); 18693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne try { 18705125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int gravity = a.getInt(GRAVITY, Gravity.NO_GRAVITY); 18713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18721e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne int column = a.getInt(COLUMN, DEFAULT_COLUMN); 18735125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE); 1874899d5922870c78e0e663bc5661849eb468afc984Philip Milne this.columnSpec = spec(column, colSpan, getAlignment(gravity, true)); 18753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18761e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne int row = a.getInt(ROW, DEFAULT_ROW); 18771e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE); 1878899d5922870c78e0e663bc5661849eb468afc984Philip Milne this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false)); 18793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } finally { 18803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne a.recycle(); 18813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 18857fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}. 18867fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * See {@link android.view.Gravity}. 18873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 18887fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param gravity the new gravity value 18893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 18903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity 18913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 18923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setGravity(int gravity) { 18935125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne rowSpec = rowSpec.copyWriteAlignment(getAlignment(gravity, false)); 18945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne columnSpec = columnSpec.copyWriteAlignment(getAlignment(gravity, true)); 18953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 18963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 18983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected void setBaseAttributes(TypedArray attributes, int widthAttr, int heightAttr) { 18993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.width = attributes.getLayoutDimension(widthAttr, DEFAULT_WIDTH); 19003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT); 19013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1903f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final void setRowSpecSpan(Interval span) { 190493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne rowSpec = rowSpec.copyWriteSpan(span); 19053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1907f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final void setColumnSpecSpan(Interval span) { 190893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne columnSpec = columnSpec.copyWriteSpan(span); 19093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1912aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1913aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs. 1914aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles. 1915aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 1916f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class Arc { 19173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final Interval span; 1918aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public final MutableInt value; 191948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean valid = true; 19203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1921aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public Arc(Interval span, MutableInt value) { 19223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.span = span; 19233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.value = value; 19243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 19273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public String toString() { 192848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return span + " " + (!valid ? "+>" : "->") + " " + value; 19293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // A mutable Integer - used to avoid heap allocation during the layout operation 19333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1934f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class MutableInt { 19353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int value; 19363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1937f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public MutableInt() { 19383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne reset(); 19393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1941f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public MutableInt(int value) { 19423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.value = value; 19433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1945f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void reset() { 19463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne value = Integer.MIN_VALUE; 19473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 194848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 194948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne @Override 195048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public String toString() { 195148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return Integer.toString(value); 195248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 195348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 195448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1955f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class Assoc<K, V> extends ArrayList<Pair<K, V>> { 195648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private final Class<K> keyType; 195748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private final Class<V> valueType; 195848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 195948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private Assoc(Class<K> keyType, Class<V> valueType) { 196048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne this.keyType = keyType; 196148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne this.valueType = valueType; 196248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 196348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1964f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) { 196548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return new Assoc<K, V>(keyType, valueType); 196648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 196748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 196848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public void put(K key, V value) { 196948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne add(Pair.create(key, value)); 197048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 197148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 197248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne @SuppressWarnings(value = "unchecked") 197348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public PackedMap<K, V> pack() { 197448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int N = size(); 197548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne K[] keys = (K[]) Array.newInstance(keyType, N); 197648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne V[] values = (V[]) Array.newInstance(valueType, N); 197748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0; i < N; i++) { 197848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne keys[i] = get(i).first; 197948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne values[i] = get(i).second; 198048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 198148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return new PackedMap<K, V>(keys, values); 198248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 19833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1985aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1986aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This data structure is used in place of a Map where we have an index that refers to the order 1987aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne in which each key/value pairs were added to the map. In this case we store keys and values 1988aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne in arrays of a length that is equal to the number of unique keys. We also maintain an 1989aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne array of indexes from insertion order to the compacted arrays of keys and values. 1990aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1991aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Note that behavior differs from that of a LinkedHashMap in that repeated entries 1992aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne *do* get added multiples times. So the length of index is equals to the number of 1993aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne items added. 1994aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1995aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This is useful in the GridLayout class where we can rely on the order of children not 1996aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne changing during layout - to use integer-based lookup for our internal structures 1997aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne rather than using (and storing) an implementation of Map<Key, ?>. 1998aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 19993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @SuppressWarnings(value = "unchecked") 2000f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class PackedMap<K, V> { 20013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final int[] index; 20023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final K[] keys; 20033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final V[] values; 20043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private PackedMap(K[] keys, V[] values) { 20063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.index = createIndex(keys); 20073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2008aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne this.keys = compact(keys, index); 2009aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne this.values = compact(values, index); 20103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2012f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public V getValue(int i) { 20133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return values[index[i]]; 20143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static <K> int[] createIndex(K[] keys) { 20173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int size = keys.length; 20183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int[] result = new int[size]; 20193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Map<K, Integer> keyToIndex = new HashMap<K, Integer>(); 20213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < size; i++) { 20223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne K key = keys[i]; 20233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Integer index = keyToIndex.get(key); 20243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (index == null) { 20253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne index = keyToIndex.size(); 20263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne keyToIndex.put(key, index); 20273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result[i] = index; 20293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 20313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2033aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 2034aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Create a compact array of keys or values using the supplied index. 2035aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 2036aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private static <K> K[] compact(K[] a, int[] index) { 2037aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int size = a.length; 2038aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Class<?> componentType = a.getClass().getComponentType(); 203951f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1); 20403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // this overwrite duplicates, retaining the last equivalent entry 20423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < size; i++) { 2043aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne result[index[i]] = a[i]; 20443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 20463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2049aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 205093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne For each group (with a given alignment) we need to store the amount of space required 20517fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne before the alignment point and the amount of space required after it. One side of this 2052aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this. 2053aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no 2054aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne simple optimisations are possible. 2055aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2056aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne The general algorithm therefore is to create a Map (actually a PackedMap) from 205793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne group to Bounds and to loop through all Views in the group taking the maximum 2058aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne of the values for each View. 2059aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 2060f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static class Bounds { 20617fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne public int before; 20627fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne public int after; 20635125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public int flexibility; // we're flexible iff all included specs are flexible 20643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private Bounds() { 20663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne reset(); 20673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2069a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void reset() { 20707fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne before = Integer.MIN_VALUE; 20717fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne after = Integer.MIN_VALUE; 20725125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne flexibility = CAN_STRETCH; // from the above, we're flexible when empty 20733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2075a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void include(int before, int after) { 20767fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne this.before = max(this.before, before); 20777fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne this.after = max(this.after, after); 20783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 208048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne protected int size(boolean min) { 20815d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne if (!min) { 20825125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne if (canStretch(flexibility)) { 20835d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne return MAX_SIZE; 20845d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 208548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 20867fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne return before + after; 20873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 208948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne protected int getOffset(View c, Alignment alignment, int size) { 209048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return before - alignment.getAlignmentValue(c, size); 209148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 209248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 20935125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne protected final void include(View c, Spec spec, GridLayout gridLayout, Axis axis) { 20945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne this.flexibility &= spec.getFlexibility(); 209548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal); 20965125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Alignment alignment = gridLayout.getAlignment(spec.alignment, axis.horizontal); 20974c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne // todo test this works correctly when the returned value is UNDEFINED 20985125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int before = alignment.getAlignmentValue(c, size); 209948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(before, size - before); 2100a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2101a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 21023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 21033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public String toString() { 21043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return "Bounds{" + 21057fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne "before=" + before + 21067fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne ", after=" + after + 21073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne '}'; 21083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 21123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * An Interval represents a contiguous range of values that lie between 21133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * the interval's {@link #min} and {@link #max} values. 21143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 21153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Intervals are immutable so may be passed as values and used as keys in hash tables. 21163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * It is not necessary to have multiple instances of Intervals which have the same 21173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link #min} and {@link #max} values. 21183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 21197fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Intervals are often written as {@code [min, max]} and represent the set of values 21207fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code x} such that {@code min <= x < max}. 21213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2122f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class Interval { 21233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 21243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The minimum value. 21253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 21263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final int min; 2127aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 21283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 21293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The maximum value. 21303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 21313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final int max; 21323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 21347fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Construct a new Interval, {@code interval}, where: 21353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <ul> 21367fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <li> {@code interval.min = min} </li> 21377fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <li> {@code interval.max = max} </li> 21383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * </ul> 21393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 21403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @param min the minimum value. 21413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @param max the maximum value. 21423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 21433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public Interval(int min, int max) { 21443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.min = min; 21453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.max = max; 21463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2148f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int size() { 21493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return max - min; 21503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2152f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Interval inverse() { 21533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return new Interval(max, min); 21543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 21577fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Returns {@code true} if the {@link #getClass class}, 21587fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@link #min} and {@link #max} properties of this Interval and the 21597fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * supplied parameter are pairwise equal; {@code false} otherwise. 21603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 21617fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param that the object to compare this interval with 21623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 21633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return {@code true} if the specified object is equal to this 21647fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code Interval}, {@code false} otherwise. 21653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 21663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 21673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean equals(Object that) { 21683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (this == that) { 21693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 21703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (that == null || getClass() != that.getClass()) { 21723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 21733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Interval interval = (Interval) that; 21763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (max != interval.max) { 21783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 21793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21804c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne //noinspection RedundantIfStatement 21813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (min != interval.min) { 21823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 21833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 21863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 21893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int hashCode() { 21903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int result = min; 21913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result = 31 * result + max; 21923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 21933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 21963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public String toString() { 21973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return "[" + min + ", " + max + "]"; 21983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2201899d5922870c78e0e663bc5661849eb468afc984Philip Milne /** 2202899d5922870c78e0e663bc5661849eb468afc984Philip Milne * A Spec defines the horizontal or vertical characteristics of a group of 22034a145d72622772b920f60195e80942058984259cPhilip Milne * cells. Each spec. defines the <em>grid indices</em> and <em>alignment</em> 22044a145d72622772b920f60195e80942058984259cPhilip Milne * along the appropriate axis. 2205899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p> 2206899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The <em>grid indices</em> are the leading and trailing edges of this cell group. 2207899d5922870c78e0e663bc5661849eb468afc984Philip Milne * See {@link GridLayout} for a description of the conventions used by GridLayout 2208899d5922870c78e0e663bc5661849eb468afc984Philip Milne * for grid indices. 2209899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p> 2210899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The <em>alignment</em> property specifies how cells should be aligned in this group. 2211899d5922870c78e0e663bc5661849eb468afc984Philip Milne * For row groups, this specifies the vertical alignment. 2212899d5922870c78e0e663bc5661849eb468afc984Philip Milne * For column groups, this specifies the horizontal alignment. 22134a145d72622772b920f60195e80942058984259cPhilip Milne * <p> 22144a145d72622772b920f60195e80942058984259cPhilip Milne * Use the following static methods to create specs: 22154a145d72622772b920f60195e80942058984259cPhilip Milne * <ul> 22164a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int)}</li> 22174a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int, int)}</li> 22184a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int, Alignment)}</li> 22194a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int, int, Alignment)}</li> 22204a145d72622772b920f60195e80942058984259cPhilip Milne * </ul> 22214a145d72622772b920f60195e80942058984259cPhilip Milne * 2222899d5922870c78e0e663bc5661849eb468afc984Philip Milne */ 222393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public static class Spec { 2224f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final Spec UNDEFINED = spec(GridLayout.UNDEFINED); 2225f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 2226f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean startDefined; 222748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne final Interval span; 222893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne final Alignment alignment; 22293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2230f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private Spec(boolean startDefined, Interval span, Alignment alignment) { 2231f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.startDefined = startDefined; 22325d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne this.span = span; 22335d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne this.alignment = alignment; 22345d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 22355d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 2236f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private Spec(boolean startDefined, int start, int size, Alignment alignment) { 2237f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this(startDefined, new Interval(start, start + size), alignment); 22383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2240f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec copyWriteSpan(Interval span) { 2241f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return new Spec(startDefined, span, alignment); 22423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2244f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec copyWriteAlignment(Alignment alignment) { 2245f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return new Spec(startDefined, span, alignment); 22465125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 22475125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 2248f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final int getFlexibility() { 22494c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH; 22503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 225393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Returns {@code true} if the {@code class}, {@code alignment} and {@code span} 225493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * properties of this Spec and the supplied parameter are pairwise equal, 22557fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false} otherwise. 22563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 225793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param that the object to compare this spec with 22583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 22593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return {@code true} if the specified object is equal to this 226093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@code Spec}; {@code false} otherwise 22613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 22623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 22633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean equals(Object that) { 22643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (this == that) { 22653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 22663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (that == null || getClass() != that.getClass()) { 22683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 22693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 227193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = (Spec) that; 22723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 227393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne if (!alignment.equals(spec.alignment)) { 22743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 22753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22764c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne //noinspection RedundantIfStatement 227793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne if (!span.equals(spec.span)) { 22783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 22793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 22823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 22853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int hashCode() { 22863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int result = span.hashCode(); 22873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result = 31 * result + alignment.hashCode(); 22883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 22893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 229393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Return a Spec, {@code spec}, where: 229493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <ul> 229593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.span = [start, start + size]} </li> 229693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.alignment = alignment} </li> 229793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * </ul> 229893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * 229993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param start the start 230093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param size the size 230193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param alignment the alignment 230293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne */ 230393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public static Spec spec(int start, int size, Alignment alignment) { 2304f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return new Spec(start != UNDEFINED, start, size, alignment); 230593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne } 230693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne 230793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne /** 230893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Return a Spec, {@code spec}, where: 230993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <ul> 231093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.span = [start, start + 1]} </li> 231193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.alignment = alignment} </li> 231293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * </ul> 231393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * 231493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param start the start index 231593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param alignment the alignment 231693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne */ 231793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public static Spec spec(int start, Alignment alignment) { 231893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne return spec(start, 1, alignment); 231993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne } 232093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne 232193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne /** 23225125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * Return a Spec, {@code spec}, where: 23235125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <ul> 23245125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <li> {@code spec.span = [start, start + size]} </li> 23255125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * </ul> 23265125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * 23275125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * @param start the start 23285125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * @param size the size 23295125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne */ 23305125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public static Spec spec(int start, int size) { 23315125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return spec(start, size, UNDEFINED_ALIGNMENT); 23325125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 23335125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 23345125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne /** 23355125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * Return a Spec, {@code spec}, where: 23365125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <ul> 23375125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <li> {@code spec.span = [start, start + 1]} </li> 23385125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * </ul> 23395125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * 23405125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * @param start the start index 23415125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne */ 23425125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public static Spec spec(int start) { 23435125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return spec(start, 1); 23445125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 23455125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 23465125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne /** 23473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Alignments specify where a view should be placed within a cell group and 23483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * what size it should be. 23493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 235093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec} 235193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an 235293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@code alignment}. Overall placement of the view in the cell 23533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * group is specified by the two alignments which act along each axis independently. 23543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 2355a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne * The GridLayout class defines the most common alignments used in general layout: 2356a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #CENTER}, {@link 2357a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne * #BASELINE} and {@link #FILL}. 2358a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne */ 2359a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne /* 2360c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)}, 23613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to return the appropriate value for the type of alignment being defined. 23623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The enclosing algorithms position the children 23631e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * so that the locations defined by the alignment values 23643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * are the same for all of the views in a group. 23653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 23663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2367c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public static abstract class Alignment { 236848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Alignment() { 2369a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2370a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 23713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 23723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns an alignment value. In the case of vertical alignments the value 23733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * returned should indicate the distance from the top of the view to the 23743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * alignment location. 23753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * For horizontal alignments measurement is made from the left edge of the component. 23763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 2377c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param view the view to which this alignment should be applied 2378c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param viewSize the measured size of the view 2379b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne * @return the alignment value 23803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 238148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne abstract int getAlignmentValue(View view, int viewSize); 23823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 23843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the size of the view specified by this alignment. 23853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * In the case of vertical alignments this method should return a height; for 23863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * horizontal alignments this method should return the width. 2387c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * <p> 2388c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * The default implementation returns {@code viewSize}. 2389c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * 2390c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param view the view to which this alignment should be applied 2391c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param viewSize the measured size of the view 2392c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param cellSize the size of the cell into which this view will be placed 239309e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne * @param measurementType This parameter is currently unused as GridLayout only supports 239409e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne * one type of measurement: {@link View#measure(int, int)}. 23953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 2396b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne * @return the aligned size 23973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 239848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) { 23993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return viewSize; 24003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2401a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 240248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Bounds getBounds() { 2403a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne return new Bounds(); 2404a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 24053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2407f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final Alignment UNDEFINED_ALIGNMENT = new Alignment() { 24085125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public int getAlignmentValue(View view, int viewSize) { 24095125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return UNDEFINED; 24105125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 24115125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne }; 24125125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 2413c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne private static final Alignment LEADING = new Alignment() { 241448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public int getAlignmentValue(View view, int viewSize) { 24153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return 0; 24163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 24183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2419c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne private static final Alignment TRAILING = new Alignment() { 242048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public int getAlignmentValue(View view, int viewSize) { 24213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return viewSize; 24223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 24243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>top</em> 24273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 24283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 24293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment TOP = LEADING; 24303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>bottom</em> 24333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 24343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 24353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment BOTTOM = TRAILING; 24363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>right</em> 24393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 24403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 24413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment RIGHT = TRAILING; 24423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>left</em> 24453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 24463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 24473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment LEFT = LEADING; 24483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be <em>centered</em> with the other views in its cell group. 245193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link 245293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * LayoutParams#columnSpec columnSpecs}. 24533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2454c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public static final Alignment CENTER = new Alignment() { 245548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public int getAlignmentValue(View view, int viewSize) { 24563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return viewSize >> 1; 24573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 24593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 24613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>baselines</em> 24623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * of the other views in its cell group. 246393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}. 24643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 24653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see View#getBaseline() 24663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2467c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public static final Alignment BASELINE = new Alignment() { 246848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public int getAlignmentValue(View view, int viewSize) { 24693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (view == null) { 24703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return UNDEFINED; 24713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int baseline = view.getBaseline(); 2473a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne return (baseline == -1) ? UNDEFINED : baseline; 2474a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2475a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2476a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 2477a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne public Bounds getBounds() { 2478a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne return new Bounds() { 2479a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne /* 2480a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne In a baseline aligned row in which some components define a baseline 2481a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne and some don't, we need a third variable to properly account for all 2482a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne the sizes. This tracks the maximum size of all the components - 2483a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne including those that don't define a baseline. 2484a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne */ 2485a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne private int size; 2486a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2487a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 2488a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void reset() { 2489a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne super.reset(); 249048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne size = Integer.MIN_VALUE; 2491a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2492a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2493a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 2494a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void include(int before, int after) { 2495a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne super.include(before, after); 2496a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne size = max(size, before + after); 2497a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2498a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2499a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 250048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne protected int size(boolean min) { 250148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return max(super.size(min), size); 2502a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2503a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2504a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 250548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne protected int getOffset(View c, Alignment alignment, int size) { 250648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return max(0, super.getOffset(c, alignment, size)); 2507a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2508a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne }; 25093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 25113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 25123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 25133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should expanded to fit the boundaries of its cell group. 251493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and 251593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@link LayoutParams#columnSpec columnSpecs}. 25163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 25173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment FILL = new Alignment() { 251848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public int getAlignmentValue(View view, int viewSize) { 25193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return UNDEFINED; 25203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2522c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne @Override 2523c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) { 25243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return cellSize; 25253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 252748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 2528f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static boolean canStretch(int flexibility) { 25295d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne return (flexibility & CAN_STRETCH) != 0; 25305d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 25315d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 25325125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne private static final int INFLEXIBLE = 0; 253348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 25344c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne private static final int CAN_STRETCH = 2; 2535452eec33d667f9e705b57e60948b070536fbc1b4Jim Miller} 2536