GridLayout.java revision d6479ec5eec13914f656f6be996d95fe1610fd57
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; 231557fd7809078e421f751efc7d2539b3efdc54b2Philip Milneimport android.graphics.Insets; 243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.graphics.Paint; 253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.AttributeSet; 263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.util.Log; 27211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milneimport android.util.LogPrinter; 2848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milneimport android.util.Pair; 29211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milneimport android.util.Printer; 303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.Gravity; 313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.View; 323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport android.view.ViewGroup; 338a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 348a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 35edd69518ffec87fb7b1931e708678ef441152cdePhilip Milneimport android.widget.RemoteViews.RemoteView; 3610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milneimport com.android.internal.R; 373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.lang.reflect.Array; 393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.ArrayList; 403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Arrays; 413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.HashMap; 423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.List; 433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport java.util.Map; 443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 455125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milneimport static android.view.Gravity.*; 46899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.EXACTLY; 47899d5922870c78e0e663bc5661849eb468afc984Philip Milneimport static android.view.View.MeasureSpec.makeMeasureSpec; 483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.max; 493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milneimport static java.lang.Math.min; 503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne/** 523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * A layout that places its children in a rectangular <em>grid</em>. 533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The grid is composed of a set of infinitely thin lines that separate the 553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * viewing area into <em>cells</em>. Throughout the API, grid lines are referenced 567fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * by grid <em>indices</em>. A grid with {@code N} columns 577fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * has {@code N + 1} grid indices that run from {@code 0} 587fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * through {@code N} inclusive. Regardless of how GridLayout is 597fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * configured, grid index {@code 0} is fixed to the leading edge of the 607fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * container and grid index {@code N} is fixed to its trailing edge 613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * (after padding is taken into account). 623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 6393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <h4>Row and Column Specs</h4> 643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Children occupy one or more contiguous cells, as defined 6693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and 6793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters. 6893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Each spec defines the set of rows or columns that are to be 693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * occupied; and how children should be aligned within the resulting group of cells. 703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Although cells do not normally overlap in a GridLayout, GridLayout does 713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * not prevent children being defined to occupy the same cell or group of cells. 723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * In this case however, there is no guarantee that children will not themselves 733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * overlap after the layout operation completes. 743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Default Cell Assignment</h4> 763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 7748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne * If a child does not specify the row and column indices of the cell it 783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * wishes to occupy, GridLayout assigns cell locations automatically using its: 793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setOrientation(int) orientation}, 803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setRowCount(int) rowCount} and 813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setColumnCount(int) columnCount} properties. 823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Space</h4> 843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Space between children may be specified either by using instances of the 863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * dedicated {@link Space} view or by setting the 873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#leftMargin leftMargin}, 893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#topMargin topMargin}, 903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#rightMargin rightMargin} and 913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link ViewGroup.MarginLayoutParams#bottomMargin bottomMargin} 923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters. When the 943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} 953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * property is set, default margins around children are automatically 96f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * allocated based on the prevailing UI style guide for the platform. 97f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Each of the margins so defined may be independently overridden by an assignment 983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to the appropriate layout parameter. 99f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Default values will generally produce a reasonable spacing between components 100f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * but values may change between different releases of the platform. 1013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 1023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Excess Space Distribution</h4> 1033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 104f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's distribution of excess space is based on <em>priority</em> 105f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * rather than <em>weight</em>. 106f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p> 107899d5922870c78e0e663bc5661849eb468afc984Philip Milne * A child's ability to stretch is inferred from the alignment properties of 108899d5922870c78e0e663bc5661849eb468afc984Philip Milne * its row and column groups (which are typically set by setting the 109899d5922870c78e0e663bc5661849eb468afc984Philip Milne * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters). 110899d5922870c78e0e663bc5661849eb468afc984Philip Milne * If alignment was defined along a given axis then the component 111f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * is taken as <em>flexible</em> in that direction. If no alignment was set, 112f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * the component is instead assumed to be <em>inflexible</em>. 113f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p> 114f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Multiple components in the same row or column group are 115f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * considered to act in <em>parallel</em>. Such a 116899d5922870c78e0e663bc5661849eb468afc984Philip Milne * group is flexible only if <em>all</em> of the components 117899d5922870c78e0e663bc5661849eb468afc984Philip Milne * within it are flexible. Row and column groups that sit either side of a common boundary 118899d5922870c78e0e663bc5661849eb468afc984Philip Milne * are instead considered to act in <em>series</em>. The composite group made of these two 119899d5922870c78e0e663bc5661849eb468afc984Philip Milne * elements is flexible if <em>one</em> of its elements is flexible. 120899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p> 121899d5922870c78e0e663bc5661849eb468afc984Philip Milne * To make a column stretch, make sure all of the components inside it define a 122899d5922870c78e0e663bc5661849eb468afc984Philip Milne * gravity. To prevent a column from stretching, ensure that one of the components 123899d5922870c78e0e663bc5661849eb468afc984Philip Milne * in the column does not define a gravity. 1243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 125f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When the principle of flexibility does not provide complete disambiguation, 126f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em> 127f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * and <em>bottom</em> edges. 128f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 129a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * <h4>Interpretation of GONE</h4> 130a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * 131a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * For layout purposes, GridLayout treats views whose visibility status is 132a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * {@link View#GONE GONE}, as having zero width and height. This is subtly different from 133a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * the policy of ignoring views that are marked as GONE outright. If, for example, a gone-marked 134a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * view was alone in a column, that column would itself collapse to zero width if and only if 135a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * no gravity was defined on the view. If gravity was defined, then the gone-marked 136a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * view has no effect on the layout and the container should be laid out as if the view 137a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * had never been added to it. 138a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * These statements apply equally to rows as well as columns, and to groups of rows or columns. 139a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne * 140f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h5>Limitations</h5> 141f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 142f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout does not provide support for the principle of <em>weight</em>, as defined in 143f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible 1446216e87fe8ad3273855233965b34049d22763e94Philip Milne * to configure a GridLayout to distribute excess space between multiple components. 145f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <p> 146f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Some common use-cases may nevertheless be accommodated as follows. 147f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * To place equal amounts of space around a component in a cell group; 148f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * use {@link #CENTER} alignment (or {@link LayoutParams#setGravity(int) gravity}). 149f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * For complete control over excess space distribution in a row or column; 150f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * use a {@link LinearLayout} subview to hold the components in the associated cell group. 151f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * When using either of these techniques, bear in mind that cell groups may be defined to overlap. 1523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 1533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * See {@link GridLayout.LayoutParams} for a full description of the 1543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * layout parameters used by GridLayout. 1553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 1563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation 1573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount 1583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount 1593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins 1603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved 1613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved 1623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 163edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne@RemoteView 1643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milnepublic class GridLayout extends ViewGroup { 1653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Public constants 1673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The horizontal orientation. 1703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final int HORIZONTAL = LinearLayout.HORIZONTAL; 172aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The vertical orientation. 1753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final int VERTICAL = LinearLayout.VERTICAL; 1773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 178aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 179aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * The constant used to indicate that a value is undefined. 180aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * Fields can use this value to indicate that their values 181aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * have not yet been set. Similarly, methods can return this value 182aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * to indicate that there is no suitable value that the implementation 183aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * can return. 184aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * The value used for the constant (currently {@link Integer#MIN_VALUE}) is 185aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * intended to avoid confusion between valid values whose sign may not be known. 186aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 187aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public static final int UNDEFINED = Integer.MIN_VALUE; 188aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1891e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne /** 1901e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * This constant is an {@link #setAlignmentMode(int) alignmentMode}. 1911e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * When the {@code alignmentMode} is set to {@link #ALIGN_BOUNDS}, alignment 1921e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * is made between the edges of each component's raw 1931e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * view boundary: i.e. the area delimited by the component's: 1941e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getTop() top}, 1951e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getLeft() left}, 1961e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getBottom() bottom} and 1971e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link android.view.View#getRight() right} properties. 1981e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * <p> 1991e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * For example, when {@code GridLayout} is in {@link #ALIGN_BOUNDS} mode, 2001e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * children that belong to a row group that uses {@link #TOP} alignment will 2011e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * all return the same value when their {@link android.view.View#getTop()} 2021e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * method is called. 2031e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 2041e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 2051e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne */ 2061e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public static final int ALIGN_BOUNDS = 0; 2071e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne 2081e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne /** 2091e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * This constant is an {@link #setAlignmentMode(int) alignmentMode}. 2101e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * When the {@code alignmentMode} is set to {@link #ALIGN_MARGINS}, 2111e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * the bounds of each view are extended outwards, according 2121e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * to their margins, before the edges of the resulting rectangle are aligned. 2131e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * <p> 2141e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * For example, when {@code GridLayout} is in {@link #ALIGN_MARGINS} mode, 2151e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * the quantity {@code top - layoutParams.topMargin} is the same for all children that 2161e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * belong to a row group that uses {@link #TOP} alignment. 2171e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 2181e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 2191e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne */ 2201e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public static final int ALIGN_MARGINS = 1; 2211e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne 2223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Misc constants 2233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 224f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final int MAX_SIZE = 100000; 225f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final int DEFAULT_CONTAINER_MARGIN = 0; 226d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne static final int UNINITIALIZED_HASH = 0; 227a2353621524472f71850a54b5a41188dd8281039Philip Milne static final Printer LOG_PRINTER = new LogPrinter(Log.DEBUG, GridLayout.class.getName()); 228a2353621524472f71850a54b5a41188dd8281039Philip Milne static final Printer NO_PRINTER = new Printer() { 229a2353621524472f71850a54b5a41188dd8281039Philip Milne @Override 230a2353621524472f71850a54b5a41188dd8281039Philip Milne public void println(String x) { 231a2353621524472f71850a54b5a41188dd8281039Philip Milne } 232a2353621524472f71850a54b5a41188dd8281039Philip Milne }; 2333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Defaults 2353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_ORIENTATION = HORIZONTAL; 2373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_COUNT = UNDEFINED; 2383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false; 239899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static final boolean DEFAULT_ORDER_PRESERVED = true; 2401e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS; 2413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // TypedArray indices 2433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 244b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ORIENTATION = R.styleable.GridLayout_orientation; 245b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW_COUNT = R.styleable.GridLayout_rowCount; 246b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount; 247b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins; 248b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode; 249b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved; 250b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved; 2513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Instance variables 2533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 254465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell final Axis mHorizontalAxis = new Axis(true); 255465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell final Axis mVerticalAxis = new Axis(false); 256465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int mOrientation = DEFAULT_ORIENTATION; 257465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS; 258465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int mAlignmentMode = DEFAULT_ALIGNMENT_MODE; 259465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int mDefaultGap; 260465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int mLastLayoutParamsHashCode = UNINITIALIZED_HASH; 261465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Printer mPrinter = LOG_PRINTER; 262aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Constructors 2643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 265d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette public GridLayout(Context context) { 266d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette this(context, null); 267d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette } 268d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette 269d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette public GridLayout(Context context, AttributeSet attrs) { 270d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette this(context, attrs, 0); 271d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette } 272d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette 273617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public GridLayout(Context context, AttributeSet attrs, int defStyleAttr) { 274617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette this(context, attrs, defStyleAttr, 0); 275617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette } 276617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette 277617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public GridLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 278617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 279465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap); 280617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette final TypedArray a = context.obtainStyledAttributes( 281617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette attrs, R.styleable.GridLayout, defStyleAttr, defStyleRes); 2823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne try { 2831e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT)); 2841e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT)); 2855125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne setOrientation(a.getInt(ORIENTATION, DEFAULT_ORIENTATION)); 2865125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne setUseDefaultMargins(a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS)); 2875125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne setAlignmentMode(a.getInt(ALIGNMENT_MODE, DEFAULT_ALIGNMENT_MODE)); 2883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); 2893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED)); 2903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } finally { 2913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne a.recycle(); 2923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Implementation 2963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 2983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the current orientation. 2993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3007fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return either {@link #HORIZONTAL} or {@link #VERTICAL} 3013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setOrientation(int) 3033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation 3053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int getOrientation() { 307465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mOrientation; 3083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 311b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * 312b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * GridLayout uses the orientation property for two purposes: 313b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <ul> 314b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <li> 315b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * To control the 'direction' in which default row/column indices are generated 316b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * when they are not specified in a component's layout parameters. 317b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * </li> 318b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <li> 319b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * To control which axis should be processed first during the layout operation: 320b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * when orientation is {@link #HORIZONTAL} the horizontal axis is laid out first. 321b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * </li> 322b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * </ul> 323b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * 324b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * The order in which axes are laid out is important if, for example, the height of 325b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * one of GridLayout's children is dependent on its width - and its width is, in turn, 326b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * dependent on the widths of other components. 327b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <p> 328b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * If your layout contains a {@link TextView} (or derivative: 329b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * {@code Button}, {@code EditText}, {@code CheckBox}, etc.) which is 330b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * in multi-line mode (the default) it is normally best to leave GridLayout's 331b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * orientation as {@code HORIZONTAL} - because {@code TextView} is capable of 332b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * deriving its height for a given width, but not the other way around. 333b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * <p> 334b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * Other than the effects above, orientation does not affect the actual layout operation of 335b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * GridLayout, so it's fine to leave GridLayout in {@code HORIZONTAL} mode even if 336b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne * the height of the intended layout greatly exceeds its width. 3377fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 3387fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * The default value of this property is {@link #HORIZONTAL}. 3393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3407fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param orientation either {@link #HORIZONTAL} or {@link #VERTICAL} 3413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getOrientation() 3433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_orientation 3453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setOrientation(int orientation) { 347465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (this.mOrientation != orientation) { 348465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell this.mOrientation = orientation; 349f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne invalidateStructure(); 3503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne requestLayout(); 3513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 3553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the current number of rows. This is either the last value that was set 3563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * with {@link #setRowCount(int)} or, if no such value was set, the maximum 35793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * value of each the upper bounds defined in {@link LayoutParams#rowSpec}. 3583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return the current number of rows 3603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setRowCount(int) 36293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#rowSpec 3633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount 3653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int getRowCount() { 367465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mVerticalAxis.getCount(); 3683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 371f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * RowCount is used only to generate default row/column indices when 372f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * they are not specified by a component's layout parameters. 3733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3747fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param rowCount the number of rows 3753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getRowCount() 37793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#rowSpec 3783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowCount 3803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setRowCount(int rowCount) { 382465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.setCount(rowCount); 383f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne invalidateStructure(); 384f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne requestLayout(); 3853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 3863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 3873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 3883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the current number of columns. This is either the last value that was set 3893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * with {@link #setColumnCount(int)} or, if no such value was set, the maximum 39093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * value of each the upper bounds defined in {@link LayoutParams#columnSpec}. 3913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return the current number of columns 3933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setColumnCount(int) 39593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#columnSpec 3963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 3973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount 3983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 3993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int getColumnCount() { 400465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mHorizontalAxis.getCount(); 4013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 4023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 4033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 404f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * ColumnCount is used only to generate default column/column indices when 405f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * they are not specified by a component's layout parameters. 4063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @param columnCount the number of columns. 4083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getColumnCount() 41093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @see LayoutParams#columnSpec 4113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnCount 4133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setColumnCount(int columnCount) { 415465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.setCount(columnCount); 416f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne invalidateStructure(); 417f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne requestLayout(); 4183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 4193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 4203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 4213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns whether or not this GridLayout will allocate default margins when no 4223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * corresponding layout parameters are defined. 4233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4247fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return {@code true} if default margins should be allocated 4253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setUseDefaultMargins(boolean) 4273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins 4293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean getUseDefaultMargins() { 431465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mUseDefaultMargins; 4323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 4333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 4343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 4357fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When {@code true}, GridLayout allocates default margins around children 4363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * based on the child's visual characteristics. Each of the 4373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * margins so defined may be independently overridden by an assignment 4383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to the appropriate layout parameter. 4393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 4407fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When {@code false}, the default value of all margins is zero. 441aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * <p> 4427fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When setting to {@code true}, consider setting the value of the 4431e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * {@link #setAlignmentMode(int) alignmentMode} 4441e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * property to {@link #ALIGN_BOUNDS}. 4457fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 4467fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * The default value of this property is {@code false}. 4473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4487fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins 4493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #getUseDefaultMargins() 4511e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 4523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#leftMargin 4543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#topMargin 4553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#rightMargin 4563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see MarginLayoutParams#bottomMargin 4573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 4583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_useDefaultMargins 4593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 4603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setUseDefaultMargins(boolean useDefaultMargins) { 461465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell this.mUseDefaultMargins = useDefaultMargins; 462aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 463aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 464aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 465aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 4661e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * Returns the alignment mode. 4671e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 4681e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @return the alignment mode; either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS} 469aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4701e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_BOUNDS 4711e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_MARGINS 472aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4731e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #setAlignmentMode(int) 474aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4751e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @attr ref android.R.styleable#GridLayout_alignmentMode 476aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 4771e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public int getAlignmentMode() { 478465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mAlignmentMode; 479aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 480aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 481aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 4821e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * Sets the alignment mode to be used for all of the alignments between the 4831e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * children of this container. 4847fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 4851e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * The default value of this property is {@link #ALIGN_MARGINS}. 4861e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * 4871e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @param alignmentMode either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS} 488aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4891e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_BOUNDS 4901e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #ALIGN_MARGINS 491aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4921e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @see #getAlignmentMode() 493aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * 4941e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * @attr ref android.R.styleable#GridLayout_alignmentMode 495aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 4961e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne public void setAlignmentMode(int alignmentMode) { 497465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell this.mAlignmentMode = alignmentMode; 498aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 4993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns whether or not row boundaries are ordered by their grid indices. 5033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5047fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return {@code true} if row boundaries must appear in the order of their indices, 5057fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false} otherwise 5063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setRowOrderPreserved(boolean) 5083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved 5103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean isRowOrderPreserved() { 512465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mVerticalAxis.isOrderPreserved(); 5133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5167fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When this property is {@code true}, GridLayout is forced to place the row boundaries 517aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * so that their associated grid indices are in ascending order in the view. 5183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 519899d5922870c78e0e663bc5661849eb468afc984Philip Milne * When this property is {@code false} GridLayout is at liberty to place the vertical row 520899d5922870c78e0e663bc5661849eb468afc984Philip Milne * boundaries in whatever order best fits the given constraints. 5217fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 522899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The default value of this property is {@code true}. 5237fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 5247fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param rowOrderPreserved {@code true} to force GridLayout to respect the order 5257fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * of row boundaries 5263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #isRowOrderPreserved() 5283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_rowOrderPreserved 5303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setRowOrderPreserved(boolean rowOrderPreserved) { 532465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.setOrderPreserved(rowOrderPreserved); 533aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne invalidateStructure(); 534aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 5353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns whether or not column boundaries are ordered by their grid indices. 5393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5407fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @return {@code true} if column boundaries must appear in the order of their indices, 5417fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false} otherwise 5423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #setColumnOrderPreserved(boolean) 5443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved 5463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean isColumnOrderPreserved() { 548465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mHorizontalAxis.isOrderPreserved(); 5493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 5513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 5527fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * When this property is {@code true}, GridLayout is forced to place the column boundaries 553aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * so that their associated grid indices are in ascending order in the view. 5543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 555899d5922870c78e0e663bc5661849eb468afc984Philip Milne * When this property is {@code false} GridLayout is at liberty to place the horizontal column 556899d5922870c78e0e663bc5661849eb468afc984Philip Milne * boundaries in whatever order best fits the given constraints. 5577fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <p> 558899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The default value of this property is {@code true}. 5593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5607fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param columnOrderPreserved use {@code true} to force GridLayout to respect the order 5613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * of column boundaries. 5623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see #isColumnOrderPreserved() 5643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 5653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_columnOrderPreserved 5663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 5673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setColumnOrderPreserved(boolean columnOrderPreserved) { 568465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.setOrderPreserved(columnOrderPreserved); 569aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne invalidateStructure(); 570aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne requestLayout(); 5713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 5723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 573211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne /** 574211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * Return the printer that will log diagnostics from this layout. 575211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * 576211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * @see #setPrinter(android.util.Printer) 577211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * 578211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * @return the printer associated with this view 579465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell * 580465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell * @hide 581211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne */ 582211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne public Printer getPrinter() { 583465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mPrinter; 584211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne } 585211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne 586211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne /** 587211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * Set the printer that will log diagnostics from this layout. 588211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * The default value is created by {@link android.util.LogPrinter}. 589211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * 590211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * @param printer the printer associated with this layout 591211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * 592211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne * @see #getPrinter() 593465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell * 594465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell * @hide 595211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne */ 596211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne public void setPrinter(Printer printer) { 597465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell this.mPrinter = (printer == null) ? NO_PRINTER : printer; 598211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne } 599211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne 6005125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne // Static utility methods 6015125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 602f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static int max2(int[] a, int valueIfEmpty) { 60351f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne int result = valueIfEmpty; 60451f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne for (int i = 0, N = a.length; i < N; i++) { 60551f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne result = Math.max(result, a[i]); 60651f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne } 60751f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne return result; 60851f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne } 60951f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne 610899d5922870c78e0e663bc5661849eb468afc984Philip Milne @SuppressWarnings("unchecked") 611f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static <T> T[] append(T[] a, T[] b) { 61248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length); 61348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne System.arraycopy(a, 0, result, 0, a.length); 61448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne System.arraycopy(b, 0, result, a.length, b.length); 6153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 6163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 618f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static Alignment getAlignment(int gravity, boolean horizontal) { 6195125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK; 6205125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT; 6215125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int flags = (gravity & mask) >> shift; 6225125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne switch (flags) { 6235125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case (AXIS_SPECIFIED | AXIS_PULL_BEFORE): 6241557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne return horizontal ? LEFT : TOP; 6255125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case (AXIS_SPECIFIED | AXIS_PULL_AFTER): 6261557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne return horizontal ? RIGHT : BOTTOM; 6275125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER): 6285125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return FILL; 6295125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne case AXIS_SPECIFIED: 6305125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return CENTER; 63147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | RELATIVE_LAYOUT_DIRECTION): 63247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio return START; 63347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio case (AXIS_SPECIFIED | AXIS_PULL_AFTER | RELATIVE_LAYOUT_DIRECTION): 63447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio return END; 6355125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne default: 6365125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return UNDEFINED_ALIGNMENT; 6375125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 6385125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 6395125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 6404c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne /** @noinspection UnusedParameters*/ 6411fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getDefaultMargin(View c, boolean horizontal, boolean leading) { 642899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (c.getClass() == Space.class) { 643899d5922870c78e0e663bc5661849eb468afc984Philip Milne return 0; 644899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 645465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell return mDefaultGap / 2; 6463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 6481fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) { 6497b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne return /*isAtEdge ? DEFAULT_CONTAINER_MARGIN :*/ getDefaultMargin(c, horizontal, leading); 6503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 6527a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) { 653465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (!mUseDefaultMargins) { 6543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return 0; 6553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 65693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? p.columnSpec : p.rowSpec; 657465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 65893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval span = spec.span; 65947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio boolean leading1 = (horizontal && isLayoutRtl()) ? !leading : leading; 66047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount()); 6613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 6621fd16378812792913a6aa6923acbec20037e09ffPhilip Milne return getDefaultMargin(c, isAtEdge, horizontal, leading); 6633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 665f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int getMargin1(View view, boolean horizontal, boolean leading) { 6663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne LayoutParams lp = getLayoutParams(view); 6673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int margin = horizontal ? 668aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne (leading ? lp.leftMargin : lp.rightMargin) : 669aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne (leading ? lp.topMargin : lp.bottomMargin); 6707a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne return margin == UNDEFINED ? getDefaultMargin(view, lp, horizontal, leading) : margin; 6711fd16378812792913a6aa6923acbec20037e09ffPhilip Milne } 6721fd16378812792913a6aa6923acbec20037e09ffPhilip Milne 6734c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne private int getMargin(View view, boolean horizontal, boolean leading) { 674465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (mAlignmentMode == ALIGN_MARGINS) { 6754c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return getMargin1(view, horizontal, leading); 6764c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne } else { 677465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 6784c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins(); 6794c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne LayoutParams lp = getLayoutParams(view); 6804c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 6814c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int index = leading ? spec.span.min : spec.span.max; 6824c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return margins[index]; 6834c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne } 6844c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne } 6854c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne 6861fd16378812792913a6aa6923acbec20037e09ffPhilip Milne private int getTotalMargin(View child, boolean horizontal) { 6871fd16378812792913a6aa6923acbec20037e09ffPhilip Milne return getMargin(child, horizontal, true) + getMargin(child, horizontal, false); 6883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 6893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 690899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static boolean fits(int[] a, int value, int start, int end) { 691899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (end > a.length) { 692899d5922870c78e0e663bc5661849eb468afc984Philip Milne return false; 693899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 694899d5922870c78e0e663bc5661849eb468afc984Philip Milne for (int i = start; i < end; i++) { 695899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (a[i] > value) { 696899d5922870c78e0e663bc5661849eb468afc984Philip Milne return false; 6973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 698899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 699899d5922870c78e0e663bc5661849eb468afc984Philip Milne return true; 700899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 7013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 702899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static void procrusteanFill(int[] a, int start, int end, int value) { 703899d5922870c78e0e663bc5661849eb468afc984Philip Milne int length = a.length; 704899d5922870c78e0e663bc5661849eb468afc984Philip Milne Arrays.fill(a, Math.min(start, length), Math.min(end, length), value); 705899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 7063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 707899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static void setCellGroup(LayoutParams lp, int row, int rowSpan, int col, int colSpan) { 708899d5922870c78e0e663bc5661849eb468afc984Philip Milne lp.setRowSpecSpan(new Interval(row, row + rowSpan)); 709899d5922870c78e0e663bc5661849eb468afc984Philip Milne lp.setColumnSpecSpan(new Interval(col, col + colSpan)); 710899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 7113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 712899d5922870c78e0e663bc5661849eb468afc984Philip Milne // Logic to avert infinite loops by ensuring that the cells can be placed somewhere. 713899d5922870c78e0e663bc5661849eb468afc984Philip Milne private static int clip(Interval minorRange, boolean minorWasDefined, int count) { 714899d5922870c78e0e663bc5661849eb468afc984Philip Milne int size = minorRange.size(); 715899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (count == 0) { 716899d5922870c78e0e663bc5661849eb468afc984Philip Milne return size; 717899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 718899d5922870c78e0e663bc5661849eb468afc984Philip Milne int min = minorWasDefined ? min(minorRange.min, count) : 0; 719899d5922870c78e0e663bc5661849eb468afc984Philip Milne return min(size, count - min); 720899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 721f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne 722899d5922870c78e0e663bc5661849eb468afc984Philip Milne // install default indices for cells that don't define them 723899d5922870c78e0e663bc5661849eb468afc984Philip Milne private void validateLayoutParams() { 724465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell final boolean horizontal = (mOrientation == HORIZONTAL); 725465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell final Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 726782c04b864dc5f71f7ec0c8e36cbaf5b838dc69cJim Miller final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0; 727f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne 728899d5922870c78e0e663bc5661849eb468afc984Philip Milne int major = 0; 729899d5922870c78e0e663bc5661849eb468afc984Philip Milne int minor = 0; 730899d5922870c78e0e663bc5661849eb468afc984Philip Milne int[] maxSizes = new int[count]; 731f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne 732899d5922870c78e0e663bc5661849eb468afc984Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 733d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); 734899d5922870c78e0e663bc5661849eb468afc984Philip Milne 735f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec; 736f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Interval majorRange = majorSpec.span; 737f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean majorWasDefined = majorSpec.startDefined; 738899d5922870c78e0e663bc5661849eb468afc984Philip Milne final int majorSpan = majorRange.size(); 739899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (majorWasDefined) { 740899d5922870c78e0e663bc5661849eb468afc984Philip Milne major = majorRange.min; 741899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 742899d5922870c78e0e663bc5661849eb468afc984Philip Milne 743f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec; 744f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Interval minorRange = minorSpec.span; 745f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean minorWasDefined = minorSpec.startDefined; 746899d5922870c78e0e663bc5661849eb468afc984Philip Milne final int minorSpan = clip(minorRange, minorWasDefined, count); 747899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (minorWasDefined) { 748899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor = minorRange.min; 749899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 750899d5922870c78e0e663bc5661849eb468afc984Philip Milne 751899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (count != 0) { 752899d5922870c78e0e663bc5661849eb468afc984Philip Milne // Find suitable row/col values when at least one is undefined. 753899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (!majorWasDefined || !minorWasDefined) { 754899d5922870c78e0e663bc5661849eb468afc984Philip Milne while (!fits(maxSizes, major, minor, minor + minorSpan)) { 755899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (minorWasDefined) { 756899d5922870c78e0e663bc5661849eb468afc984Philip Milne major++; 757899d5922870c78e0e663bc5661849eb468afc984Philip Milne } else { 758899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (minor + minorSpan <= count) { 759899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor++; 760899d5922870c78e0e663bc5661849eb468afc984Philip Milne } else { 761899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor = 0; 762899d5922870c78e0e663bc5661849eb468afc984Philip Milne major++; 763899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 764f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne } 765f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne } 7663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 767899d5922870c78e0e663bc5661849eb468afc984Philip Milne procrusteanFill(maxSizes, minor, minor + minorSpan, major + majorSpan); 7683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 769899d5922870c78e0e663bc5661849eb468afc984Philip Milne 770899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (horizontal) { 771899d5922870c78e0e663bc5661849eb468afc984Philip Milne setCellGroup(lp, major, majorSpan, minor, minorSpan); 772899d5922870c78e0e663bc5661849eb468afc984Philip Milne } else { 773899d5922870c78e0e663bc5661849eb468afc984Philip Milne setCellGroup(lp, minor, minorSpan, major, majorSpan); 774899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 775899d5922870c78e0e663bc5661849eb468afc984Philip Milne 776899d5922870c78e0e663bc5661849eb468afc984Philip Milne minor = minor + minorSpan; 777899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 7783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void invalidateStructure() { 781465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mLastLayoutParamsHashCode = UNINITIALIZED_HASH; 782465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.invalidateStructure(); 783465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.invalidateStructure(); 784899d5922870c78e0e663bc5661849eb468afc984Philip Milne // This can end up being done twice. Better twice than not at all. 7853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateValues(); 7863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 7883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void invalidateValues() { 789aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne // Need null check because requestLayout() is called in View's initializer, 790aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne // before we are set up. 791465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (mHorizontalAxis != null && mVerticalAxis != null) { 792465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.invalidateValues(); 793465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.invalidateValues(); 794aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 7953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 7963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 797d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne /** @hide */ 798d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne @Override 799d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne protected void onSetLayoutParams(View child, ViewGroup.LayoutParams layoutParams) { 800d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne super.onSetLayoutParams(child, layoutParams); 8010f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8020f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (!checkLayoutParams(layoutParams)) { 8030f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams("supplied LayoutParams are of the wrong type"); 8040f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8050f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 806d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne invalidateStructure(); 8073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 809f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final LayoutParams getLayoutParams(View c) { 810d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne return (LayoutParams) c.getLayoutParams(); 8113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8130f57cea8989cc03bcae19b621096e50b035b7308Philip Milne private static void handleInvalidParams(String msg) { 8140f57cea8989cc03bcae19b621096e50b035b7308Philip Milne throw new IllegalArgumentException(msg + ". "); 8150f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8160f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8170f57cea8989cc03bcae19b621096e50b035b7308Philip Milne private void checkLayoutParams(LayoutParams lp, boolean horizontal) { 8180f57cea8989cc03bcae19b621096e50b035b7308Philip Milne String groupName = horizontal ? "column" : "row"; 8190f57cea8989cc03bcae19b621096e50b035b7308Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 8200f57cea8989cc03bcae19b621096e50b035b7308Philip Milne Interval span = spec.span; 8210f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (span.min != UNDEFINED && span.min < 0) { 8220f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams(groupName + " indices must be positive"); 8230f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 824465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 8250f57cea8989cc03bcae19b621096e50b035b7308Philip Milne int count = axis.definedCount; 8260f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (count != UNDEFINED) { 8270f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (span.max > count) { 8280f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams(groupName + 8290f57cea8989cc03bcae19b621096e50b035b7308Philip Milne " indices (start + span) mustn't exceed the " + groupName + " count"); 8300f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8310f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (span.size() > count) { 8320f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams(groupName + " span mustn't exceed the " + groupName + " count"); 8330f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8340f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8350f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8360f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8370f57cea8989cc03bcae19b621096e50b035b7308Philip Milne @Override 8380f57cea8989cc03bcae19b621096e50b035b7308Philip Milne protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 8390f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (!(p instanceof LayoutParams)) { 8400f57cea8989cc03bcae19b621096e50b035b7308Philip Milne return false; 8410f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8420f57cea8989cc03bcae19b621096e50b035b7308Philip Milne LayoutParams lp = (LayoutParams) p; 8430f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8440f57cea8989cc03bcae19b621096e50b035b7308Philip Milne checkLayoutParams(lp, true); 8450f57cea8989cc03bcae19b621096e50b035b7308Philip Milne checkLayoutParams(lp, false); 8460f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8470f57cea8989cc03bcae19b621096e50b035b7308Philip Milne return true; 8480f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 8490f57cea8989cc03bcae19b621096e50b035b7308Philip Milne 8503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 8513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected LayoutParams generateDefaultLayoutParams() { 8523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return new LayoutParams(); 8533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 8563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams generateLayoutParams(AttributeSet attrs) { 8575125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return new LayoutParams(getContext(), attrs); 8583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 8613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 8623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return new LayoutParams(p); 8633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Draw grid 8663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 8673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) { 86847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio if (isLayoutRtl()) { 86947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio int width = getWidth(); 8707b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne graphics.drawLine(width - x1, y1, width - x2, y2, paint); 87147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio } else { 8727b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne graphics.drawLine(x1, y1, x2, y2, paint); 87347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio } 8743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 8753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 87610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne /** 87710ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne * @hide 87810ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne */ 87910ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne @Override 8807b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne protected void onDebugDrawMargins(Canvas canvas, Paint paint) { 88110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne // Apply defaults, so as to remove UNDEFINED values 88210ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne LayoutParams lp = new LayoutParams(); 88310ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne for (int i = 0; i < getChildCount(); i++) { 88410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne View c = getChildAt(i); 88510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne lp.setMargins( 8867b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne getMargin1(c, true, true), 8877b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne getMargin1(c, false, true), 8887b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne getMargin1(c, true, false), 8897b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne getMargin1(c, false, false)); 8907b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne lp.onDebugDraw(c, canvas, paint); 89110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne } 892b559976a50c34848d602cc7138859507a379893cPhilip Milne } 893b559976a50c34848d602cc7138859507a379893cPhilip Milne 89410ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne /** 89510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne * @hide 89610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne */ 8973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 89810ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne protected void onDebugDraw(Canvas canvas) { 89910ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne Paint paint = new Paint(); 90010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne paint.setStyle(Paint.Style.STROKE); 90110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne paint.setColor(Color.argb(50, 255, 255, 255)); 90210ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne 9037b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne Insets insets = getOpticalInsets(); 9047b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne 9057b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int top = getPaddingTop() + insets.top; 9067b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int left = getPaddingLeft() + insets.left; 9077b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int right = getWidth() - getPaddingRight() - insets.right; 9087b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int bottom = getHeight() - getPaddingBottom() - insets.bottom; 9097b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne 910465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int[] xs = mHorizontalAxis.locations; 91110ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne if (xs != null) { 91210ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne for (int i = 0, length = xs.length; i < length; i++) { 9137b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int x = left + xs[i]; 9147b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne drawLine(canvas, x, top, x, bottom, paint); 915b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 91610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne } 917b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 918465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int[] ys = mVerticalAxis.locations; 91910ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne if (ys != null) { 92010ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne for (int i = 0, length = ys.length; i < length; i++) { 9217b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne int y = top + ys[i]; 9227b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne drawLine(canvas, left, y, right, y, paint); 9233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 9243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 92510ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne 92610ca24a97cefc14fca1b26f59e627f487b3b108bPhilip Milne super.onDebugDraw(canvas); 9273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 9283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 9293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Add/remove 9303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 931e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne /** 932e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne * @hide 933e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne */ 9343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 935f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne protected void onViewAdded(View child) { 936f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne super.onViewAdded(child); 9373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateStructure(); 9383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 9393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 940e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne /** 941e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne * @hide 942e7dda0bb3d2b097f36b3e59f34fb5ab70e36b555Philip Milne */ 9433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 944f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne protected void onViewRemoved(View child) { 945f51d91c3ab232154b6c00d7f71377ff2421f79bfPhilip Milne super.onViewRemoved(child); 946b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne invalidateStructure(); 947350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne } 948350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne 949350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne /** 950350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * We need to call invalidateStructure() when a child's GONE flag changes state. 951350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * This implementation is a catch-all, invalidating on any change in the visibility flags. 952350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * 953350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne * @hide 954350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne */ 955350f0a63c9e785304063a95a6df9e128a67ec64fPhilip Milne @Override 9560d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) { 9570d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase super.onChildVisibilityChanged(child, oldVisibility, newVisibility); 9580d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase if (oldVisibility == GONE || newVisibility == GONE) { 959a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne invalidateStructure(); 9600d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase } 961b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne } 962b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne 963d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne private int computeLayoutParamsHashCode() { 964d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne int result = 1; 965d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 966d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne View c = getChildAt(i); 967d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) continue; 968d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne LayoutParams lp = (LayoutParams) c.getLayoutParams(); 969d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne result = 31 * result + lp.hashCode(); 970d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 971d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne return result; 972d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 9733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 974edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne private void consistencyCheck() { 975465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (mLastLayoutParamsHashCode == UNINITIALIZED_HASH) { 976edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne validateLayoutParams(); 977465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mLastLayoutParamsHashCode = computeLayoutParamsHashCode(); 978465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell } else if (mLastLayoutParamsHashCode != computeLayoutParamsHashCode()) { 979465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mPrinter.println("The fields of some layout parameters were modified in between " 980211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne + "layout operations. Check the javadoc for GridLayout.LayoutParams#rowSpec."); 981edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne invalidateStructure(); 982edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne consistencyCheck(); 983d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 984b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 985b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 986d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne // Measurement 987d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 988e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne // Note: padding has already been removed from the supplied specs 9894a145d72622772b920f60195e80942058984259cPhilip Milne private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec, 990edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne int childWidth, int childHeight) { 9914a145d72622772b920f60195e80942058984259cPhilip Milne int childWidthSpec = getChildMeasureSpec(parentWidthSpec, 992e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne getTotalMargin(child, true), childWidth); 9934a145d72622772b920f60195e80942058984259cPhilip Milne int childHeightSpec = getChildMeasureSpec(parentHeightSpec, 994e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne getTotalMargin(child, false), childHeight); 9954a145d72622772b920f60195e80942058984259cPhilip Milne child.measure(childWidthSpec, childHeightSpec); 996b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 997b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 998e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne // Note: padding has already been removed from the supplied specs 9994a145d72622772b920f60195e80942058984259cPhilip Milne private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) { 1000b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1001b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 1002d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) continue; 10034a145d72622772b920f60195e80942058984259cPhilip Milne LayoutParams lp = getLayoutParams(c); 10044a145d72622772b920f60195e80942058984259cPhilip Milne if (firstPass) { 10054a145d72622772b920f60195e80942058984259cPhilip Milne measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height); 10064a145d72622772b920f60195e80942058984259cPhilip Milne } else { 1007465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell boolean horizontal = (mOrientation == HORIZONTAL); 1008ecab1178648670f2c72b47faf250040fcded3d13Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 10094a145d72622772b920f60195e80942058984259cPhilip Milne if (spec.alignment == FILL) { 10104a145d72622772b920f60195e80942058984259cPhilip Milne Interval span = spec.span; 1011465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; 10124a145d72622772b920f60195e80942058984259cPhilip Milne int[] locations = axis.getLocations(); 1013ecab1178648670f2c72b47faf250040fcded3d13Philip Milne int cellSize = locations[span.max] - locations[span.min]; 1014ecab1178648670f2c72b47faf250040fcded3d13Philip Milne int viewSize = cellSize - getTotalMargin(c, horizontal); 1015ecab1178648670f2c72b47faf250040fcded3d13Philip Milne if (horizontal) { 1016ecab1178648670f2c72b47faf250040fcded3d13Philip Milne measureChildWithMargins2(c, widthSpec, heightSpec, viewSize, lp.height); 10174a145d72622772b920f60195e80942058984259cPhilip Milne } else { 1018ecab1178648670f2c72b47faf250040fcded3d13Philip Milne measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, viewSize); 10194a145d72622772b920f60195e80942058984259cPhilip Milne } 10204a145d72622772b920f60195e80942058984259cPhilip Milne } 10214a145d72622772b920f60195e80942058984259cPhilip Milne } 1022b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 1023b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne } 1024b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne 1025e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne static int adjust(int measureSpec, int delta) { 1026e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne return makeMeasureSpec( 1027e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne MeasureSpec.getSize(measureSpec + delta), MeasureSpec.getMode(measureSpec)); 1028e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne } 1029e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne 1030aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne @Override 1031aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne protected void onMeasure(int widthSpec, int heightSpec) { 1032edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne consistencyCheck(); 1033d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 10344a145d72622772b920f60195e80942058984259cPhilip Milne /** If we have been called by {@link View#measure(int, int)}, one of width or height 10354a145d72622772b920f60195e80942058984259cPhilip Milne * is likely to have changed. We must invalidate if so. */ 10364a145d72622772b920f60195e80942058984259cPhilip Milne invalidateValues(); 10374a145d72622772b920f60195e80942058984259cPhilip Milne 1038e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int hPadding = getPaddingLeft() + getPaddingRight(); 1039e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int vPadding = getPaddingTop() + getPaddingBottom(); 1040e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne 1041e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int widthSpecSansPadding = adjust( widthSpec, -hPadding); 1042e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int heightSpecSansPadding = adjust(heightSpec, -vPadding); 10434a145d72622772b920f60195e80942058984259cPhilip Milne 1044e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, true); 1045e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne 1046e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int widthSansPadding; 1047e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int heightSansPadding; 10484a145d72622772b920f60195e80942058984259cPhilip Milne 10494a145d72622772b920f60195e80942058984259cPhilip Milne // Use the orientation property to decide which axis should be laid out first. 1050465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell if (mOrientation == HORIZONTAL) { 1051465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding); 1052e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false); 1053465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding); 10544a145d72622772b920f60195e80942058984259cPhilip Milne } else { 1055465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding); 1056e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false); 1057465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding); 10584a145d72622772b920f60195e80942058984259cPhilip Milne } 1059aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1060e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int measuredWidth = Math.max(widthSansPadding + hPadding, getSuggestedMinimumWidth()); 1061e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne int measuredHeight = Math.max(heightSansPadding + vPadding, getSuggestedMinimumHeight()); 106209e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne 10633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setMeasuredDimension( 1064e0b85cd706da22d1eeeba92b842662d69090dbc5Philip Milne resolveSizeAndState(measuredWidth, widthSpec, 0), 106509e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne resolveSizeAndState(measuredHeight, heightSpec, 0)); 10663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 10673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 106848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private int getMeasurement(View c, boolean horizontal) { 10697b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight(); 10703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 10713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1072f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final int getMeasurementIncludingMargin(View c, boolean horizontal) { 1073d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) { 10745125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return 0; 10755125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 10764c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal); 1077aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 10783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1079aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne @Override 1080aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public void requestLayout() { 1081aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne super.requestLayout(); 1082aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne invalidateValues(); 1083aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1084aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1085f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Alignment getAlignment(Alignment alignment, boolean horizontal) { 10865125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return (alignment != UNDEFINED_ALIGNMENT) ? alignment : 108747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio (horizontal ? START : BASELINE); 10885125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 10895125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 10903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Layout container 10913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1092aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /** 1093aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * {@inheritDoc} 1094aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 1095aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1096aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne The layout operation is implemented by delegating the heavy lifting to the 1097aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne to the mHorizontalAxis and mVerticalAxis instances of the internal Axis class. 1098aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Together they compute the locations of the vertical and horizontal lines of 1099aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne the grid (respectively!). 1100aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1101aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This method is then left with the simpler task of applying margins, gravity 1102aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne and sizing to each child view and then placing it in its cell. 1103aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 11043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 110509e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 1106edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne consistencyCheck(); 1107d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 110809e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne int targetWidth = right - left; 110909e2d4d0d5101e2fc44909b83965465a7b90afabPhilip Milne int targetHeight = bottom - top; 11103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingLeft = getPaddingLeft(); 11123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingTop = getPaddingTop(); 11133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingRight = getPaddingRight(); 11143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int paddingBottom = getPaddingBottom(); 11153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1116465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight); 1117465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom); 11183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1119465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int[] hLocations = mHorizontalAxis.getLocations(); 1120465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell int[] vLocations = mVerticalAxis.getLocations(); 11214c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne 1122b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1123b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 1124d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) continue; 1125b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne LayoutParams lp = getLayoutParams(c); 112693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec columnSpec = lp.columnSpec; 112793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec rowSpec = lp.rowSpec; 1128aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 112993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval colSpan = columnSpec.span; 113093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval rowSpan = rowSpec.span; 11313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11324c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int x1 = hLocations[colSpan.min]; 11334c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int y1 = vLocations[rowSpan.min]; 11343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11354c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int x2 = hLocations[colSpan.max]; 11364c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int y2 = vLocations[rowSpan.max]; 11373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int cellWidth = x2 - x1; 11393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int cellHeight = y2 - y1; 11403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 114148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int pWidth = getMeasurement(c, true); 114248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int pHeight = getMeasurement(c, false); 11433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11445125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Alignment hAlign = getAlignment(columnSpec.alignment, true); 11455125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Alignment vAlign = getAlignment(rowSpec.alignment, false); 1146aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1147465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i); 1148465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i); 11497fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 11507fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne // Gravity offsets: the location of the alignment group relative to its cell group. 11516216e87fe8ad3273855233965b34049d22763e94Philip Milne int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true)); 11526216e87fe8ad3273855233965b34049d22763e94Philip Milne int gravityOffsetY = vAlign.getGravityOffset(c, cellHeight - boundsY.size(true)); 11536216e87fe8ad3273855233965b34049d22763e94Philip Milne 11546216e87fe8ad3273855233965b34049d22763e94Philip Milne int leftMargin = getMargin(c, true, true); 11554c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int topMargin = getMargin(c, false, true); 11566216e87fe8ad3273855233965b34049d22763e94Philip Milne int rightMargin = getMargin(c, true, false); 11574c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne int bottomMargin = getMargin(c, false, false); 11587fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 11591557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int sumMarginsX = leftMargin + rightMargin; 11601557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int sumMarginsY = topMargin + bottomMargin; 11611557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne 11624c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne // Alignment offsets: the location of the view relative to its alignment group. 11631557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true); 11641557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false); 11657fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 11661557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX); 11671557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY); 11687fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne 11696216e87fe8ad3273855233965b34049d22763e94Philip Milne int dx = x1 + gravityOffsetX + alignmentOffsetX; 11703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11716216e87fe8ad3273855233965b34049d22763e94Philip Milne int cx = !isLayoutRtl() ? paddingLeft + leftMargin + dx : 11726216e87fe8ad3273855233965b34049d22763e94Philip Milne targetWidth - width - paddingRight - rightMargin - dx; 11736216e87fe8ad3273855233965b34049d22763e94Philip Milne int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin; 11743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1175899d5922870c78e0e663bc5661849eb468afc984Philip Milne if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) { 1176899d5922870c78e0e663bc5661849eb468afc984Philip Milne c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY)); 1177899d5922870c78e0e663bc5661849eb468afc984Philip Milne } 1178b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne c.layout(cx, cy, cx + width, cy + height); 11793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 11813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 11828a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 11838a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 11848a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 11858a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(GridLayout.class.getName()); 11868a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 11878a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 11888a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 11898a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 11908a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(info); 11918a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov info.setClassName(GridLayout.class.getName()); 11928a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 11938a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 11943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Inner classes 11953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1196aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1197aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This internal class houses the algorithm for computing the locations of grid lines; 1198aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne along either the horizontal or vertical axis. A GridLayout uses two instances of this class - 1199aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne distinguished by the "horizontal" flag which is true for the horizontal axis and false 1200aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne for the vertical one. 1201aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 1202f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final class Axis { 120348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private static final int NEW = 0; 12043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int PENDING = 1; 12053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int COMPLETE = 2; 12063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final boolean horizontal; 12083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1209f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int definedCount = UNDEFINED; 12104a145d72622772b920f60195e80942058984259cPhilip Milne private int maxIndex = UNDEFINED; 12113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 121293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne PackedMap<Spec, Bounds> groupBounds; 12133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean groupBoundsValid = false; 12143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 121548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne PackedMap<Interval, MutableInt> forwardLinks; 121648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean forwardLinksValid = false; 121748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 121848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne PackedMap<Interval, MutableInt> backwardLinks; 121948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean backwardLinksValid = false; 12203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int[] leadingMargins; 1222aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public boolean leadingMarginsValid = false; 1223aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 12243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int[] trailingMargins; 1225aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public boolean trailingMarginsValid = false; 12263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public Arc[] arcs; 12283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean arcsValid = false; 12293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1230aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public int[] locations; 123148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean locationsValid = false; 1232aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1233f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean orderPreserved = DEFAULT_ORDER_PRESERVED; 12343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 123548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private MutableInt parentMin = new MutableInt(0); 123648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private MutableInt parentMax = new MutableInt(-MAX_SIZE); 123748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 12383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private Axis(boolean horizontal) { 12393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.horizontal = horizontal; 12403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12424a145d72622772b920f60195e80942058984259cPhilip Milne private int calculateMaxIndex() { 12434a145d72622772b920f60195e80942058984259cPhilip Milne // the number Integer.MIN_VALUE + 1 comes up in undefined cells 12444a145d72622772b920f60195e80942058984259cPhilip Milne int result = -1; 1245b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1246b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 1247b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne LayoutParams params = getLayoutParams(c); 124893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? params.columnSpec : params.rowSpec; 12494a145d72622772b920f60195e80942058984259cPhilip Milne Interval span = spec.span; 12504a145d72622772b920f60195e80942058984259cPhilip Milne result = max(result, span.min); 12514a145d72622772b920f60195e80942058984259cPhilip Milne result = max(result, span.max); 12520f57cea8989cc03bcae19b621096e50b035b7308Philip Milne result = max(result, span.size()); 12533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12544a145d72622772b920f60195e80942058984259cPhilip Milne return result == -1 ? UNDEFINED : result; 12553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12574a145d72622772b920f60195e80942058984259cPhilip Milne private int getMaxIndex() { 12584a145d72622772b920f60195e80942058984259cPhilip Milne if (maxIndex == UNDEFINED) { 12594a145d72622772b920f60195e80942058984259cPhilip Milne maxIndex = max(0, calculateMaxIndex()); // use zero when there are no children 12603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12614a145d72622772b920f60195e80942058984259cPhilip Milne return maxIndex; 1262f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1263f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1264f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int getCount() { 12654a145d72622772b920f60195e80942058984259cPhilip Milne return max(definedCount, getMaxIndex()); 12663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setCount(int count) { 12690f57cea8989cc03bcae19b621096e50b035b7308Philip Milne if (count != UNDEFINED && count < getMaxIndex()) { 12700f57cea8989cc03bcae19b621096e50b035b7308Philip Milne handleInvalidParams((horizontal ? "column" : "row") + 12710f57cea8989cc03bcae19b621096e50b035b7308Philip Milne "Count must be greater than or equal to the maximum of all grid indices " + 12720f57cea8989cc03bcae19b621096e50b035b7308Philip Milne "(and spans) defined in the LayoutParams of each child"); 12730f57cea8989cc03bcae19b621096e50b035b7308Philip Milne } 1274f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.definedCount = count; 12753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean isOrderPreserved() { 1278f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return orderPreserved; 12793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setOrderPreserved(boolean orderPreserved) { 1282f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.orderPreserved = orderPreserved; 12833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateStructure(); 12843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 128693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne private PackedMap<Spec, Bounds> createGroupBounds() { 128793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class); 128848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 1289b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne View c = getChildAt(i); 1290a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne // we must include views that are GONE here, see introductory javadoc 12915125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne LayoutParams lp = getLayoutParams(c); 12925125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 12935125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds(); 12945125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne assoc.put(spec, bounds); 12953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 129648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return assoc.pack(); 12973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 12983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 12993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void computeGroupBounds() { 1300b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne Bounds[] values = groupBounds.values; 1301b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0; i < values.length; i++) { 1302b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne values[i].reset(); 13033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 1304aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 13053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne View c = getChildAt(i); 1306a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne // we must include views that are GONE here, see introductory javadoc 13073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne LayoutParams lp = getLayoutParams(c); 130893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 13091557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne groupBounds.getValue(i).include(GridLayout.this, c, spec, this); 13103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1313f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public PackedMap<Spec, Bounds> getGroupBounds() { 13143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (groupBounds == null) { 13153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBounds = createGroupBounds(); 13163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (!groupBoundsValid) { 13183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne computeGroupBounds(); 13193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBoundsValid = true; 13203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return groupBounds; 13223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 13243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Add values computed by alignment - taking the max of all alignments in each span 132548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private PackedMap<Interval, MutableInt> createLinks(boolean min) { 132648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class); 132793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec[] keys = getGroupBounds().keys; 132848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0, N = keys.length; i < N; i++) { 132948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Interval span = min ? keys[i].span : keys[i].span.inverse(); 133048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne result.put(span, new MutableInt()); 13313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 133248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return result.pack(); 13333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 133548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) { 133648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne MutableInt[] spans = links.values; 13373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < spans.length; i++) { 13383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne spans[i].reset(); 13393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 13415d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne // Use getter to trigger a re-evaluation 134248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Bounds[] bounds = getGroupBounds().values; 13433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < bounds.length; i++) { 134448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int size = bounds[i].size(min); 134548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne MutableInt valueHolder = links.getValue(i); 13465125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne // this effectively takes the max() of the minima and the min() of the maxima 13475125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne valueHolder.value = max(valueHolder.value, min ? size : -size); 13483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 135148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private PackedMap<Interval, MutableInt> getForwardLinks() { 135248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (forwardLinks == null) { 135348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinks = createLinks(true); 13543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 135548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!forwardLinksValid) { 135648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeLinks(forwardLinks, true); 135748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinksValid = true; 13583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 135948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return forwardLinks; 13603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 136248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private PackedMap<Interval, MutableInt> getBackwardLinks() { 136348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (backwardLinks == null) { 136448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinks = createLinks(false); 13653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 136648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!backwardLinksValid) { 136748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeLinks(backwardLinks, false); 136848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinksValid = true; 136948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 137048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return backwardLinks; 13713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 137348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void include(List<Arc> arcs, Interval key, MutableInt size, 1374edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne boolean ignoreIfAlreadyPresent) { 137548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne /* 137648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Remove self referential links. 137748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne These appear: 137848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne . as parental constraints when GridLayout has no children 137948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne . when components have been marked as GONE 138048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne */ 138148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (key.size() == 0) { 138248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return; 13833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 138448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // this bit below should really be computed outside here - 138548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // its just to stop default (row/col > 0) constraints obliterating valid entries 138648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (ignoreIfAlreadyPresent) { 138748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (Arc arc : arcs) { 138848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Interval span = arc.span; 138948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (span.equals(key)) { 139048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return; 139148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 139248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 139348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 139448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne arcs.add(new Arc(key, size)); 13953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 13963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 139748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void include(List<Arc> arcs, Interval key, MutableInt size) { 139848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(arcs, key, size, true); 13993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1401aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne // Group arcs by their first vertex, returning an array of arrays. 14023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // This is linear in the number of arcs. 1403f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Arc[][] groupArcsByFirstVertex(Arc[] arcs) { 140448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int N = getCount() + 1; // the number of vertices 14053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Arc[][] result = new Arc[N][]; 14063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int[] sizes = new int[N]; 14073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (Arc arc : arcs) { 14083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne sizes[arc.span.min]++; 14095d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 14103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < sizes.length; i++) { 14113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result[i] = new Arc[sizes[i]]; 14123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // reuse the sizes array to hold the current last elements as we insert each arc 14143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Arrays.fill(sizes, 0); 14153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (Arc arc : arcs) { 14163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int i = arc.span.min; 14173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result[i][sizes[i]++] = arc; 14183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 14203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 14213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 142348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private Arc[] topologicalSort(final Arc[] arcs) { 142448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return new Object() { 142548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] result = new Arc[arcs.length]; 142648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int cursor = result.length - 1; 142748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs); 14283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int[] visited = new int[getCount() + 1]; 14293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 143048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne void walk(int loc) { 143148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne switch (visited[loc]) { 143248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case NEW: { 143348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne visited[loc] = PENDING; 143448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (Arc arc : arcsByVertex[loc]) { 143548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne walk(arc.span.max); 143648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne result[cursor--] = arc; 14373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 143848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne visited[loc] = COMPLETE; 143948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne break; 144048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 144148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case PENDING: { 1442b65408fc0fefa82161475de7f7f32284f6f60a56Philip Milne // le singe est dans l'arbre 144348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne assert false; 144448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne break; 144548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 144648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case COMPLETE: { 144748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne break; 14483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 145148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 145248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] sort() { 145348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) { 145448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne walk(loc); 145548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 145648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne assert cursor == -1; 145748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return result; 145848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 145948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne }.sort(); 146048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 146148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 146248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private Arc[] topologicalSort(List<Arc> arcs) { 146348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return topologicalSort(arcs.toArray(new Arc[arcs.size()])); 14643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 146648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) { 146748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0; i < links.keys.length; i++) { 146848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Interval key = links.keys[i]; 146948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(result, key, links.values[i], false); 147048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 147148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 147248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1473aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private Arc[] createArcs() { 147448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne List<Arc> mins = new ArrayList<Arc>(); 147548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne List<Arc> maxs = new ArrayList<Arc>(); 14763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 147748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add the minimum values from the components. 147848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne addComponentSizes(mins, getForwardLinks()); 147948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add the maximum values from the components. 148048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne addComponentSizes(maxs, getBackwardLinks()); 14813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 148248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add ordering constraints to prevent row/col sizes from going negative 1483f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (orderPreserved) { 148448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add a constraint for every row/col 14853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < getCount(); i++) { 1486899d5922870c78e0e663bc5661849eb468afc984Philip Milne include(mins, new Interval(i, i + 1), new MutableInt(0)); 14873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 14883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 148948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 149048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Add the container constraints. Use the version of include that allows 149148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // duplicate entries in case a child spans the entire grid. 149248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int N = getCount(); 149348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(mins, new Interval(0, N), parentMin, false); 149448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(maxs, new Interval(N, 0), parentMax, false); 149548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 149648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // Sort 149748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] sMins = topologicalSort(mins); 149848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Arc[] sMaxs = topologicalSort(maxs); 149948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 150048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return append(sMins, sMaxs); 150148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 150248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 150348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void computeArcs() { 150448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne // getting the links validates the values that are shared by the arc list 150548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne getForwardLinks(); 150648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne getBackwardLinks(); 15073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1509aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public Arc[] getArcs() { 15103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (arcs == null) { 1511aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne arcs = createArcs(); 15123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (!arcsValid) { 151448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeArcs(); 15153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne arcsValid = true; 15163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return arcs; 15183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1520aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private boolean relax(int[] locations, Arc entry) { 152148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!entry.valid) { 152248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return false; 152348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 15243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Interval span = entry.span; 15253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int u = span.min; 15263f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int v = span.max; 15273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int value = entry.value.value; 15283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int candidate = locations[u] + value; 1529aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (candidate > locations[v]) { 15303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne locations[v] = candidate; 15313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 15323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 15343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 15353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1536f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private void init(int[] locations) { 15374a145d72622772b920f60195e80942058984259cPhilip Milne Arrays.fill(locations, 0); 1538f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1539f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1540f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private String arcsToString(List<Arc> arcs) { 15414a145d72622772b920f60195e80942058984259cPhilip Milne String var = horizontal ? "x" : "y"; 1542f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne StringBuilder result = new StringBuilder(); 15434a145d72622772b920f60195e80942058984259cPhilip Milne boolean first = true; 15444a145d72622772b920f60195e80942058984259cPhilip Milne for (Arc arc : arcs) { 15454a145d72622772b920f60195e80942058984259cPhilip Milne if (first) { 15464a145d72622772b920f60195e80942058984259cPhilip Milne first = false; 1547f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } else { 15484a145d72622772b920f60195e80942058984259cPhilip Milne result = result.append(", "); 1549f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1550f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int src = arc.span.min; 1551f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int dst = arc.span.max; 1552f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int value = arc.value.value; 1553f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne result.append((src < dst) ? 1554edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne var + dst + "-" + var + src + ">=" + value : 1555edd69518ffec87fb7b1931e708678ef441152cdePhilip Milne var + src + "-" + var + dst + "<=" + -value); 1556f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1557f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1558f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return result.toString(); 1559f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1560f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1561f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private void logError(String axisName, Arc[] arcs, boolean[] culprits0) { 1562f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne List<Arc> culprits = new ArrayList<Arc>(); 1563f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne List<Arc> removed = new ArrayList<Arc>(); 1564f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int c = 0; c < arcs.length; c++) { 1565f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Arc arc = arcs[c]; 1566f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (culprits0[c]) { 1567f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne culprits.add(arc); 1568f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1569f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (!arc.valid) { 1570f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne removed.add(arc); 1571f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1572f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1573465ea74234dd9f7c8e2f5927f51eb087de74ed2eAdam Powell mPrinter.println(axisName + " constraints: " + arcsToString(culprits) + 1574211d03322cf6e8a6c8a947bf8a494abd78a767c2Philip Milne " are inconsistent; permanently removing: " + arcsToString(removed) + ". "); 1575f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1576f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1577aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 1578aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N) 1579aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1580aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne GridLayout converts its requirements into a system of linear constraints of the 1581aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne form: 1582aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1583aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne x[i] - x[j] < a[k] 1584aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1585aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Where the x[i] are variables and the a[k] are constants. 1586aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1587aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne For example, if the variables were instead labeled x, y, z we might have: 1588aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1589aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne x - y < 17 1590aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne y - z < 23 1591aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne z - x < 42 1592aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1593aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This is a special case of the Linear Programming problem that is, in turn, 1594aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne equivalent to the single-source shortest paths problem on a digraph, for 1595aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne which the O(n^2) Bellman-Ford algorithm the most commonly used general solution. 1596aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 159748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void solve(Arc[] arcs, int[] locations) { 1598f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne String axisName = horizontal ? "horizontal" : "vertical"; 15993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1. 1600f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean[] originalCulprits = null; 16013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1602f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int p = 0; p < arcs.length; p++) { 1603f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne init(locations); 1604f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1605f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne // We take one extra pass over traditional Bellman-Ford (and omit their final step) 1606f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int i = 0; i < N; i++) { 1607f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean changed = false; 1608f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int j = 0, length = arcs.length; j < length; j++) { 1609f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne changed |= relax(locations, arcs[j]); 1610f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1611f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (!changed) { 1612f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (originalCulprits != null) { 1613f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne logError(axisName, arcs, originalCulprits); 1614f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1615f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return; 16163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 161848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1619f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne boolean[] culprits = new boolean[arcs.length]; 1620f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int i = 0; i < N; i++) { 1621f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int j = 0, length = arcs.length; j < length; j++) { 1622f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne culprits[j] |= relax(locations, arcs[j]); 1623f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1624f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 162548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1626f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (p == 0) { 1627f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne originalCulprits = culprits; 162848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1629f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1630f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne for (int i = 0; i < arcs.length; i++) { 1631f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (culprits[i]) { 1632f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Arc arc = arcs[i]; 1633f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne // Only remove max values, min values alone cannot be inconsistent 1634f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne if (arc.span.min < arc.span.max) { 1635f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne continue; 1636f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne } 1637f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne arc.valid = false; 1638f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne break; 163948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 164048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 164148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 16423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1644aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private void computeMargins(boolean leading) { 1645aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int[] margins = leading ? leadingMargins : trailingMargins; 1646b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne for (int i = 0, N = getChildCount(); i < N; i++) { 16473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne View c = getChildAt(i); 1648d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (c.getVisibility() == View.GONE) continue; 16493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne LayoutParams lp = getLayoutParams(c); 165093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; 165193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Interval span = spec.span; 16523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int index = leading ? span.min : span.max; 16534c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne margins[index] = max(margins[index], getMargin1(c, horizontal, leading)); 16543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1657f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne // External entry points 1658f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 1659f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int[] getLeadingMargins() { 1660aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (leadingMargins == null) { 1661aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMargins = new int[getCount() + 1]; 1662aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1663aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (!leadingMarginsValid) { 1664aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne computeMargins(true); 1665aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMarginsValid = true; 1666aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1667aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return leadingMargins; 1668aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1669aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1670f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int[] getTrailingMargins() { 1671aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (trailingMargins == null) { 1672aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMargins = new int[getCount() + 1]; 1673aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1674aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (!trailingMarginsValid) { 1675aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne computeMargins(false); 1676aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMarginsValid = true; 1677aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1678aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return trailingMargins; 1679aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 16803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 168148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void computeLocations(int[] a) { 1682f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne solve(getArcs(), a); 16834a145d72622772b920f60195e80942058984259cPhilip Milne if (!orderPreserved) { 16844a145d72622772b920f60195e80942058984259cPhilip Milne // Solve returns the smallest solution to the constraint system for which all 16854a145d72622772b920f60195e80942058984259cPhilip Milne // values are positive. One value is therefore zero - though if the row/col 16864a145d72622772b920f60195e80942058984259cPhilip Milne // order is not preserved this may not be the first vertex. For consistency, 16874a145d72622772b920f60195e80942058984259cPhilip Milne // translate all the values so that they measure the distance from a[0]; the 16884a145d72622772b920f60195e80942058984259cPhilip Milne // leading edge of the parent. After this transformation some values may be 16894a145d72622772b920f60195e80942058984259cPhilip Milne // negative. 16904a145d72622772b920f60195e80942058984259cPhilip Milne int a0 = a[0]; 16914a145d72622772b920f60195e80942058984259cPhilip Milne for (int i = 0, N = a.length; i < N; i++) { 16924a145d72622772b920f60195e80942058984259cPhilip Milne a[i] = a[i] - a0; 16934a145d72622772b920f60195e80942058984259cPhilip Milne } 16944a145d72622772b920f60195e80942058984259cPhilip Milne } 16953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 16963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1697f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int[] getLocations() { 1698aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne if (locations == null) { 1699aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int N = getCount() + 1; 1700aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne locations = new int[N]; 1701aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 170248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne if (!locationsValid) { 170348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne computeLocations(locations); 170448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne locationsValid = true; 170548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1706aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne return locations; 17073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 17083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1709aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private int size(int[] locations) { 17104a145d72622772b920f60195e80942058984259cPhilip Milne // The parental edges are attached to vertices 0 and N - even when order is not 17114a145d72622772b920f60195e80942058984259cPhilip Milne // being preserved and other vertices fall outside this range. Measure the distance 17124a145d72622772b920f60195e80942058984259cPhilip Milne // between vertices 0 and N, assuming that locations[0] = 0. 17134a145d72622772b920f60195e80942058984259cPhilip Milne return locations[getCount()]; 1714aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne } 1715aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 171648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private void setParentConstraints(int min, int max) { 171748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne parentMin.value = min; 171848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne parentMax.value = -max; 171948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne locationsValid = false; 17203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 17213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 172248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private int getMeasure(int min, int max) { 172348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne setParentConstraints(min, max); 172448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return size(getLocations()); 172548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1726aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1727f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public int getMeasure(int measureSpec) { 172848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int mode = MeasureSpec.getMode(measureSpec); 172948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int size = MeasureSpec.getSize(measureSpec); 173048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne switch (mode) { 173148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case MeasureSpec.UNSPECIFIED: { 173293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne return getMeasure(0, MAX_SIZE); 173348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 173448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case MeasureSpec.EXACTLY: { 173548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return getMeasure(size, size); 173648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 173748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne case MeasureSpec.AT_MOST: { 173848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return getMeasure(0, size); 173948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 174048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne default: { 174148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne assert false; 174248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return 0; 174348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 17443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 174548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 1746aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 1747f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void layout(int size) { 174848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne setParentConstraints(size, size); 174948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne getLocations(); 17503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 17513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1752f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void invalidateStructure() { 17534a145d72622772b920f60195e80942058984259cPhilip Milne maxIndex = UNDEFINED; 1754aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 17553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBounds = null; 175648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinks = null; 175748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinks = null; 175848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1759aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMargins = null; 1760aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMargins = null; 1761c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne arcs = null; 176248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1763aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne locations = null; 17643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne invalidateValues(); 17663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 17673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1768f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void invalidateValues() { 17693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne groupBoundsValid = false; 177048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne forwardLinksValid = false; 177148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne backwardLinksValid = false; 177248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 1773aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne leadingMarginsValid = false; 1774aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne trailingMarginsValid = false; 177548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne arcsValid = false; 177648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 177748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne locationsValid = false; 17783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 17793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 17803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 17813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 17823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Layout information associated with each of the children of a GridLayout. 17833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 17843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * GridLayout supports both row and column spanning and arbitrary forms of alignment within 17853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * each cell group. The fundamental parameters associated with each cell group are 17863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * gathered into their vertical and horizontal components and stored 178793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * in the {@link #rowSpec} and {@link #columnSpec} layout parameters. 17886216e87fe8ad3273855233965b34049d22763e94Philip Milne * {@link GridLayout.Spec Specs} are immutable structures 1789b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne * and may be shared between the layout parameters of different children. 17903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 179193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * The row and column specs contain the leading and trailing indices along each axis 1792aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne * and together specify the four grid indices that delimit the cells of this cell group. 17933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 179493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * The alignment properties of the row and column specs together specify 17953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * both aspects of alignment within the cell group. It is also possible to specify a child's 17963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)} 17973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * method. 1798f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1799f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h4>WRAP_CONTENT and MATCH_PARENT</h4> 1800f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1801f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * Because the default values of the {@link #width} and {@link #height} 1802f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly 1803f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * declared in the layout parameters of GridLayout's children. In addition, 1804f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from 1805f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is 1806f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * instead controlled by the principle of <em>flexibility</em>, 1807f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * as discussed in {@link GridLayout}. 1808f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1809f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <h4>Summary</h4> 1810f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 1811f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * You should not need to use either of the special size values: 1812f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of 1813f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * a GridLayout. 18143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 18153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <h4>Default values</h4> 18163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 18173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <ul> 18183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #width} = {@link #WRAP_CONTENT}</li> 18193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #height} = {@link #WRAP_CONTENT}</li> 18203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #topMargin} = 0 when 18213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 18227fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 18233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 18243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #leftMargin} = 0 when 18253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 18267fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 18273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 18283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #bottomMargin} = 0 when 18293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 18307fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 18313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 18323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <li>{@link #rightMargin} = 0 when 18333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is 18347fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false}; otherwise {@link #UNDEFINED}, to 18353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * indicate that a default value should be computed on demand. </li> 1836f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li> 1837f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li> 1838f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li> 1839f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li> 1840f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li> 18416216e87fe8ad3273855233965b34049d22763e94Philip Milne * <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li> 18423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * </ul> 18433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 1844f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * See {@link GridLayout} for a more complete description of the conventions 1845f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * used by GridLayout in the interpretation of the properties of this class. 1846f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * 18473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_row 18483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan 18493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_column 18503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan 18513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity 18523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 18533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static class LayoutParams extends MarginLayoutParams { 18543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Default values 18563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_WIDTH = WRAP_CONTENT; 18583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_HEIGHT = WRAP_CONTENT; 18593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_MARGIN = UNDEFINED; 18603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_ROW = UNDEFINED; 18613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_COLUMN = UNDEFINED; 1862f474870fe1189f73cf8ffbaba9e524ef194b5043Philip Milne private static final Interval DEFAULT_SPAN = new Interval(UNDEFINED, UNDEFINED + 1); 18633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int DEFAULT_SPAN_SIZE = DEFAULT_SPAN.size(); 18643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // TypedArray indices 18663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1867b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin; 1868b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft; 1869b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop; 1870b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int RIGHT_MARGIN = 1871b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne R.styleable.ViewGroup_MarginLayout_layout_marginRight; 18723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static final int BOTTOM_MARGIN = 1873b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne R.styleable.ViewGroup_MarginLayout_layout_marginBottom; 18743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 1875b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column; 1876b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan; 18775d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 1878b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW = R.styleable.GridLayout_Layout_layout_row; 1879b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan; 18805d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 1881b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity; 18823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Instance variables 18843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 18853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1886f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * The spec that defines the vertical characteristics of the cell group 18873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * described by these layout parameters. 1888d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * If an assignment is made to this field after a measurement or layout operation 1889d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * has already taken place, a call to 1890d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)} 1891d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * must be made to notify GridLayout of the change. GridLayout is normally able 1892d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * to detect when code fails to observe this rule, issue a warning and take steps to 1893d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * compensate for the omission. This facility is implemented on a best effort basis 1894d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * and should not be relied upon in production code - so it is best to include the above 1895d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * calls to remove the warnings as soon as it is practical. 18963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1897f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public Spec rowSpec = Spec.UNDEFINED; 1898f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 18993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 1900f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne * The spec that defines the horizontal characteristics of the cell group 19013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * described by these layout parameters. 1902d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * If an assignment is made to this field after a measurement or layout operation 1903d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * has already taken place, a call to 1904d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)} 1905d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * must be made to notify GridLayout of the change. GridLayout is normally able 1906d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * to detect when code fails to observe this rule, issue a warning and take steps to 1907d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * compensate for the omission. This facility is implemented on a best effort basis 1908d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * and should not be relied upon in production code - so it is best to include the above 1909d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne * calls to remove the warnings as soon as it is practical. 19103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 1911f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public Spec columnSpec = Spec.UNDEFINED; 19123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Constructors 19143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private LayoutParams( 19163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int width, int height, 19173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int left, int top, int right, int bottom, 191893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec rowSpec, Spec columnSpec) { 19193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(width, height); 19203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne setMargins(left, top, right, bottom); 192193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne this.rowSpec = rowSpec; 192293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne this.columnSpec = columnSpec; 19233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 192693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Constructs a new LayoutParams instance for this <code>rowSpec</code> 192793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * and <code>columnSpec</code>. All other fields are initialized with 19283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * default values as defined in {@link LayoutParams}. 19293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 193093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param rowSpec the rowSpec 193193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param columnSpec the columnSpec 19323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 193393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public LayoutParams(Spec rowSpec, Spec columnSpec) { 19343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this(DEFAULT_WIDTH, DEFAULT_HEIGHT, 19353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, 193693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne rowSpec, columnSpec); 19373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 19403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}. 19413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 19423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams() { 1943f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this(Spec.UNDEFINED, Spec.UNDEFINED); 19443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Copying constructors 19473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 19493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 19503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 19513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(ViewGroup.LayoutParams params) { 19523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(params); 19533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 19563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 19573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 19583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(MarginLayoutParams params) { 19593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne super(params); 19603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 19630a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette * Copy constructor. Clones the width, height, margin values, row spec, 19640a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette * and column spec of the source. 19650a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette * 19660a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette * @param source The layout params to copy from. 19673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 19680a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette public LayoutParams(LayoutParams source) { 19690a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette super(source); 19700a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette 19710a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette this.rowSpec = source.rowSpec; 19720a0e155cadecd32599a7354a1836232c885f4bd2Alan Viverette this.columnSpec = source.columnSpec; 19733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // AttributeSet constructors 19763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 19783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@inheritDoc} 19793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 19803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Values not defined in the attribute set take the default values 19813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * defined in {@link LayoutParams}. 19823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 19833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public LayoutParams(Context context, AttributeSet attrs) { 19845125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne super(context, attrs); 19855125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne reInitSuper(context, attrs); 19865125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne init(context, attrs); 19873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 19883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Implementation 19903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Reinitialise the margins using a different default policy than MarginLayoutParams. 19923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // Here we use the value UNDEFINED (as distinct from zero) to represent the undefined state 19933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // so that a layout manager default can be accessed post set up. We need this as, at the 19943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // point of installation, we do not know how many rows/cols there are and therefore 19953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // which elements are positioned next to the container's trailing edges. We need to 19963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // know this as margins around the container's boundary should have different 19973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // defaults to those between peers. 19983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 19993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // This method could be parametrized and moved into MarginLayout. 20003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private void reInitSuper(Context context, AttributeSet attrs) { 2001b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne TypedArray a = 2002b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout); 20033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne try { 20043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN); 20053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.leftMargin = a.getDimensionPixelSize(LEFT_MARGIN, margin); 20073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.topMargin = a.getDimensionPixelSize(TOP_MARGIN, margin); 20083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.rightMargin = a.getDimensionPixelSize(RIGHT_MARGIN, margin); 20093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.bottomMargin = a.getDimensionPixelSize(BOTTOM_MARGIN, margin); 20103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } finally { 20113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne a.recycle(); 20123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20155125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne private void init(Context context, AttributeSet attrs) { 2016b0ce49b5ad53631ff0c3cdd8266e82f3c20c65dcPhilip Milne TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout); 20173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne try { 20185125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int gravity = a.getInt(GRAVITY, Gravity.NO_GRAVITY); 20193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20201e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne int column = a.getInt(COLUMN, DEFAULT_COLUMN); 20215125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE); 2022899d5922870c78e0e663bc5661849eb468afc984Philip Milne this.columnSpec = spec(column, colSpan, getAlignment(gravity, true)); 20233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20241e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne int row = a.getInt(ROW, DEFAULT_ROW); 20251e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE); 2026899d5922870c78e0e663bc5661849eb468afc984Philip Milne this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false)); 20273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } finally { 20283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne a.recycle(); 20293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 20337fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}. 20346216e87fe8ad3273855233965b34049d22763e94Philip Milne * See {@link Gravity}. 20353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 20367fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param gravity the new gravity value 20373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 20383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity 20393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 20403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public void setGravity(int gravity) { 20415125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne rowSpec = rowSpec.copyWriteAlignment(getAlignment(gravity, false)); 20425125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne columnSpec = columnSpec.copyWriteAlignment(getAlignment(gravity, true)); 20433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 20463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne protected void setBaseAttributes(TypedArray attributes, int widthAttr, int heightAttr) { 20473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.width = attributes.getLayoutDimension(widthAttr, DEFAULT_WIDTH); 20483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT); 20493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2051f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final void setRowSpecSpan(Interval span) { 205293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne rowSpec = rowSpec.copyWriteSpan(span); 20533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2055f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final void setColumnSpecSpan(Interval span) { 205693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne columnSpec = columnSpec.copyWriteSpan(span); 20573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2058d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2059d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne @Override 2060d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne public boolean equals(Object o) { 2061d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (this == o) return true; 2062d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (o == null || getClass() != o.getClass()) return false; 2063d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2064d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne LayoutParams that = (LayoutParams) o; 2065d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2066d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (!columnSpec.equals(that.columnSpec)) return false; 2067d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne if (!rowSpec.equals(that.rowSpec)) return false; 2068d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2069d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne return true; 2070d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 2071d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne 2072d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne @Override 2073d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne public int hashCode() { 2074d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne int result = rowSpec.hashCode(); 2075d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne result = 31 * result + columnSpec.hashCode(); 2076d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne return result; 2077d7dd89095ff2041f0793317c4ee8e8be49388148Philip Milne } 20783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2080aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 2081aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs. 2082aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles. 2083aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 2084f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class Arc { 20853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final Interval span; 2086aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public final MutableInt value; 208748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public boolean valid = true; 20883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2089aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne public Arc(Interval span, MutableInt value) { 20903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.span = span; 20913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.value = value; 20923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 20943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 20953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public String toString() { 209648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return span + " " + (!valid ? "+>" : "->") + " " + value; 20973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 20993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // A mutable Integer - used to avoid heap allocation during the layout operation 21013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2102f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class MutableInt { 21033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int value; 21043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2105f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public MutableInt() { 21063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne reset(); 21073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2109f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public MutableInt(int value) { 21103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.value = value; 21113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2113f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public void reset() { 21143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne value = Integer.MIN_VALUE; 21153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 211648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 211748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne @Override 211848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public String toString() { 211948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return Integer.toString(value); 212048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 212148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 212248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 2123f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class Assoc<K, V> extends ArrayList<Pair<K, V>> { 212448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private final Class<K> keyType; 212548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private final Class<V> valueType; 212648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 212748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne private Assoc(Class<K> keyType, Class<V> valueType) { 212848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne this.keyType = keyType; 212948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne this.valueType = valueType; 213048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 213148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 2132f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) { 213348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return new Assoc<K, V>(keyType, valueType); 213448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 213548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 213648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public void put(K key, V value) { 213748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne add(Pair.create(key, value)); 213848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 213948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 214048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne @SuppressWarnings(value = "unchecked") 214148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne public PackedMap<K, V> pack() { 214248b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne int N = size(); 214348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne K[] keys = (K[]) Array.newInstance(keyType, N); 214448b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne V[] values = (V[]) Array.newInstance(valueType, N); 214548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne for (int i = 0; i < N; i++) { 214648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne keys[i] = get(i).first; 214748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne values[i] = get(i).second; 214848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 214948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return new PackedMap<K, V>(keys, values); 215048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 21513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2153aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 2154aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This data structure is used in place of a Map where we have an index that refers to the order 2155aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne in which each key/value pairs were added to the map. In this case we store keys and values 2156aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne in arrays of a length that is equal to the number of unique keys. We also maintain an 2157aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne array of indexes from insertion order to the compacted arrays of keys and values. 2158aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2159aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Note that behavior differs from that of a LinkedHashMap in that repeated entries 2160aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne *do* get added multiples times. So the length of index is equals to the number of 2161aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne items added. 2162aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2163aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne This is useful in the GridLayout class where we can rely on the order of children not 2164aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne changing during layout - to use integer-based lookup for our internal structures 2165aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne rather than using (and storing) an implementation of Map<Key, ?>. 2166aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 21673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @SuppressWarnings(value = "unchecked") 2168f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class PackedMap<K, V> { 21693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final int[] index; 21703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final K[] keys; 21713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final V[] values; 21723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private PackedMap(K[] keys, V[] values) { 21743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.index = createIndex(keys); 21753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2176aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne this.keys = compact(keys, index); 2177aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne this.values = compact(values, index); 21783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2180f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne public V getValue(int i) { 21813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return values[index[i]]; 21823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private static <K> int[] createIndex(K[] keys) { 21853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int size = keys.length; 21863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int[] result = new int[size]; 21873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 21883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Map<K, Integer> keyToIndex = new HashMap<K, Integer>(); 21893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < size; i++) { 21903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne K key = keys[i]; 21913f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Integer index = keyToIndex.get(key); 21923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (index == null) { 21933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne index = keyToIndex.size(); 21943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne keyToIndex.put(key, index); 21953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21963f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result[i] = index; 21973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 21983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 21993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2201aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 2202aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Create a compact array of keys or values using the supplied index. 2203aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 2204aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne private static <K> K[] compact(K[] a, int[] index) { 2205aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne int size = a.length; 2206aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne Class<?> componentType = a.getClass().getComponentType(); 220751f17d54613c33638c8a2da8affcd9ba35994cb3Philip Milne K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1); 22083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne // this overwrite duplicates, retaining the last equivalent entry 22103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne for (int i = 0; i < size; i++) { 2211aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne result[index[i]] = a[i]; 22123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 22143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2217aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne /* 221893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne For each group (with a given alignment) we need to store the amount of space required 22197fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne before the alignment point and the amount of space required after it. One side of this 222047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio calculation is always 0 for START and END alignments but we don't make use of this. 2221aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no 2222aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne simple optimisations are possible. 2223aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 2224aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne The general algorithm therefore is to create a Map (actually a PackedMap) from 222593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne group to Bounds and to loop through all Views in the group taking the maximum 2226aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne of the values for each View. 2227aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne */ 2228f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static class Bounds { 22297fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne public int before; 22307fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne public int after; 22315125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public int flexibility; // we're flexible iff all included specs are flexible 22323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne private Bounds() { 22343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne reset(); 22353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2237a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void reset() { 22387fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne before = Integer.MIN_VALUE; 22397fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne after = Integer.MIN_VALUE; 22405125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne flexibility = CAN_STRETCH; // from the above, we're flexible when empty 22413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2243a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void include(int before, int after) { 22447fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne this.before = max(this.before, before); 22457fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne this.after = max(this.after, after); 22463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 224848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne protected int size(boolean min) { 22495d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne if (!min) { 22505125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne if (canStretch(flexibility)) { 22515d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne return MAX_SIZE; 22525d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 225348b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 22547fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne return before + after; 22553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22571557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) { 22587a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne return before - a.getAlignmentValue(c, size, gl.getLayoutMode()); 225948b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne } 226048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 22611557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne protected final void include(GridLayout gl, View c, Spec spec, Axis axis) { 22625125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne this.flexibility &= spec.getFlexibility(); 22631557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne boolean horizontal = axis.horizontal; 22641557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne int size = gl.getMeasurementIncludingMargin(c, horizontal); 22651557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne Alignment alignment = gl.getAlignment(spec.alignment, horizontal); 22664c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne // todo test this works correctly when the returned value is UNDEFINED 22677a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode()); 226848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne include(before, size - before); 2269a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2270a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 22713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 22723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public String toString() { 22733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return "Bounds{" + 22747fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne "before=" + before + 22757fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne ", after=" + after + 22763f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne '}'; 22773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 22793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 22803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 22813f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * An Interval represents a contiguous range of values that lie between 22823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * the interval's {@link #min} and {@link #max} values. 22833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 22843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Intervals are immutable so may be passed as values and used as keys in hash tables. 22853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * It is not necessary to have multiple instances of Intervals which have the same 22863f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * {@link #min} and {@link #max} values. 22873f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 22887fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Intervals are often written as {@code [min, max]} and represent the set of values 22897fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code x} such that {@code min <= x < max}. 22903f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2291f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final static class Interval { 22923f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 22933f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The minimum value. 22943f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 22953f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final int min; 2296aa616f31fe7c0c8e3657bb9a5889ec5e56ee5232Philip Milne 22973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 22983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The maximum value. 22993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 23003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public final int max; 23013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 23037fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Construct a new Interval, {@code interval}, where: 23043f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <ul> 23057fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <li> {@code interval.min = min} </li> 23067fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * <li> {@code interval.max = max} </li> 23073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * </ul> 23083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 23093f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @param min the minimum value. 23103f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @param max the maximum value. 23113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 23123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public Interval(int min, int max) { 23133f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.min = min; 23143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne this.max = max; 23153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2317f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne int size() { 23183f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return max - min; 23193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2321f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne Interval inverse() { 23223f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return new Interval(max, min); 23233f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23243f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 23267fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * Returns {@code true} if the {@link #getClass class}, 23277fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@link #min} and {@link #max} properties of this Interval and the 23287fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * supplied parameter are pairwise equal; {@code false} otherwise. 23293f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 23307fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * @param that the object to compare this interval with 23313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 23323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return {@code true} if the specified object is equal to this 23337fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code Interval}, {@code false} otherwise. 23343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 23353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 23363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean equals(Object that) { 23373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (this == that) { 23383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 23393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (that == null || getClass() != that.getClass()) { 23413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 23423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne Interval interval = (Interval) that; 23453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (max != interval.max) { 23473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 23483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23494c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne //noinspection RedundantIfStatement 23503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (min != interval.min) { 23513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 23523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 23553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 23583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int hashCode() { 23593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int result = min; 23603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result = 31 * result + max; 23613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 23623f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 23643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 23653f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public String toString() { 23663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return "[" + min + ", " + max + "]"; 23673f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 23693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2370899d5922870c78e0e663bc5661849eb468afc984Philip Milne /** 2371899d5922870c78e0e663bc5661849eb468afc984Philip Milne * A Spec defines the horizontal or vertical characteristics of a group of 23724a145d72622772b920f60195e80942058984259cPhilip Milne * cells. Each spec. defines the <em>grid indices</em> and <em>alignment</em> 23734a145d72622772b920f60195e80942058984259cPhilip Milne * along the appropriate axis. 2374899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p> 2375899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The <em>grid indices</em> are the leading and trailing edges of this cell group. 2376899d5922870c78e0e663bc5661849eb468afc984Philip Milne * See {@link GridLayout} for a description of the conventions used by GridLayout 2377899d5922870c78e0e663bc5661849eb468afc984Philip Milne * for grid indices. 2378899d5922870c78e0e663bc5661849eb468afc984Philip Milne * <p> 2379899d5922870c78e0e663bc5661849eb468afc984Philip Milne * The <em>alignment</em> property specifies how cells should be aligned in this group. 2380899d5922870c78e0e663bc5661849eb468afc984Philip Milne * For row groups, this specifies the vertical alignment. 2381899d5922870c78e0e663bc5661849eb468afc984Philip Milne * For column groups, this specifies the horizontal alignment. 23824a145d72622772b920f60195e80942058984259cPhilip Milne * <p> 23834a145d72622772b920f60195e80942058984259cPhilip Milne * Use the following static methods to create specs: 23844a145d72622772b920f60195e80942058984259cPhilip Milne * <ul> 23854a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int)}</li> 23864a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int, int)}</li> 23874a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int, Alignment)}</li> 23884a145d72622772b920f60195e80942058984259cPhilip Milne * <li>{@link #spec(int, int, Alignment)}</li> 23894a145d72622772b920f60195e80942058984259cPhilip Milne * </ul> 23904a145d72622772b920f60195e80942058984259cPhilip Milne * 2391899d5922870c78e0e663bc5661849eb468afc984Philip Milne */ 239293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public static class Spec { 2393f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final Spec UNDEFINED = spec(GridLayout.UNDEFINED); 2394f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne 2395f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final boolean startDefined; 239648b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne final Interval span; 239793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne final Alignment alignment; 23983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2399f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private Spec(boolean startDefined, Interval span, Alignment alignment) { 2400f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this.startDefined = startDefined; 24015d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne this.span = span; 24025d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne this.alignment = alignment; 24035d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 24045d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 2405f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne private Spec(boolean startDefined, int start, int size, Alignment alignment) { 2406f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne this(startDefined, new Interval(start, start + size), alignment); 24073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24083f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2409f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec copyWriteSpan(Interval span) { 2410f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return new Spec(startDefined, span, alignment); 24113f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24123f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2413f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final Spec copyWriteAlignment(Alignment alignment) { 2414f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return new Spec(startDefined, span, alignment); 24155125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 24165125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 2417f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne final int getFlexibility() { 24184c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH; 24193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24203f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24213f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 242293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Returns {@code true} if the {@code class}, {@code alignment} and {@code span} 242393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * properties of this Spec and the supplied parameter are pairwise equal, 24247fd948756947506db62a2bafca2ed45ff53ac0a0Philip Milne * {@code false} otherwise. 24253f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 242693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param that the object to compare this spec with 24273f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 24283f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @return {@code true} if the specified object is equal to this 242993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@code Spec}; {@code false} otherwise 24303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 24313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 24323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public boolean equals(Object that) { 24333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (this == that) { 24343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 24353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne if (that == null || getClass() != that.getClass()) { 24373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 24383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 244093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne Spec spec = (Spec) that; 24413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 244293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne if (!alignment.equals(spec.alignment)) { 24433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 24443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24454c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne //noinspection RedundantIfStatement 244693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne if (!span.equals(spec.span)) { 24473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return false; 24483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24503f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return true; 24513f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24523f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24533f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne @Override 24543f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public int hashCode() { 24553f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int result = span.hashCode(); 24563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne result = 31 * result + alignment.hashCode(); 24573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return result; 24583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 24603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 24613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 246293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Return a Spec, {@code spec}, where: 246393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <ul> 246493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.span = [start, start + size]} </li> 246593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.alignment = alignment} </li> 246693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * </ul> 24677b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * <p> 24687b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * To leave the start index undefined, use the value {@link #UNDEFINED}. 246993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * 247093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param start the start 247193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param size the size 247293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param alignment the alignment 247393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne */ 247493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public static Spec spec(int start, int size, Alignment alignment) { 2475f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne return new Spec(start != UNDEFINED, start, size, alignment); 247693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne } 247793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne 247893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne /** 247993cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * Return a Spec, {@code spec}, where: 248093cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <ul> 248193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.span = [start, start + 1]} </li> 248293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * <li> {@code spec.alignment = alignment} </li> 248393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * </ul> 24847b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * <p> 24857b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * To leave the start index undefined, use the value {@link #UNDEFINED}. 248693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * 248793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param start the start index 248893cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * @param alignment the alignment 24897b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * 24907b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * @see #spec(int, int, Alignment) 249193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne */ 249293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne public static Spec spec(int start, Alignment alignment) { 249393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne return spec(start, 1, alignment); 249493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne } 249593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne 249693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne /** 24975125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * Return a Spec, {@code spec}, where: 24985125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <ul> 24995125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <li> {@code spec.span = [start, start + size]} </li> 25005125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * </ul> 25017b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * <p> 25027b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * To leave the start index undefined, use the value {@link #UNDEFINED}. 25035125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * 25045125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * @param start the start 25055125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * @param size the size 25067b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * 25077b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * @see #spec(int, Alignment) 25085125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne */ 25095125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public static Spec spec(int start, int size) { 25105125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return spec(start, size, UNDEFINED_ALIGNMENT); 25115125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 25125125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 25135125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne /** 25145125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * Return a Spec, {@code spec}, where: 25155125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <ul> 25165125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * <li> {@code spec.span = [start, start + 1]} </li> 25175125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * </ul> 25187b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * <p> 25197b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * To leave the start index undefined, use the value {@link #UNDEFINED}. 25205125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * 25215125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne * @param start the start index 25227b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * 25237b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne * @see #spec(int, int) 25245125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne */ 25255125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne public static Spec spec(int start) { 25265125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return spec(start, 1); 25275125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 25285125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 25295125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne /** 25303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Alignments specify where a view should be placed within a cell group and 25313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * what size it should be. 25323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 253393cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec} 253493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an 253593cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@code alignment}. Overall placement of the view in the cell 25363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * group is specified by the two alignments which act along each axis independently. 25373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 2538a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne * The GridLayout class defines the most common alignments used in general layout: 25396216e87fe8ad3273855233965b34049d22763e94Philip Milne * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #START}, 25406216e87fe8ad3273855233965b34049d22763e94Philip Milne * {@link #END}, {@link #CENTER}, {@link #BASELINE} and {@link #FILL}. 2541a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne */ 2542a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne /* 2543c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)}, 25443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * to return the appropriate value for the type of alignment being defined. 25453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * The enclosing algorithms position the children 25461e54825135a7ccde421aa7fc400ab69e9348b5d6Philip Milne * so that the locations defined by the alignment values 25473f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * are the same for all of the views in a group. 25483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * <p> 25493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2550c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public static abstract class Alignment { 255148b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Alignment() { 2552a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2553a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 25546216e87fe8ad3273855233965b34049d22763e94Philip Milne abstract int getGravityOffset(View view, int cellDelta); 25556216e87fe8ad3273855233965b34049d22763e94Philip Milne 25563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 25573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns an alignment value. In the case of vertical alignments the value 25583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * returned should indicate the distance from the top of the view to the 25593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * alignment location. 25603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * For horizontal alignments measurement is made from the left edge of the component. 25613f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 2562c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param view the view to which this alignment should be applied 2563c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param viewSize the measured size of the view 25647a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne * @param mode the basis of alignment: CLIP or OPTICAL 2565b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne * @return the alignment value 25663f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 25677a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne abstract int getAlignmentValue(View view, int viewSize, int mode); 25683f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 25693f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 25703f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Returns the size of the view specified by this alignment. 25713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * In the case of vertical alignments this method should return a height; for 25723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * horizontal alignments this method should return the width. 2573c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * <p> 2574c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * The default implementation returns {@code viewSize}. 2575c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * 2576c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param view the view to which this alignment should be applied 2577c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param viewSize the measured size of the view 2578c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne * @param cellSize the size of the cell into which this view will be placed 2579b3a8c54389c9be2b37c5524ad8eb3112054221a7Philip Milne * @return the aligned size 25803f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 25816216e87fe8ad3273855233965b34049d22763e94Philip Milne int getSizeInCell(View view, int viewSize, int cellSize) { 25823f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return viewSize; 25833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 2584a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 258548b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne Bounds getBounds() { 2586a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne return new Bounds(); 2587a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 25883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 25893f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2590f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static final Alignment UNDEFINED_ALIGNMENT = new Alignment() { 259147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 25926216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 25936216e87fe8ad3273855233965b34049d22763e94Philip Milne return UNDEFINED; 25946216e87fe8ad3273855233965b34049d22763e94Philip Milne } 25956216e87fe8ad3273855233965b34049d22763e94Philip Milne 25966216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 25977a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 25985125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne return UNDEFINED; 25995125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne } 26005125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne }; 26015125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne 260247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio /** 260347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>start</em> 260447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * edges of the other views in its cell group. 260547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio */ 2606c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne private static final Alignment LEADING = new Alignment() { 260747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 26086216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 26096216e87fe8ad3273855233965b34049d22763e94Philip Milne return 0; 26106216e87fe8ad3273855233965b34049d22763e94Philip Milne } 26116216e87fe8ad3273855233965b34049d22763e94Philip Milne 26126216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 26137a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 26143f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return 0; 26153f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 26163f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 26173f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 261847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio /** 261947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>end</em> 262047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * edges of the other views in its cell group. 262147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio */ 2622c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne private static final Alignment TRAILING = new Alignment() { 262347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 26246216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 26256216e87fe8ad3273855233965b34049d22763e94Philip Milne return cellDelta; 26266216e87fe8ad3273855233965b34049d22763e94Philip Milne } 26276216e87fe8ad3273855233965b34049d22763e94Philip Milne 26286216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 26297a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 26303f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return viewSize; 26313f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 26323f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 26333f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 26343f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 26353f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>top</em> 26363f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 26373f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 26383f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment TOP = LEADING; 26393f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 26403f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 26413f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>bottom</em> 26423f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 26433f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 26443f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment BOTTOM = TRAILING; 26453f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 26463f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 264747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>start</em> 26483f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 26493f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 265047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio public static final Alignment START = LEADING; 265147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio 265247d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio /** 265347d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>end</em> 265447d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * edges of the other views in its cell group. 265547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio */ 265647d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio public static final Alignment END = TRAILING; 265747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio 26586216e87fe8ad3273855233965b34049d22763e94Philip Milne private static Alignment createSwitchingAlignment(final Alignment ltr, final Alignment rtl) { 265947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio return new Alignment() { 266047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 26616216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 26626216e87fe8ad3273855233965b34049d22763e94Philip Milne return (!view.isLayoutRtl() ? ltr : rtl).getGravityOffset(view, cellDelta); 26636216e87fe8ad3273855233965b34049d22763e94Philip Milne } 26646216e87fe8ad3273855233965b34049d22763e94Philip Milne 26656216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 26667a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 26677a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne return (!view.isLayoutRtl() ? ltr : rtl).getAlignmentValue(view, viewSize, mode); 266847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio } 266947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio }; 267047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio } 26713f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 26723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 26733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>left</em> 26743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * edges of the other views in its cell group. 26753f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 26766216e87fe8ad3273855233965b34049d22763e94Philip Milne public static final Alignment LEFT = createSwitchingAlignment(START, END); 267747d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio 267847d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio /** 267947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * Indicates that a view should be aligned with the <em>right</em> 268047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio * edges of the other views in its cell group. 268147d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio */ 26826216e87fe8ad3273855233965b34049d22763e94Philip Milne public static final Alignment RIGHT = createSwitchingAlignment(END, START); 26833f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 26843f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 26853f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be <em>centered</em> with the other views in its cell group. 268693cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link 268793cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * LayoutParams#columnSpec columnSpecs}. 26883f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2689c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public static final Alignment CENTER = new Alignment() { 269047d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 26916216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 26926216e87fe8ad3273855233965b34049d22763e94Philip Milne return cellDelta >> 1; 26936216e87fe8ad3273855233965b34049d22763e94Philip Milne } 26946216e87fe8ad3273855233965b34049d22763e94Philip Milne 26956216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 26967a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 26973f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return viewSize >> 1; 26983f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 26993f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 27003f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 27013f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 27023f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should be aligned with the <em>baselines</em> 27033f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * of the other views in its cell group. 270493cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}. 27053f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * 27063f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * @see View#getBaseline() 27073f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 2708c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne public static final Alignment BASELINE = new Alignment() { 270947d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 27106216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 27116216e87fe8ad3273855233965b34049d22763e94Philip Milne return 0; // baseline gravity is top 27126216e87fe8ad3273855233965b34049d22763e94Philip Milne } 27136216e87fe8ad3273855233965b34049d22763e94Philip Milne 27146216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 27157a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 2716a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne if (view.getVisibility() == GONE) { 2717a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne return 0; 2718a841644367772f51d4ac5f2af2a14cc2d0e36df1Philip Milne } 27193f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne int baseline = view.getBaseline(); 27207b7578184567f4e4f0740ce935cc192765410ccaPhilip Milne return baseline == -1 ? UNDEFINED : baseline; 2721a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2722a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2723a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 2724a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne public Bounds getBounds() { 2725a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne return new Bounds() { 2726a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne /* 2727a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne In a baseline aligned row in which some components define a baseline 2728a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne and some don't, we need a third variable to properly account for all 2729a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne the sizes. This tracks the maximum size of all the components - 2730a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne including those that don't define a baseline. 2731a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne */ 2732a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne private int size; 2733a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2734a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 2735a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void reset() { 2736a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne super.reset(); 273748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne size = Integer.MIN_VALUE; 2738a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2739a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2740a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 2741a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne protected void include(int before, int after) { 2742a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne super.include(before, after); 2743a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne size = max(size, before + after); 2744a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2745a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2746a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 274748b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne protected int size(boolean min) { 274848b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne return max(super.size(min), size); 2749a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2750a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne 2751a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne @Override 27521557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) { 27531557fd7809078e421f751efc7d2539b3efdc54b2Philip Milne return max(0, super.getOffset(gl, c, a, size, hrz)); 2754a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne } 2755a1f7b10f7299b40ee3a4e5e309882ea1a931cd5ePhilip Milne }; 27563f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 27573f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 27583f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 27593f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne /** 27603f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne * Indicates that a view should expanded to fit the boundaries of its cell group. 276193cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and 276293cd6a6c78683643de51f9e698b38847bd1f1155Philip Milne * {@link LayoutParams#columnSpec columnSpecs}. 27633f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne */ 27643f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne public static final Alignment FILL = new Alignment() { 276547d248eb438674ab0ca10154f3ff5e88f4ed70b7Fabrice Di Meglio @Override 27666216e87fe8ad3273855233965b34049d22763e94Philip Milne int getGravityOffset(View view, int cellDelta) { 27676216e87fe8ad3273855233965b34049d22763e94Philip Milne return 0; 27686216e87fe8ad3273855233965b34049d22763e94Philip Milne } 27696216e87fe8ad3273855233965b34049d22763e94Philip Milne 27706216e87fe8ad3273855233965b34049d22763e94Philip Milne @Override 27717a23b49a8ceb07d3fa12c45fd42cd16131fd746aPhilip Milne public int getAlignmentValue(View view, int viewSize, int mode) { 27723f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return UNDEFINED; 27733f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 27743f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne 2775c9885f6557dc1c96e2cc2c1a86fba359f00f131cPhilip Milne @Override 27766216e87fe8ad3273855233965b34049d22763e94Philip Milne public int getSizeInCell(View view, int viewSize, int cellSize) { 27773f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne return cellSize; 27783f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne } 27793f8956d82bb40b15acee26017db0d13ddf43c80aPhilip Milne }; 278048b55244d286b6d4e3699a5d9e938a9c87aaae75Philip Milne 2781f6679c88d12e9f7e10e6884d4a8487673e53c097Philip Milne static boolean canStretch(int flexibility) { 27825d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne return (flexibility & CAN_STRETCH) != 0; 27835d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne } 27845d1a9840aaf57ae90716f0ac34abdcd09f7f4ed6Philip Milne 27855125e21bc0bbe5b9718d0f03b26cdafc67a7c726Philip Milne private static final int INFLEXIBLE = 0; 27864c8cf4c93314722a77ce69396b9cb201ac007a58Philip Milne private static final int CAN_STRETCH = 2; 2787452eec33d667f9e705b57e60948b070536fbc1b4Jim Miller} 2788