blob: 8bb4d16fe7dfe02c1c3035ade24a7587c324838d [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.widget;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.content.Context;
20import android.content.res.TypedArray;
21import android.util.AttributeSet;
22import android.util.SparseBooleanArray;
23import android.view.View;
24import android.view.ViewGroup;
Aurimas Liutikas99441c52016-10-11 16:48:32 -070025
26import com.android.internal.R;
27
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import java.util.regex.Pattern;
29
30/**
31 * <p>A layout that arranges its children into rows and columns.
32 * A TableLayout consists of a number of {@link android.widget.TableRow} objects,
33 * each defining a row (actually, you can have other children, which will be
34 * explained below). TableLayout containers do not display border lines for
35 * their rows, columns, or cells. Each row has zero or more cells; each cell can
36 * hold one {@link android.view.View View} object. The table has as many columns
37 * as the row with the most cells. A table can leave cells empty. Cells can span
38 * columns, as they can in HTML.</p>
39 *
40 * <p>The width of a column is defined by the row with the widest cell in that
41 * column. However, a TableLayout can specify certain columns as shrinkable or
42 * stretchable by calling
43 * {@link #setColumnShrinkable(int, boolean) setColumnShrinkable()}
44 * or {@link #setColumnStretchable(int, boolean) setColumnStretchable()}. If
45 * marked as shrinkable, the column width can be shrunk to fit the table into
46 * its parent object. If marked as stretchable, it can expand in width to fit
47 * any extra space. The total width of the table is defined by its parent
48 * container. It is important to remember that a column can be both shrinkable
49 * and stretchable. In such a situation, the column will change its size to
50 * always use up the available space, but never more. Finally, you can hide a
51 * column by calling
52 * {@link #setColumnCollapsed(int,boolean) setColumnCollapsed()}.</p>
53 *
54 * <p>The children of a TableLayout cannot specify the <code>layout_width</code>
Romain Guy980a9382010-01-08 15:06:28 -080055 * attribute. Width is always <code>MATCH_PARENT</code>. However, the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 * <code>layout_height</code> attribute can be defined by a child; default value
57 * is {@link android.widget.TableLayout.LayoutParams#WRAP_CONTENT}. If the child
58 * is a {@link android.widget.TableRow}, then the height is always
59 * {@link android.widget.TableLayout.LayoutParams#WRAP_CONTENT}.</p>
60 *
61 * <p> Cells must be added to a row in increasing column order, both in code and
62 * XML. Column numbers are zero-based. If you don't specify a column number for
63 * a child cell, it will autoincrement to the next available column. If you skip
64 * a column number, it will be considered an empty cell in that row. See the
65 * TableLayout examples in ApiDemos for examples of creating tables in XML.</p>
66 *
67 * <p>Although the typical child of a TableLayout is a TableRow, you can
68 * actually use any View subclass as a direct child of TableLayout. The View
69 * will be displayed as a single row that spans all the table columns.</p>
Scott Main41ec6532010-08-19 16:57:07 -070070 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 */
72public class TableLayout extends LinearLayout {
73 private int[] mMaxWidths;
74 private SparseBooleanArray mStretchableColumns;
75 private SparseBooleanArray mShrinkableColumns;
76 private SparseBooleanArray mCollapsedColumns;
77
78 private boolean mShrinkAllColumns;
79 private boolean mStretchAllColumns;
80
81 private TableLayout.PassThroughHierarchyChangeListener mPassThroughListener;
82
83 private boolean mInitialized;
84
85 /**
86 * <p>Creates a new TableLayout for the given context.</p>
87 *
88 * @param context the application environment
89 */
90 public TableLayout(Context context) {
91 super(context);
92 initTableLayout();
93 }
94
95 /**
96 * <p>Creates a new TableLayout for the given context and with the
97 * specified set attributes.</p>
98 *
99 * @param context the application environment
100 * @param attrs a collection of attributes
101 */
102 public TableLayout(Context context, AttributeSet attrs) {
103 super(context, attrs);
104
105 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TableLayout);
106
107 String stretchedColumns = a.getString(R.styleable.TableLayout_stretchColumns);
108 if (stretchedColumns != null) {
109 if (stretchedColumns.charAt(0) == '*') {
110 mStretchAllColumns = true;
111 } else {
112 mStretchableColumns = parseColumns(stretchedColumns);
113 }
114 }
115
116 String shrinkedColumns = a.getString(R.styleable.TableLayout_shrinkColumns);
117 if (shrinkedColumns != null) {
118 if (shrinkedColumns.charAt(0) == '*') {
119 mShrinkAllColumns = true;
120 } else {
121 mShrinkableColumns = parseColumns(shrinkedColumns);
122 }
123 }
124
125 String collapsedColumns = a.getString(R.styleable.TableLayout_collapseColumns);
126 if (collapsedColumns != null) {
127 mCollapsedColumns = parseColumns(collapsedColumns);
128 }
129
130 a.recycle();
131 initTableLayout();
132 }
133
134 /**
135 * <p>Parses a sequence of columns ids defined in a CharSequence with the
136 * following pattern (regex): \d+(\s*,\s*\d+)*</p>
137 *
138 * <p>Examples: "1" or "13, 7, 6" or "".</p>
139 *
140 * <p>The result of the parsing is stored in a sparse boolean array. The
141 * parsed column ids are used as the keys of the sparse array. The values
142 * are always true.</p>
143 *
144 * @param sequence a sequence of column ids, can be empty but not null
145 * @return a sparse array of boolean mapping column indexes to the columns
146 * collapse state
147 */
148 private static SparseBooleanArray parseColumns(String sequence) {
149 SparseBooleanArray columns = new SparseBooleanArray();
150 Pattern pattern = Pattern.compile("\\s*,\\s*");
151 String[] columnDefs = pattern.split(sequence);
152
153 for (String columnIdentifier : columnDefs) {
154 try {
155 int columnIndex = Integer.parseInt(columnIdentifier);
156 // only valid, i.e. positive, columns indexes are handled
157 if (columnIndex >= 0) {
158 // putting true in this sparse array indicates that the
159 // column index was defined in the XML file
160 columns.put(columnIndex, true);
161 }
162 } catch (NumberFormatException e) {
163 // we just ignore columns that don't exist
164 }
165 }
166
167 return columns;
168 }
169
170 /**
171 * <p>Performs initialization common to prorgrammatic use and XML use of
172 * this widget.</p>
173 */
174 private void initTableLayout() {
175 if (mCollapsedColumns == null) {
176 mCollapsedColumns = new SparseBooleanArray();
177 }
178 if (mStretchableColumns == null) {
179 mStretchableColumns = new SparseBooleanArray();
180 }
181 if (mShrinkableColumns == null) {
182 mShrinkableColumns = new SparseBooleanArray();
183 }
184
Adam Powellc3c0e392012-08-23 14:12:22 -0700185 // TableLayouts are always in vertical orientation; keep this tracked
186 // for shared LinearLayout code.
187 setOrientation(VERTICAL);
188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 mPassThroughListener = new PassThroughHierarchyChangeListener();
190 // make sure to call the parent class method to avoid potential
191 // infinite loops
192 super.setOnHierarchyChangeListener(mPassThroughListener);
193
194 mInitialized = true;
195 }
196
197 /**
198 * {@inheritDoc}
199 */
200 @Override
201 public void setOnHierarchyChangeListener(
202 OnHierarchyChangeListener listener) {
203 // the user listener is delegated to our pass-through listener
204 mPassThroughListener.mOnHierarchyChangeListener = listener;
205 }
206
207 private void requestRowsLayout() {
208 if (mInitialized) {
209 final int count = getChildCount();
210 for (int i = 0; i < count; i++) {
211 getChildAt(i).requestLayout();
212 }
213 }
214 }
215
216 /**
217 * {@inheritDoc}
218 */
219 @Override
220 public void requestLayout() {
221 if (mInitialized) {
222 int count = getChildCount();
223 for (int i = 0; i < count; i++) {
224 getChildAt(i).forceLayout();
225 }
226 }
227
228 super.requestLayout();
229 }
230
231 /**
232 * <p>Indicates whether all columns are shrinkable or not.</p>
233 *
234 * @return true if all columns are shrinkable, false otherwise
Philip Milne1018fb42012-03-13 12:00:04 -0700235 *
236 * @attr ref android.R.styleable#TableLayout_shrinkColumns
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 */
238 public boolean isShrinkAllColumns() {
239 return mShrinkAllColumns;
240 }
241
242 /**
243 * <p>Convenience method to mark all columns as shrinkable.</p>
244 *
245 * @param shrinkAllColumns true to mark all columns shrinkable
246 *
247 * @attr ref android.R.styleable#TableLayout_shrinkColumns
248 */
249 public void setShrinkAllColumns(boolean shrinkAllColumns) {
250 mShrinkAllColumns = shrinkAllColumns;
251 }
252
253 /**
254 * <p>Indicates whether all columns are stretchable or not.</p>
255 *
256 * @return true if all columns are stretchable, false otherwise
Philip Milne1018fb42012-03-13 12:00:04 -0700257 *
258 * @attr ref android.R.styleable#TableLayout_stretchColumns
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 */
260 public boolean isStretchAllColumns() {
261 return mStretchAllColumns;
262 }
263
264 /**
265 * <p>Convenience method to mark all columns as stretchable.</p>
266 *
267 * @param stretchAllColumns true to mark all columns stretchable
268 *
269 * @attr ref android.R.styleable#TableLayout_stretchColumns
270 */
271 public void setStretchAllColumns(boolean stretchAllColumns) {
272 mStretchAllColumns = stretchAllColumns;
273 }
274
275 /**
276 * <p>Collapses or restores a given column. When collapsed, a column
277 * does not appear on screen and the extra space is reclaimed by the
278 * other columns. A column is collapsed/restored only when it belongs to
279 * a {@link android.widget.TableRow}.</p>
280 *
281 * <p>Calling this method requests a layout operation.</p>
282 *
283 * @param columnIndex the index of the column
284 * @param isCollapsed true if the column must be collapsed, false otherwise
285 *
286 * @attr ref android.R.styleable#TableLayout_collapseColumns
287 */
288 public void setColumnCollapsed(int columnIndex, boolean isCollapsed) {
289 // update the collapse status of the column
290 mCollapsedColumns.put(columnIndex, isCollapsed);
291
292 int count = getChildCount();
293 for (int i = 0; i < count; i++) {
294 final View view = getChildAt(i);
295 if (view instanceof TableRow) {
296 ((TableRow) view).setColumnCollapsed(columnIndex, isCollapsed);
297 }
298 }
299
300 requestRowsLayout();
301 }
302
303 /**
304 * <p>Returns the collapsed state of the specified column.</p>
305 *
306 * @param columnIndex the index of the column
307 * @return true if the column is collapsed, false otherwise
308 */
309 public boolean isColumnCollapsed(int columnIndex) {
310 return mCollapsedColumns.get(columnIndex);
311 }
312
313 /**
314 * <p>Makes the given column stretchable or not. When stretchable, a column
315 * takes up as much as available space as possible in its row.</p>
316 *
317 * <p>Calling this method requests a layout operation.</p>
318 *
319 * @param columnIndex the index of the column
320 * @param isStretchable true if the column must be stretchable,
321 * false otherwise. Default is false.
322 *
323 * @attr ref android.R.styleable#TableLayout_stretchColumns
324 */
325 public void setColumnStretchable(int columnIndex, boolean isStretchable) {
326 mStretchableColumns.put(columnIndex, isStretchable);
327 requestRowsLayout();
328 }
329
330 /**
331 * <p>Returns whether the specified column is stretchable or not.</p>
332 *
333 * @param columnIndex the index of the column
334 * @return true if the column is stretchable, false otherwise
335 */
336 public boolean isColumnStretchable(int columnIndex) {
337 return mStretchAllColumns || mStretchableColumns.get(columnIndex);
338 }
339
340 /**
341 * <p>Makes the given column shrinkable or not. When a row is too wide, the
342 * table can reclaim extra space from shrinkable columns.</p>
343 *
344 * <p>Calling this method requests a layout operation.</p>
345 *
346 * @param columnIndex the index of the column
347 * @param isShrinkable true if the column must be shrinkable,
348 * false otherwise. Default is false.
349 *
350 * @attr ref android.R.styleable#TableLayout_shrinkColumns
351 */
352 public void setColumnShrinkable(int columnIndex, boolean isShrinkable) {
353 mShrinkableColumns.put(columnIndex, isShrinkable);
354 requestRowsLayout();
355 }
356
357 /**
358 * <p>Returns whether the specified column is shrinkable or not.</p>
359 *
360 * @param columnIndex the index of the column
361 * @return true if the column is shrinkable, false otherwise. Default is false.
362 */
363 public boolean isColumnShrinkable(int columnIndex) {
364 return mShrinkAllColumns || mShrinkableColumns.get(columnIndex);
365 }
366
367 /**
368 * <p>Applies the columns collapse status to a new row added to this
369 * table. This method is invoked by PassThroughHierarchyChangeListener
370 * upon child insertion.</p>
371 *
372 * <p>This method only applies to {@link android.widget.TableRow}
373 * instances.</p>
374 *
375 * @param child the newly added child
376 */
377 private void trackCollapsedColumns(View child) {
378 if (child instanceof TableRow) {
379 final TableRow row = (TableRow) child;
380 final SparseBooleanArray collapsedColumns = mCollapsedColumns;
381 final int count = collapsedColumns.size();
382 for (int i = 0; i < count; i++) {
383 int columnIndex = collapsedColumns.keyAt(i);
384 boolean isCollapsed = collapsedColumns.valueAt(i);
385 // the collapse status is set only when the column should be
386 // collapsed; otherwise, this might affect the default
387 // visibility of the row's children
388 if (isCollapsed) {
389 row.setColumnCollapsed(columnIndex, isCollapsed);
390 }
391 }
392 }
393 }
394
395 /**
396 * {@inheritDoc}
397 */
398 @Override
399 public void addView(View child) {
400 super.addView(child);
401 requestRowsLayout();
402 }
403
404 /**
405 * {@inheritDoc}
406 */
407 @Override
408 public void addView(View child, int index) {
409 super.addView(child, index);
410 requestRowsLayout();
411 }
412
413 /**
414 * {@inheritDoc}
415 */
416 @Override
417 public void addView(View child, ViewGroup.LayoutParams params) {
418 super.addView(child, params);
419 requestRowsLayout();
420 }
421
422 /**
423 * {@inheritDoc}
424 */
425 @Override
426 public void addView(View child, int index, ViewGroup.LayoutParams params) {
427 super.addView(child, index, params);
428 requestRowsLayout();
429 }
430
431 /**
432 * {@inheritDoc}
433 */
434 @Override
435 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
436 // enforce vertical layout
437 measureVertical(widthMeasureSpec, heightMeasureSpec);
438 }
439
440 /**
441 * {@inheritDoc}
442 */
443 @Override
444 protected void onLayout(boolean changed, int l, int t, int r, int b) {
445 // enforce vertical layout
Philip Milnead365cc2012-09-27 14:38:46 -0700446 layoutVertical(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 }
448
449 /**
450 * {@inheritDoc}
451 */
452 @Override
453 void measureChildBeforeLayout(View child, int childIndex,
454 int widthMeasureSpec, int totalWidth,
455 int heightMeasureSpec, int totalHeight) {
456 // when the measured child is a table row, we force the width of its
457 // children with the widths computed in findLargestCells()
458 if (child instanceof TableRow) {
459 ((TableRow) child).setColumnsWidthConstraints(mMaxWidths);
460 }
461
462 super.measureChildBeforeLayout(child, childIndex,
463 widthMeasureSpec, totalWidth, heightMeasureSpec, totalHeight);
464 }
465
466 /**
467 * {@inheritDoc}
468 */
469 @Override
470 void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -0700471 findLargestCells(widthMeasureSpec, heightMeasureSpec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 shrinkAndStretchColumns(widthMeasureSpec);
473
474 super.measureVertical(widthMeasureSpec, heightMeasureSpec);
475 }
476
477 /**
478 * <p>Finds the largest cell in each column. For each column, the width of
479 * the largest cell is applied to all the other cells.</p>
480 *
481 * @param widthMeasureSpec the measure constraint imposed by our parent
482 */
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -0700483 private void findLargestCells(int widthMeasureSpec, int heightMeasureSpec) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 boolean firstRow = true;
485
486 // find the maximum width for each column
487 // the total number of columns is dynamically changed if we find
488 // wider rows as we go through the children
489 // the array is reused for each layout operation; the array can grow
490 // but never shrinks. Unused extra cells in the array are just ignored
491 // this behavior avoids to unnecessary grow the array after the first
492 // layout operation
493 final int count = getChildCount();
494 for (int i = 0; i < count; i++) {
495 final View child = getChildAt(i);
496 if (child.getVisibility() == GONE) {
497 continue;
498 }
499
500 if (child instanceof TableRow) {
501 final TableRow row = (TableRow) child;
502 // forces the row's height
503 final ViewGroup.LayoutParams layoutParams = row.getLayoutParams();
504 layoutParams.height = LayoutParams.WRAP_CONTENT;
505
Filip Gruszczynskib6824bf2015-04-13 09:16:25 -0700506 final int[] widths = row.getColumnsWidths(widthMeasureSpec, heightMeasureSpec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 final int newLength = widths.length;
508 // this is the first row, we just need to copy the values
509 if (firstRow) {
510 if (mMaxWidths == null || mMaxWidths.length != newLength) {
511 mMaxWidths = new int[newLength];
512 }
513 System.arraycopy(widths, 0, mMaxWidths, 0, newLength);
514 firstRow = false;
515 } else {
516 int length = mMaxWidths.length;
517 final int difference = newLength - length;
518 // the current row is wider than the previous rows, so
519 // we just grow the array and copy the values
520 if (difference > 0) {
521 final int[] oldMaxWidths = mMaxWidths;
522 mMaxWidths = new int[newLength];
523 System.arraycopy(oldMaxWidths, 0, mMaxWidths, 0,
524 oldMaxWidths.length);
525 System.arraycopy(widths, oldMaxWidths.length,
526 mMaxWidths, oldMaxWidths.length, difference);
527 }
528
529 // the row is narrower or of the same width as the previous
530 // rows, so we find the maximum width for each column
531 // if the row is narrower than the previous ones,
532 // difference will be negative
533 final int[] maxWidths = mMaxWidths;
534 length = Math.min(length, newLength);
535 for (int j = 0; j < length; j++) {
536 maxWidths[j] = Math.max(maxWidths[j], widths[j]);
537 }
538 }
539 }
540 }
541 }
542
543 /**
544 * <p>Shrinks the columns if their total width is greater than the
545 * width allocated by widthMeasureSpec. When the total width is less
546 * than the allocated width, this method attempts to stretch columns
547 * to fill the remaining space.</p>
548 *
549 * @param widthMeasureSpec the width measure specification as indicated
550 * by this widget's parent
551 */
552 private void shrinkAndStretchColumns(int widthMeasureSpec) {
553 // when we have no row, mMaxWidths is not initialized and the loop
554 // below could cause a NPE
555 if (mMaxWidths == null) {
556 return;
557 }
558
559 // should we honor AT_MOST, EXACTLY and UNSPECIFIED?
560 int totalWidth = 0;
561 for (int width : mMaxWidths) {
562 totalWidth += width;
563 }
564
565 int size = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
566
567 if ((totalWidth > size) && (mShrinkAllColumns || mShrinkableColumns.size() > 0)) {
568 // oops, the largest columns are wider than the row itself
Gilles Debunne6741c942011-01-25 20:11:45 -0800569 // fairly redistribute the row's width among the columns
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 mutateColumnsWidth(mShrinkableColumns, mShrinkAllColumns, size, totalWidth);
571 } else if ((totalWidth < size) && (mStretchAllColumns || mStretchableColumns.size() > 0)) {
572 // if we have some space left, we distribute it among the
573 // expandable columns
574 mutateColumnsWidth(mStretchableColumns, mStretchAllColumns, size, totalWidth);
575 }
576 }
577
578 private void mutateColumnsWidth(SparseBooleanArray columns,
579 boolean allColumns, int size, int totalWidth) {
580 int skipped = 0;
581 final int[] maxWidths = mMaxWidths;
582 final int length = maxWidths.length;
583 final int count = allColumns ? length : columns.size();
584 final int totalExtraSpace = size - totalWidth;
585 int extraSpace = totalExtraSpace / count;
586
Gilles Debunnef5c6eff2010-02-09 19:08:36 -0800587 // Column's widths are changed: force child table rows to re-measure.
588 // (done by super.measureVertical after shrinkAndStretchColumns.)
589 final int nbChildren = getChildCount();
590 for (int i = 0; i < nbChildren; i++) {
591 View child = getChildAt(i);
592 if (child instanceof TableRow) {
593 child.forceLayout();
594 }
595 }
596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 if (!allColumns) {
598 for (int i = 0; i < count; i++) {
599 int column = columns.keyAt(i);
600 if (columns.valueAt(i)) {
601 if (column < length) {
602 maxWidths[column] += extraSpace;
603 } else {
604 skipped++;
605 }
606 }
607 }
608 } else {
609 for (int i = 0; i < count; i++) {
610 maxWidths[i] += extraSpace;
611 }
612
613 // we don't skip any column so we can return right away
614 return;
615 }
616
617 if (skipped > 0 && skipped < count) {
618 // reclaim any extra space we left to columns that don't exist
619 extraSpace = skipped * extraSpace / (count - skipped);
620 for (int i = 0; i < count; i++) {
621 int column = columns.keyAt(i);
622 if (columns.valueAt(i) && column < length) {
623 if (extraSpace > maxWidths[column]) {
624 maxWidths[column] = 0;
625 } else {
626 maxWidths[column] += extraSpace;
627 }
628 }
629 }
630 }
631 }
632
633 /**
634 * {@inheritDoc}
635 */
636 @Override
637 public LayoutParams generateLayoutParams(AttributeSet attrs) {
638 return new TableLayout.LayoutParams(getContext(), attrs);
639 }
640
641 /**
642 * Returns a set of layout parameters with a width of
Romain Guy980a9382010-01-08 15:06:28 -0800643 * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 * and a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}.
645 */
646 @Override
647 protected LinearLayout.LayoutParams generateDefaultLayoutParams() {
648 return new LayoutParams();
649 }
650
651 /**
652 * {@inheritDoc}
653 */
654 @Override
655 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
656 return p instanceof TableLayout.LayoutParams;
657 }
658
659 /**
660 * {@inheritDoc}
661 */
662 @Override
663 protected LinearLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
664 return new LayoutParams(p);
665 }
666
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800667 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -0800668 public CharSequence getAccessibilityClassName() {
669 return TableLayout.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800670 }
671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 /**
673 * <p>This set of layout parameters enforces the width of each child to be
Romain Guy980a9382010-01-08 15:06:28 -0800674 * {@link #MATCH_PARENT} and the height of each child to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 * {@link #WRAP_CONTENT}, but only if the height is not specified.</p>
676 */
677 @SuppressWarnings({"UnusedDeclaration"})
678 public static class LayoutParams extends LinearLayout.LayoutParams {
679 /**
680 * {@inheritDoc}
681 */
682 public LayoutParams(Context c, AttributeSet attrs) {
683 super(c, attrs);
684 }
685
686 /**
687 * {@inheritDoc}
688 */
689 public LayoutParams(int w, int h) {
Romain Guy980a9382010-01-08 15:06:28 -0800690 super(MATCH_PARENT, h);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 }
692
693 /**
694 * {@inheritDoc}
695 */
696 public LayoutParams(int w, int h, float initWeight) {
Romain Guy980a9382010-01-08 15:06:28 -0800697 super(MATCH_PARENT, h, initWeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 }
699
700 /**
701 * <p>Sets the child width to
702 * {@link android.view.ViewGroup.LayoutParams} and the child height to
703 * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}.</p>
704 */
705 public LayoutParams() {
Romain Guy980a9382010-01-08 15:06:28 -0800706 super(MATCH_PARENT, WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 }
708
709 /**
710 * {@inheritDoc}
711 */
712 public LayoutParams(ViewGroup.LayoutParams p) {
713 super(p);
Kirill Grouchnikovc4d5e122016-06-20 12:35:28 -0400714 width = MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 }
716
717 /**
718 * {@inheritDoc}
719 */
720 public LayoutParams(MarginLayoutParams source) {
721 super(source);
Kirill Grouchnikovc4d5e122016-06-20 12:35:28 -0400722 width = MATCH_PARENT;
723 if (source instanceof TableLayout.LayoutParams) {
724 weight = ((TableLayout.LayoutParams) source).weight;
725 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 }
727
728 /**
729 * <p>Fixes the row's width to
Romain Guy980a9382010-01-08 15:06:28 -0800730 * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}; the row's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 * height is fixed to
732 * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} if no layout
733 * height is specified.</p>
734 *
735 * @param a the styled attributes set
736 * @param widthAttr the width attribute to fetch
737 * @param heightAttr the height attribute to fetch
738 */
739 @Override
Dave Burke579e1402012-10-18 20:41:55 -0700740 protected void setBaseAttributes(TypedArray a,
741 int widthAttr, int heightAttr) {
Romain Guy980a9382010-01-08 15:06:28 -0800742 this.width = MATCH_PARENT;
Dave Burke579e1402012-10-18 20:41:55 -0700743 if (a.hasValue(heightAttr)) {
744 this.height = a.getLayoutDimension(heightAttr, "layout_height");
745 } else {
746 this.height = WRAP_CONTENT;
747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 }
749 }
750
751 /**
752 * <p>A pass-through listener acts upon the events and dispatches them
753 * to another listener. This allows the table layout to set its own internal
754 * hierarchy change listener without preventing the user to setup his.</p>
755 */
756 private class PassThroughHierarchyChangeListener implements
757 OnHierarchyChangeListener {
758 private OnHierarchyChangeListener mOnHierarchyChangeListener;
759
760 /**
761 * {@inheritDoc}
762 */
763 public void onChildViewAdded(View parent, View child) {
764 trackCollapsedColumns(child);
765
766 if (mOnHierarchyChangeListener != null) {
767 mOnHierarchyChangeListener.onChildViewAdded(parent, child);
768 }
769 }
770
771 /**
772 * {@inheritDoc}
773 */
774 public void onChildViewRemoved(View parent, View child) {
775 if (mOnHierarchyChangeListener != null) {
776 mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
777 }
778 }
779 }
780}