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