|
|
|
|
@@ -104,14 +104,16 @@ import static java.lang.Math.min;
|
|
|
|
|
*
|
|
|
|
|
* <h4>Excess Space Distribution</h4>
|
|
|
|
|
*
|
|
|
|
|
* GridLayout's distribution of excess space is based on <em>priority</em>
|
|
|
|
|
* rather than <em>weight</em>.
|
|
|
|
|
* As of API 21, GridLayout's distribution of excess space accomodates the principle of weight.
|
|
|
|
|
* In the event that no weights are specified, the previous conventions are respected and
|
|
|
|
|
* columns and rows are taken as flexible if their views specify some form of alignment
|
|
|
|
|
* within their groups.
|
|
|
|
|
* <p>
|
|
|
|
|
* A child's ability to stretch is inferred from the alignment properties of
|
|
|
|
|
* its row and column groups (which are typically set by setting the
|
|
|
|
|
* {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters).
|
|
|
|
|
* If alignment was defined along a given axis then the component
|
|
|
|
|
* is taken as <em>flexible</em> in that direction. If no alignment was set,
|
|
|
|
|
* The flexibility of a view is therefore influenced by its alignment which is,
|
|
|
|
|
* in turn, typically defined by setting the
|
|
|
|
|
* {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters.
|
|
|
|
|
* If either a weight or alignment were defined along a given axis then the component
|
|
|
|
|
* is taken as <em>flexible</em> in that direction. If no weight or alignment was set,
|
|
|
|
|
* the component is instead assumed to be <em>inflexible</em>.
|
|
|
|
|
* <p>
|
|
|
|
|
* Multiple components in the same row or column group are
|
|
|
|
|
@@ -122,12 +124,16 @@ import static java.lang.Math.min;
|
|
|
|
|
* elements is flexible if <em>one</em> of its elements is flexible.
|
|
|
|
|
* <p>
|
|
|
|
|
* To make a column stretch, make sure all of the components inside it define a
|
|
|
|
|
* gravity. To prevent a column from stretching, ensure that one of the components
|
|
|
|
|
* in the column does not define a gravity.
|
|
|
|
|
* weight or a gravity. To prevent a column from stretching, ensure that one of the components
|
|
|
|
|
* in the column does not define a weight or a gravity.
|
|
|
|
|
* <p>
|
|
|
|
|
* When the principle of flexibility does not provide complete disambiguation,
|
|
|
|
|
* GridLayout's algorithms favour rows and columns that are closer to its <em>right</em>
|
|
|
|
|
* and <em>bottom</em> edges.
|
|
|
|
|
* and <em>bottom</em> edges. To be more precise, GridLayout treats each of its layout
|
|
|
|
|
* parameters as a constraint in the a set of variables that define the grid-lines along a
|
|
|
|
|
* given axis. During layout, GridLayout solves the constraints so as to return the unique
|
|
|
|
|
* solution to those constraints for which all variables are less-than-or-equal-to
|
|
|
|
|
* the corresponding value in any other valid solution.
|
|
|
|
|
*
|
|
|
|
|
* <h4>Interpretation of GONE</h4>
|
|
|
|
|
*
|
|
|
|
|
@@ -140,18 +146,6 @@ import static java.lang.Math.min;
|
|
|
|
|
* had never been added to it.
|
|
|
|
|
* These statements apply equally to rows as well as columns, and to groups of rows or columns.
|
|
|
|
|
*
|
|
|
|
|
* <h5>Limitations</h5>
|
|
|
|
|
*
|
|
|
|
|
* GridLayout does not provide support for the principle of <em>weight</em>, as defined in
|
|
|
|
|
* {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible
|
|
|
|
|
* to configure a GridLayout to distribute excess space between multiple components.
|
|
|
|
|
* <p>
|
|
|
|
|
* Some common use-cases may nevertheless be accommodated as follows.
|
|
|
|
|
* To place equal amounts of space around a component in a cell group;
|
|
|
|
|
* use {@link #CENTER} alignment (or {@link LayoutParams#setGravity(int) gravity}).
|
|
|
|
|
* For complete control over excess space distribution in a row or column;
|
|
|
|
|
* use a {@link LinearLayout} subview to hold the components in the associated cell group.
|
|
|
|
|
* When using either of these techniques, bear in mind that cell groups may be defined to overlap.
|
|
|
|
|
* <p>
|
|
|
|
|
* See {@link GridLayout.LayoutParams} for a full description of the
|
|
|
|
|
* layout parameters used by GridLayout.
|
|
|
|
|
@@ -1693,8 +1687,74 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
return trailingMargins;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void computeLocations(int[] a) {
|
|
|
|
|
private void solve(int[] a) {
|
|
|
|
|
solve(getArcs(), a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void resetDeltas() {
|
|
|
|
|
Bounds[] values = getGroupBounds().values;
|
|
|
|
|
for (int i = 0, N = values.length; i < N; i++) {
|
|
|
|
|
values[i].shareOfDelta = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean requiresWeightDistribution() {
|
|
|
|
|
Bounds[] values = getGroupBounds().values;
|
|
|
|
|
for (int i = 0, N = values.length; i < N; i++) {
|
|
|
|
|
if (values[i].weight != 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void shareOutDelta(int[] locations) {
|
|
|
|
|
PackedMap<Spec, Bounds> groupBounds = getGroupBounds();
|
|
|
|
|
Spec[] specs = groupBounds.keys;
|
|
|
|
|
Bounds[] bounds = groupBounds.values;
|
|
|
|
|
int totalDelta = 0;
|
|
|
|
|
float totalWeight = 0;
|
|
|
|
|
final int N = bounds.length;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
|
|
|
Spec spec = specs[i];
|
|
|
|
|
Bounds bound = bounds[i];
|
|
|
|
|
if (bound.weight != 0) {
|
|
|
|
|
int minSize = bound.size(true);
|
|
|
|
|
Interval span = spec.span;
|
|
|
|
|
int actualSize = locations[span.max] - locations[span.min];
|
|
|
|
|
int delta = actualSize - minSize;
|
|
|
|
|
totalDelta += delta;
|
|
|
|
|
totalWeight += bound.weight;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
|
|
|
Bounds bound = bounds[i];
|
|
|
|
|
float weight = bound.weight;
|
|
|
|
|
if (weight != 0) {
|
|
|
|
|
int delta = Math.round((weight * totalDelta / totalWeight));
|
|
|
|
|
bound.shareOfDelta = delta;
|
|
|
|
|
// the two adjustments below compensate for the rounding above
|
|
|
|
|
totalDelta -= delta;
|
|
|
|
|
totalWeight -= weight;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void solveAndDistributeSpace(int[] a) {
|
|
|
|
|
resetDeltas();
|
|
|
|
|
solve(a);
|
|
|
|
|
if (requiresWeightDistribution()) {
|
|
|
|
|
shareOutDelta(a);
|
|
|
|
|
arcsValid = false;
|
|
|
|
|
forwardLinksValid = false;
|
|
|
|
|
backwardLinksValid = false;
|
|
|
|
|
solve(a);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void computeLocations(int[] a) {
|
|
|
|
|
solveAndDistributeSpace(a);
|
|
|
|
|
if (!orderPreserved) {
|
|
|
|
|
// Solve returns the smallest solution to the constraint system for which all
|
|
|
|
|
// values are positive. One value is therefore zero - though if the row/col
|
|
|
|
|
@@ -1810,6 +1870,23 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
* both aspects of alignment within the cell group. It is also possible to specify a child's
|
|
|
|
|
* alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
|
|
|
|
|
* method.
|
|
|
|
|
* <p>
|
|
|
|
|
* The weight property is also included in Spec and specifies the proportion of any
|
|
|
|
|
* excess space that is due to the enclosing row or column.
|
|
|
|
|
* GridLayout's model of flexibility and weight is broadly based on the physical properties of
|
|
|
|
|
* systems of mechanical springs. For example, a column in a GridLayout is modeled as
|
|
|
|
|
* if a set of springs were attached in parallel at their ends. Columns are therefore
|
|
|
|
|
* flexible only if and only if all views inside them are flexible. Similarly, the combined
|
|
|
|
|
* weight of a column is defined as the <em>minimum</em> of the weights of the components it
|
|
|
|
|
* contains. So, if any one component in a column of components has a weight of zero,
|
|
|
|
|
* the entire group has a weight of zero and will not receive any of the
|
|
|
|
|
* excess space that GridLayout distributes in its second
|
|
|
|
|
* (internal) layout pass. The default weight of a component is zero,
|
|
|
|
|
* reflecting inflexibility, but the default weight of a column (with nothing in it)
|
|
|
|
|
* is effectively infinite, reflecting the fact that a parallel group of
|
|
|
|
|
* springs is infinitely flexible when it contains no springs.
|
|
|
|
|
* <p>
|
|
|
|
|
* The above comments apply equally to rows and groups of rows and columns.
|
|
|
|
|
*
|
|
|
|
|
* <h4>WRAP_CONTENT and MATCH_PARENT</h4>
|
|
|
|
|
*
|
|
|
|
|
@@ -1851,9 +1928,11 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
* <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li>
|
|
|
|
|
* <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li>
|
|
|
|
|
* <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li>
|
|
|
|
|
* <li>{@link #rowSpec}<code>.weight</code> = 0 </li>
|
|
|
|
|
* <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li>
|
|
|
|
|
* <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li>
|
|
|
|
|
* <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li>
|
|
|
|
|
* <li>{@link #columnSpec}<code>.weight</code> = 0 </li>
|
|
|
|
|
* </ul>
|
|
|
|
|
*
|
|
|
|
|
* See {@link GridLayout} for a more complete description of the conventions
|
|
|
|
|
@@ -1861,8 +1940,10 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
*
|
|
|
|
|
* @attr ref android.R.styleable#GridLayout_Layout_layout_row
|
|
|
|
|
* @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
|
|
|
|
|
* @attr ref android.R.styleable#GridLayout_Layout_layout_rowWeight
|
|
|
|
|
* @attr ref android.R.styleable#GridLayout_Layout_layout_column
|
|
|
|
|
* @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan
|
|
|
|
|
* @attr ref android.R.styleable#GridLayout_Layout_layout_columnWeight
|
|
|
|
|
* @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
|
|
|
|
|
*/
|
|
|
|
|
public static class LayoutParams extends MarginLayoutParams {
|
|
|
|
|
@@ -1889,9 +1970,11 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
|
|
|
|
|
private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
|
|
|
|
|
private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
|
|
|
|
|
private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight;
|
|
|
|
|
|
|
|
|
|
private static final int ROW = R.styleable.GridLayout_Layout_layout_row;
|
|
|
|
|
private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan;
|
|
|
|
|
private static final int ROW_WEIGHT = R.styleable.GridLayout_Layout_layout_rowWeight;
|
|
|
|
|
|
|
|
|
|
private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity;
|
|
|
|
|
|
|
|
|
|
@@ -2034,11 +2117,13 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
|
|
|
|
|
int column = a.getInt(COLUMN, DEFAULT_COLUMN);
|
|
|
|
|
int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
|
|
|
|
|
this.columnSpec = spec(column, colSpan, getAlignment(gravity, true));
|
|
|
|
|
float colWeight = a.getFloat(COLUMN_WEIGHT, Spec.DEFAULT_WEIGHT);
|
|
|
|
|
this.columnSpec = spec(column, colSpan, getAlignment(gravity, true), colWeight);
|
|
|
|
|
|
|
|
|
|
int row = a.getInt(ROW, DEFAULT_ROW);
|
|
|
|
|
int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
|
|
|
|
|
this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false));
|
|
|
|
|
float rowWeight = a.getFloat(ROW_WEIGHT, Spec.DEFAULT_WEIGHT);
|
|
|
|
|
this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false), rowWeight);
|
|
|
|
|
} finally {
|
|
|
|
|
a.recycle();
|
|
|
|
|
}
|
|
|
|
|
@@ -2244,6 +2329,8 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
public int before;
|
|
|
|
|
public int after;
|
|
|
|
|
public int flexibility; // we're flexible iff all included specs are flexible
|
|
|
|
|
public float weight; // the min of the weights of the individual specs
|
|
|
|
|
public int shareOfDelta;
|
|
|
|
|
|
|
|
|
|
private Bounds() {
|
|
|
|
|
reset();
|
|
|
|
|
@@ -2253,6 +2340,7 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
before = Integer.MIN_VALUE;
|
|
|
|
|
after = Integer.MIN_VALUE;
|
|
|
|
|
flexibility = CAN_STRETCH; // from the above, we're flexible when empty
|
|
|
|
|
weight = Float.MAX_VALUE; // default is large => row/cols take all slack when empty
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void include(int before, int after) {
|
|
|
|
|
@@ -2266,7 +2354,7 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
return MAX_SIZE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return before + after;
|
|
|
|
|
return before + after + shareOfDelta;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
|
|
|
|
|
@@ -2275,6 +2363,7 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
|
|
|
|
|
protected final void include(GridLayout gl, View c, Spec spec, Axis axis) {
|
|
|
|
|
this.flexibility &= spec.getFlexibility();
|
|
|
|
|
weight = Math.min(weight, spec.weight);
|
|
|
|
|
boolean horizontal = axis.horizontal;
|
|
|
|
|
int size = gl.getMeasurementIncludingMargin(c, horizontal);
|
|
|
|
|
Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
|
|
|
|
|
@@ -2401,36 +2490,43 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
* <li>{@link #spec(int, int)}</li>
|
|
|
|
|
* <li>{@link #spec(int, Alignment)}</li>
|
|
|
|
|
* <li>{@link #spec(int, int, Alignment)}</li>
|
|
|
|
|
* <li>{@link #spec(int, float)}</li>
|
|
|
|
|
* <li>{@link #spec(int, int, float)}</li>
|
|
|
|
|
* <li>{@link #spec(int, Alignment, float)}</li>
|
|
|
|
|
* <li>{@link #spec(int, int, Alignment, float)}</li>
|
|
|
|
|
* </ul>
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
public static class Spec {
|
|
|
|
|
static final Spec UNDEFINED = spec(GridLayout.UNDEFINED);
|
|
|
|
|
static final float DEFAULT_WEIGHT = 0;
|
|
|
|
|
|
|
|
|
|
final boolean startDefined;
|
|
|
|
|
final Interval span;
|
|
|
|
|
final Alignment alignment;
|
|
|
|
|
final float weight;
|
|
|
|
|
|
|
|
|
|
private Spec(boolean startDefined, Interval span, Alignment alignment) {
|
|
|
|
|
private Spec(boolean startDefined, Interval span, Alignment alignment, float weight) {
|
|
|
|
|
this.startDefined = startDefined;
|
|
|
|
|
this.span = span;
|
|
|
|
|
this.alignment = alignment;
|
|
|
|
|
this.weight = weight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Spec(boolean startDefined, int start, int size, Alignment alignment) {
|
|
|
|
|
this(startDefined, new Interval(start, start + size), alignment);
|
|
|
|
|
private Spec(boolean startDefined, int start, int size, Alignment alignment, float weight) {
|
|
|
|
|
this(startDefined, new Interval(start, start + size), alignment, weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final Spec copyWriteSpan(Interval span) {
|
|
|
|
|
return new Spec(startDefined, span, alignment);
|
|
|
|
|
return new Spec(startDefined, span, alignment, weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final Spec copyWriteAlignment(Alignment alignment) {
|
|
|
|
|
return new Spec(startDefined, span, alignment);
|
|
|
|
|
return new Spec(startDefined, span, alignment, weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final int getFlexibility() {
|
|
|
|
|
return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH;
|
|
|
|
|
return (alignment == UNDEFINED_ALIGNMENT && weight == 0) ? INFLEXIBLE : CAN_STRETCH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -2478,6 +2574,7 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
* <ul>
|
|
|
|
|
* <li> {@code spec.span = [start, start + size]} </li>
|
|
|
|
|
* <li> {@code spec.alignment = alignment} </li>
|
|
|
|
|
* <li> {@code spec.weight = weight} </li>
|
|
|
|
|
* </ul>
|
|
|
|
|
* <p>
|
|
|
|
|
* To leave the start index undefined, use the value {@link #UNDEFINED}.
|
|
|
|
|
@@ -2485,9 +2582,55 @@ public class GridLayout extends ViewGroup {
|
|
|
|
|
* @param start the start
|
|
|
|
|
* @param size the size
|
|
|
|
|
* @param alignment the alignment
|
|
|
|
|
* @param weight the weight
|
|
|
|
|
*/
|
|
|
|
|
public static Spec spec(int start, int size, Alignment alignment, float weight) {
|
|
|
|
|
return new Spec(start != UNDEFINED, start, size, alignment, weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Equivalent to: {@code spec(start, 1, alignment, weight)}.
|
|
|
|
|
*
|
|
|
|
|
* @param start the start
|
|
|
|
|
* @param alignment the alignment
|
|
|
|
|
* @param weight the weight
|
|
|
|
|
*/
|
|
|
|
|
public static Spec spec(int start, Alignment alignment, float weight) {
|
|
|
|
|
return spec(start, 1, alignment, weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Equivalent to: {@code spec(start, 1, default_alignment, weight)} -
|
|
|
|
|
* where {@code default_alignment} is specified in
|
|
|
|
|
* {@link android.widget.GridLayout.LayoutParams}.
|
|
|
|
|
*
|
|
|
|
|
* @param start the start
|
|
|
|
|
* @param size the size
|
|
|
|
|
* @param weight the weight
|
|
|
|
|
*/
|
|
|
|
|
public static Spec spec(int start, int size, float weight) {
|
|
|
|
|
return spec(start, size, UNDEFINED_ALIGNMENT, weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Equivalent to: {@code spec(start, 1, weight)}.
|
|
|
|
|
*
|
|
|
|
|
* @param start the start
|
|
|
|
|
* @param weight the weight
|
|
|
|
|
*/
|
|
|
|
|
public static Spec spec(int start, float weight) {
|
|
|
|
|
return spec(start, 1, weight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Equivalent to: {@code spec(start, size, alignment, 0f)}.
|
|
|
|
|
*
|
|
|
|
|
* @param start the start
|
|
|
|
|
* @param size the size
|
|
|
|
|
* @param alignment the alignment
|
|
|
|
|
*/
|
|
|
|
|
public static Spec spec(int start, int size, Alignment alignment) {
|
|
|
|
|
return new Spec(start != UNDEFINED, start, size, alignment);
|
|
|
|
|
return spec(start, size, alignment, Spec.DEFAULT_WEIGHT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|