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