create a rich ui layout with table layout manger

Upload: aung-phyo-koko

Post on 06-Apr-2018

224 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    1/12

    How To - Create a rich UI layout with TableLayoutManager

    Last Updated: 25 September 2009

    Article Number: DB-00783

    Summary

    This article applies to the following:

    BlackBerry Device Software 4.2 and later

    Details

    Cells are the basic building blocks for any layout. Each cell defines its space requirements for the Field contained within it. If you try to

    visualize this arrangement, it looks very much like a table. Using a TableLayoutManager, you can handle fixed or relative cell sizes.Also, by using embedded tables, you can easily build almost any layout required.

    The full source code for a TableLayoutManager is provided at the end of this article.You can also download the source code file

    fromhere.

    The TableLayoutManager has the following two constructors:

    public TableLayoutManager(int columnStyles[], long style)

    public TableLayoutManager(int columnStyles[], int columnWidths[], inthorizontalPadding, long style)

    Parameter Description

    columnStyles[]

    Defines the styles for all the columns. The size of this array is basically the number of columns you want in agiven row. The different styles you can choose are as follows:

    USE_PREFERRED_SIZE - Allows the field to use all the space required

    USE_PREFERRED_WIDTH_WITH_MAXIMUM - Allows the field to use as much space as requiredup to a maximum. You can specify the maximum width for each field by passing in the width inthe columnWidths variable

    FIXED_WIDTH - Specifies that columns are of fixed width

    SPLIT_REMAINING_WIDTH - Specifies the remaining width to use. It can be thought of as "thiscolumn will utilize all the remaining width of the table". For example, if

    theTableLayoutManager has one of these columns defined

    as SPLIT_REMAINING_WIDTHand the manager has Manager.USE_ALL_WIDTH, the column

    will fill the remaining space. If there are multiple columns defined as SPLIT_REMAINING_WIDTH,

    the columns will evenly share that remaining width

    style The manager style. You can just choose from Manager. HORIZONTAL_SCROLL, Manager.xxxx.

    columnWidths If you choose, you can specify widths to be used for each field to force particular column size.

    horizontalPadding Allows you to specify horizontal padding between columns.

    You can add any Field to the TableLayoutManager, including other managers (even otherTableLayoutManagers) to create

    very complex layouts. Simply define the number of columns required and then, based on number of fields added to the layout,

    http://www.blackberry.com/knowledgecentersupport/kmsupport/developerknowledgebase/txt/TableLayoutManager.javahttp://www.blackberry.com/knowledgecentersupport/kmsupport/developerknowledgebase/txt/TableLayoutManager.javahttp://www.blackberry.com/knowledgecentersupport/kmsupport/developerknowledgebase/txt/TableLayoutManager.java
  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    2/12

    the TableLayoutManagerwill automatically align the fields in separate rows such that you do not need to define the number of rows at

    compile time.

    For example, the following code shows how to create an image thumbnail preview. A table layout with five columns is created and populated

    from an array of images. Note that rows are automatically added as the table fills out.

    TableLayoutManager colFMgr = new TableLayoutManager(new int[]

    {

    TableLayoutManager.USE_PREFERRED_SIZE,

    TableLayoutManager.USE_PREFERRED_SIZE,

    TableLayoutManager.USE_PREFERRED_SIZE,

    TableLayoutManager.USE_PREFERRED_SIZE,

    TableLayoutManager.USE_PREFERRED_SIZE

    }, Manager.HORIZONTAL_SCROLL);

    for(int i= 0;i < images.length;i++)

    {

    colFMgr.add(new BitmapField(images[i],Field.FOCUSABLE));

    }

    add(colFMgr);

    TableLayoutManager - Source codeimport net.rim.device.api.ui.Field;

    import net.rim.device.api.ui.Manager;

    import net.rim.device.api.ui.XYPoint;

    import net.rim.device.api.util.Arrays;

    /**

    * TableLayoutManager can be used to create multi column table

    * views. You can even embed table within another table to create

    * complex tabular views.

    */

    public class TableLayoutManager extends Manager{

    int _columnWidths[];

    int _suggestedColumnWidths[];

    int _rowHeights[];

    int _columnStyles[];

    /** Let the field use up ALL the space that it needs **/

    public static final int USE_PREFERRED_SIZE = 1;

    /** let the field use up as much space as it needs UP TO a maximum */

    public static final int USE_PREFERRED_WIDTH_WITH_MAXIMUM = 2;

    /** the fields should use up the remaining space evenly */

    public static final int SPLIT_REMAINING_WIDTH = 4;

    /** the column is fixed width **/

    public static final int FIXED_WIDTH = 8;

    private static int BITMASK_USE_PREFERRED =

    USE_PREFERRED_WIDTH_WITH_MAXIMUM

    | USE_PREFERRED_SIZE;

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    3/12

    public static int DEFAULT_PADDING = 5;

    int _rows;

    int _columns;

    private int _horizPadding;

    public TableLayoutManager(int columnStyles[], long style)

    {

    this(columnStyles, null, DEFAULT_PADDING, style);

    }

    /**

    * creates a table with the specified column styles

    *

    * @param columnStyles

    * - array of styles for all the columns. The size

    * of this array determines the number of columns.

    * @param columnWidths

    * - array of widths. This is used for the FIXED_WIDTH,

    * and USE_PREFERRED_WIDTH_WITH_MAXIMUM styles.* the value is ignored for the other styles.

    * @param horizontalPadding

    * - space between columns

    * @param style

    */

    public TableLayoutManager(int columnStyles[], int columnWidths[],

    int horizontalPadding, long style)

    {

    super(style);

    _horizPadding = horizontalPadding;

    _columnStyles = columnStyles;

    if (_columnStyles == null)

    throw new IllegalArgumentException("not column styles");

    if (columnWidths != null)

    {

    _suggestedColumnWidths = Arrays.copy(columnWidths,

    0,columnWidths.length);

    if (_suggestedColumnWidths.length < _columnStyles.length)

    {

    int oldLength = _suggestedColumnWidths.length;

    int increase = columnStyles.length - oldLength;

    _suggestedColumnWidths = Arrays.copy(columnWidths, 0,

    columnStyles.length);

    Arrays.fill(_suggestedColumnWidths, 0,

    oldLength, increase);

    }

    }

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    4/12

    else

    _suggestedColumnWidths = new int[_columnStyles.length];

    }

    private Field getField(int x, int y)

    {

    int i = x + (y * _columns);

    if (i >= getFieldCount()) return null;

    return getField(i);

    }

    private boolean isColumnStyle(int value, int flag)

    {

    return ((value) & (flag)) > 0;

    }

    /**

    * Implements the getPreferredWidth call to return the

    * expected width for this manager. The expected width is* the Max(Sum (Column Widths))

    */

    public int getPreferredWidth()

    {

    int numberFields = getFieldCount();

    if (numberFields == 0) return 0;

    int rows = numberFields / _columnStyles.length;

    int prefferedWidth = 0;

    int styles[] = _columnStyles;

    int[] columnWidths = new int[_columns];

    Arrays.fill(columnWidths, -1);

    for (int i = 0; i < _columns; i++)

    {

    // assign the fixed widths

    if (isColumnStyle(styles[i], FIXED_WIDTH))

    {

    columnWidths[i] = _suggestedColumnWidths[i];

    }

    else

    {

    if (isColumnStyle(styles[i], BITMASK_USE_PREFERRED))

    {

    for (int j = 0; j < rows; j++)

    {

    Field field = getField(i, j);

    if (field != null)

    {

    int actualWidth = getPreferredWidthOfChild(field)

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    5/12

    + field.getMarginLeft()

    + field.getMarginRight();

    if (isColumnStyle(styles[i],

    USE_PREFERRED_WIDTH_WITH_MAXIMUM))

    {

    actualWidth = Math.min(actualWidth,

    _suggestedColumnWidths[i]);

    }

    columnWidths[i] =

    Math.max(actualWidth,columnWidths[i]);

    }

    }

    }

    }

    }

    // TODO - this loop can be optimized

    for (int n = 0; n < _columns; n++)

    {prefferedWidth += columnWidths[n];

    }

    return prefferedWidth;

    }

    /**

    * implements the preferred height for this layout

    */

    public int getPreferredHeight()

    {

    int numberFields = getFieldCount();

    if (numberFields == 0) return 0;

    int rows = numberFields / _columnStyles.length;

    int prefferedHeight = 0;

    int[] rowHeights = new int[rows];

    Arrays.fill(rowHeights, -1);

    for (int i = 0; i < _columns; i++)

    {

    for (int j = 0; j < rows; j++)

    {

    Field field = getField(i, j);

    if (field != null)

    {

    int actualHeight = getPreferredHeightOfChild(field)

    + field.getMarginBottom()

    + field.getMarginTop();

    rowHeights[j] = Math.max(actualHeight, rowHeights[j]);

    }

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    6/12

    }

    }

    for (int n = 0; n < rows; n++)

    {

    prefferedHeight += rowHeights[n];

    }

    return prefferedHeight;

    }

    /**

    * Defines how Fields for this manager needs to be handled.

    */

    protected void sublayout(int layoutWidth, int layoutHeight)

    {

    int numberFields = getFieldCount();

    if (numberFields == 0) return;

    layoutWidth -= getPaddingLeft() + getPaddingRight();

    layoutHeight -= getPaddingTop() + getPaddingBottom();_columns = _columnStyles.length;

    int styles[] = _columnStyles;

    if (isStyle(Field.USE_ALL_WIDTH))

    {

    boolean found = false;

    // if the field should take maximum space, at least

    // the last field

    // should be SPLIT_REMAINING_WIDTH

    for (int n = 0; n < _columns; n++)

    {

    if (styles[n] == SPLIT_REMAINING_WIDTH)

    {

    found = true;

    break;

    }

    }

    if (!found)

    {

    styles[_columns - 1] = SPLIT_REMAINING_WIDTH;

    }

    }

    _rows = numberFields / _columns;

    if ((numberFields % _columns) > 0) _rows++;

    _columnWidths = new int[_columns]; // arrays that keep track of

    // maximum widths

    _rowHeights = new int[_rows];

    // widths and heights are -1 if unassigned, we use this

    // fact to assign the column widths

    Arrays.fill(_columnWidths, -1);

    Arrays.fill(_rowHeights, -1);

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    7/12

    /*

    * there are three types of columns, fixed width, split

    * remaining width, and use preferred size step 1) we

    * need to look at the columns that are marked as "use

    * preferred size", find the widest element, then

    * record that maximum width step 2) as well, we can

    * assign the column widths for the columns that are

    * fixed width

    */

    for (int i = 0; i < _columns; i++)

    {

    // assign the fixed widths

    if (isColumnStyle(styles[i], FIXED_WIDTH))

    {

    _columnWidths[i] = _suggestedColumnWidths[i];

    }

    else{

    if (isColumnStyle(styles[i], BITMASK_USE_PREFERRED))

    {

    for (int j = 0; j < _rows; j++)

    {

    Field field = getField(i, j);

    if (field != null)

    {

    layoutChild(field, Math.max(0, layoutWidth

    - (field.getMarginLeft()

    + field.getMarginRight())),

    Math.max(0,layoutHeight

    - (field.getMarginBottom()

    + field.getMarginTop())));

    int actualWidth = getPreferredWidthOfChild(field)

    + field.getMarginLeft()

    + field.getMarginRight();

    int actualHeight = getPreferredHeightOfChild(field)

    + field.getMarginBottom()

    + field.getMarginTop();

    if (isColumnStyle(styles[i],

    USE_PREFERRED_WIDTH_WITH_MAXIMUM))

    {

    actualWidth = Math.min(actualWidth,

    _suggestedColumnWidths[i]);

    }

    _columnWidths[i] = Math.max(actualWidth,

    _columnWidths[i]);

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    8/12

    _rowHeights[j] = Math.max(actualHeight,

    _rowHeights[j]);

    }

    }

    }

    }

    }

    /*

    * step 3 - find out the total width used up by the

    * fields that have known widths

    */

    int usedColumnWidth = 0;

    int numUnassignedColumnWidths = 0;

    for (int i = 0; i < _columns; i++)

    {

    if (_columnWidths[i] >= 0)

    {usedColumnWidth += _columnWidths[i]

    + ((i < (_columns - 1)) ? _horizPadding : 0);

    }

    else

    {

    numUnassignedColumnWidths++;

    }

    }

    /*

    * assign the remaining space evenly amongst the

    * unassigned columns

    */

    if (numUnassignedColumnWidths > 0)

    {

    int remainingWidthToAssign = layoutWidth - usedColumnWidth;

    if (remainingWidthToAssign < 0)

    {

    remainingWidthToAssign = 0;

    }

    int splitRemainingWidth = (remainingWidthToAssign -

    ((numUnassignedColumnWidths - 1)

    * _horizPadding))

    / numUnassignedColumnWidths;

    for (int i = 0; i < _columns; i++)

    {

    int assignedWidth = Math.min(remainingWidthToAssign,

    splitRemainingWidth);

    if (_columnWidths[i] < 0)

    {

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    9/12

    _columnWidths[i] = assignedWidth;

    remainingWidthToAssign -= assignedWidth;

    }

    }

    }

    int currentRow = 0;

    int currentColumn = 0;

    int y = getPaddingTop();

    for (int n = 0; n < numberFields; n++)

    { Field field = getField(n);

    if (!isColumnStyle(styles[currentColumn], USE_PREFERRED_SIZE))

    { // do

    // the others we missed from above

    layoutChild(field, Math.max(0, _columnWidths[currentColumn]

    - (field.getMarginLeft()

    + field.getMarginRight())),

    Math.max(0, layoutHeight- y

    - (field.getMarginBottom()

    + field.getMarginTop())));

    }

    _rowHeights[currentRow] = Math.max(_rowHeights[currentRow], field

    .getExtent().height

    + field.getMarginBottom()

    + field.getMarginTop());

    currentColumn++;

    if ((n == (numberFields - 1)) || (currentColumn >= _columns))

    {

    // we are at the end of the row or list, so now

    // go and actually do the positioning for each row

    int x = getPaddingLeft();

    for (int i = 0; i < currentColumn; i++)

    {

    Field field1 = getField(i, currentRow);

    XYPoint offset = calcAlignmentOffset(field1, Math.max(0,

    _columnWidths[i]

    - (field1.getMarginLeft() + field1

    .getMarginRight())), Math.max(0,

    _rowHeights[currentRow]

    - (field1.getMarginBottom()

    + field1.getMarginTop())));

    setPositionChild(field1, x + offset.x

    + field1.getMarginLeft(), y + offset.y

    + field1.getMarginTop());

    x += _columnWidths[i] + _horizPadding;

    }

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    10/12

    y += _rowHeights[currentRow];

    currentColumn = 0;

    currentRow++;

    }

    }

    int totalWidth = 0;

    if (isStyle(Field.USE_ALL_WIDTH))

    {

    totalWidth = layoutWidth;

    }

    else

    {

    for (int i = 0; i < _columns; i++)

    {

    totalWidth += _columnWidths[i]

    + ((i < (_columns - 1)) ? _horizPadding : 0);

    }}

    totalWidth += getPaddingLeft() + getPaddingRight();

    y += getPaddingBottom();

    setExtent(totalWidth, Math.min(y, layoutHeight));

    }

    /**

    * Navigation movement to allow for both cell to cell within

    * a columns and row movement

    */

    protected boolean navigationMovement(int dx, int dy, int status, int time)

    {

    int focusIndex = getFieldWithFocusIndex();

    int dirY = (dy > 0) ? 1 : -1;

    int absY = Math.abs(dy);

    for (int y = 0; y < absY; y++)

    {

    focusIndex += _columns * dirY;

    if (focusIndex < 0 || focusIndex >= getFieldCount())

    {

    return false;

    }

    else

    {

    Field f = getField(focusIndex);

    if (f.isFocusable())

    {

    f.setFocus();

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    11/12

    }

    else

    y--; // do it over again

    }

    }

    int dirX = (dx > 0) ? 1 : -1;

    int absX = Math.abs(dx);

    for (int x = 0; x < absX; x++)

    {

    focusIndex += dirX;

    if (focusIndex < 0 || focusIndex >= getFieldCount())

    {

    return false;

    }

    else

    {

    Field f = getField(focusIndex);

    if (f.isFocusable()){

    f.setFocus();

    }

    else

    x--; // do it over again

    }

    }

    return true;

    }

    /**

    * Calculate the styles and return appropriate XY offset

    * locations within the cell.

    * @param field

    * @param width

    * @param height

    * @return

    */

    private XYPoint calcAlignmentOffset(Field field, int width, int height)

    {

    XYPoint offset = new XYPoint(0, 0);

    long fieldStyle = field.getStyle();

    long field_x_style = fieldStyle & Field.FIELD_HALIGN_MASK;

    if (field_x_style == Field.FIELD_RIGHT)

    {

    offset.x = width - field.getExtent().width;

    }

    else if (field_x_style == Field.FIELD_HCENTER)

    {

    offset.x = (width - field.getExtent().width) / 2;

  • 8/2/2019 Create a Rich UI Layout With Table Layout Manger

    12/12

    }

    long field_y_style = fieldStyle & Field.FIELD_VALIGN_MASK;

    if (field_y_style == Field.FIELD_BOTTOM)

    {

    offset.y = height - field.getExtent().height;

    }

    else if (field_y_style == Field.FIELD_VCENTER)

    {

    offset.y = (height - field.getExtent().height) / 2;

    }

    return offset;

    }

    }