creating custom fields and managers is easier than you think!

84
Creating Custom Fields and Managers is Easier than You Think! Terrill Dent, Michael Brown DEV 19 September 27, 2010

Upload: hela-benkhal

Post on 25-Mar-2016

217 views

Category:

Documents


1 download

DESCRIPTION

Creating Custom Fields and Managers

TRANSCRIPT

Page 1: Creating Custom Fields and Managers is Easier than You Think!

Creating Custom Fields and Managers is Easier than You Think!Terrill Dent, Michael Brown

DEV 19September 27, 2010

Page 2: Creating Custom Fields and Managers is Easier than You Think!

Session Surveys

• Remember to complete your breakout session evaluation in one of two ways:

– On your BlackBerry® smartphone – use the DEVCON 2010 mobile guide, from Pyxis

– Login to My Scheduler at one of the Cyber Zone locations or on your PC

Page 3: Creating Custom Fields and Managers is Easier than You Think!

ABOUT US

Page 4: Creating Custom Fields and Managers is Easier than You Think!

SOURCE CODE ONLINEVisit www.blackberrydevcon.com for download

18Realistic

Interfaces

19Custom Fields and Managers

20Custom Layouts

21Branding

Page 5: Creating Custom Fields and Managers is Easier than You Think!

DEMOa taste of things to come

Page 6: Creating Custom Fields and Managers is Easier than You Think!

Agenda

• Fields– Custom Button

– Slider

• Managers– Toolbar

– Two Column Manager

Terrill and I were thinking that I would present Dev 21 by myself (we are both listed currently). I don’t know if that’s something you need to update on your end

Page 7: Creating Custom Fields and Managers is Easier than You Think!

FIELD BASICSa quick overview

Page 8: Creating Custom Fields and Managers is Easier than You Think!

Fields

A few things to consider when writing a custom field:

1. Constructor

2. Font

3. Layout

4. Paint

5. Input Handling (clicks, touches, keyboard, navigation)

Page 9: Creating Custom Fields and Managers is Easier than You Think!

Fields

A few things to consider when writing a custom field:

1. Constructor

2. Font

3. Layout

4. Paint

5. Input Handling (clicks, touches, keyboard, navigation)

Visual aspects

Page 10: Creating Custom Fields and Managers is Easier than You Think!

Fields

A few things to consider when writing a custom field:

1. Constructor

2. Font

3. Layout

4. Paint

5. Input Handling (clicks, touches, keyboard, navigation)

Interaction aspects

Page 11: Creating Custom Fields and Managers is Easier than You Think!

CREATING A BUTTONvisual aspects

Page 12: Creating Custom Fields and Managers is Easier than You Think!

ButtonThe Goal

• Text surrounded by an attractive border

• Different visual appearance based on state– Unfocused

– Focused

– Pressed / Active

Page 13: Creating Custom Fields and Managers is Easier than You Think!

ButtonThe Goal

Page 14: Creating Custom Fields and Managers is Easier than You Think!

Button1) Constructor

The Field constructor takes a style parameter.

Some styles are used internally by the field:

– Editability [EDITABLE , READONLY]

– Size [ USE_ALL_WIDTH, USE_ALL_HEIGHT ]

Some styles are used by the field’s manager:

– Position [ LEFT, TOP, RIGHT, BOTTOM, etc]

– Focusability [ FOCUSABLE, NON_FOCUSABLE]

Page 15: Creating Custom Fields and Managers is Easier than You Think!

Button1) Constructor

• Our constructor takes the button text, three borders and text colours for the various states, and a style:public CustomButtonField(

String text, Border normalBorder, Border focusBorder, Border activeBorder, int normalColor, int focusColor, int activeColor,long style )

• We will paint the border and background of the button ourselves– This lets us change them whenever the state of the button changes

Page 16: Creating Custom Fields and Managers is Easier than You Think!

Button2) Font

• The applyFont() method will be called if the user changes their default system font while your application is running

• You can derive a specific font to use instead of the system font

public void applyFont() {_font = Font.getDefault().derive( Font.BOLD );

}

Page 17: Creating Custom Fields and Managers is Easier than You Think!

Font.getAdvance()Beware!

Font.getBounds()Useful

Font.measureText()Very complicated…

Typically getBounds() is good enough...

abcd

Button2) Font – Measuring Text

abcd

Page 18: Creating Custom Fields and Managers is Easier than You Think!

Button3) Layout – The Box Model

Margin

Border

Padding

Content

Page 19: Creating Custom Fields and Managers is Easier than You Think!

Button3) Layout

Margin

Border

Padding

Content

In layout() we only have one task:

set the size of the content area

Padding and Borders are handled by our Manager

Page 20: Creating Custom Fields and Managers is Easier than You Think!

Button3) Layout

• The layout method must call setExtent()– We need to determine the size of the field based on the maximum

dimensions provided by our manager

protected void layout( int width, int height ) {setExtent(Math.min( width, getPreferredWidth() ),Math.min( height, getPreferredHeight() ) );

...

}

Page 21: Creating Custom Fields and Managers is Easier than You Think!

Button3) Layout

• We implement the helper methods getPreferredWidth() and getPreferredHeight()

– Some managers may use these values as “hints” so it is polite to implement them properly

public int getPreferredWidth() {

return isStyle( USE_ALL_WIDTH ) ? Integer.MAX_VALUE: _borderWidth + getFont().getBounds( _text );

}

public int getPreferredHeight() {

return _borderHeight + getFont().getHeight();}

Here we take care to respect the USE_ALL_WIDTH style bit

Allows for a button that is as wide as the possible, or just as wide as its text

Page 22: Creating Custom Fields and Managers is Easier than You Think!

Button4) Paint

• In paint() we paint the content area of the field– In our case, this is just the button text, with the proper color

protected void paint( Graphics g ){

int oldColour = g.getColor();try {

setTextColor( g );g.drawText(

_text, 0, _backgroundRect.y, DrawStyle.HCENTER, _contentRect.width );

} finally {g.setColor( oldColour );

}}

Page 23: Creating Custom Fields and Managers is Easier than You Think!

Button4) Paint

• In paintBackground() we paint the area around the text– In this example, this includes the border and the backgound since we

are drawing them ourselves

– In general, the framework will draw the border and background for us, so this step is often not necessary

protected void paintBackground( Graphics g ){Border currentBorder = getCurrentBorder();Background currentBackground = getCurrentBackground();

currentBorder.paint( g, _borderRect );currentBackground.draw( g, _backgroundRect );

}

Page 24: Creating Custom Fields and Managers is Easier than You Think!

CREATING A BUTTONinteraction aspects

Page 25: Creating Custom Fields and Managers is Easier than You Think!

Button5) Input Handling

• Many different types of trackpad input, but for a button, they all mean just about the same thing…

keyChar()

navigationClick()

trackwheelClick()

invokeAction()

• To find out when the button was clicked, register as a FieldChangeListener

public void clickButton() {fieldChangeNotify( 0 );

}

Page 26: Creating Custom Fields and Managers is Easier than You Think!

Button5) Input Handling

• Down / Click Event– When the user touches the button, activate Pressed state

• Up / Unclick Event– When the user lets go, deactivate Pressed state, click the button, and

fire the listener events

– Need to be a little bit careful not to fire the listener events multiple times – some devices send both Up AND Unclick events

Page 27: Creating Custom Fields and Managers is Easier than You Think!

ButtonDirty State

• Each field has a dirty state used to check whether the device should prompt about unsaved changes to an editable screen

• Buttons shouldn’t ever be dirty…

public void setDirty( boolean dirty ) {}

public void setMuddy( boolean muddy ) {}

• or…

public boolean isDirty() { return false; }

Page 28: Creating Custom Fields and Managers is Easier than You Think!

ButtonFinished Result

• The CustomButtonField is a flexible, full featured, bitmap based Button

• Supports custom Focus and Pressed States

• Supports USE_ALL_WIDTH and custom padding on a per-field basis

Page 29: Creating Custom Fields and Managers is Easier than You Think!

CREATING A SLIDERvisual aspects

Page 30: Creating Custom Fields and Managers is Easier than You Think!

SliderThe Goal

Page 31: Creating Custom Fields and Managers is Easier than You Think!

SliderThe Goal

• A ball that slides along a track

• A finite number of “notches” that the ball can occupy

• Different visual appearance based on state– Unfocused

– Focused

– Pressed / Active

Page 32: Creating Custom Fields and Managers is Easier than You Think!

SliderPieces of a Slider

Base

Progress

Thumb

Page 33: Creating Custom Fields and Managers is Easier than You Think!

SliderPieces of a Slider

Condense these graphics

Leave enough content in the middle to tile

We need two more full image sets for the Focused and Pressed states

SliderPieces of a Slider

Base

Progress

Thumb

Page 34: Creating Custom Fields and Managers is Easier than You Think!

SliderLayout

Start with the available spacelayout( int width, int height )

Preferred width is all available width

Page 35: Creating Custom Fields and Managers is Easier than You Think!

SliderLayout

Start with the available spacelayout( int width, int height )

Preferred width is all available width

preferredWidth = availableWidth

Page 36: Creating Custom Fields and Managers is Easier than You Think!

SliderLayout

Preferred height is the max of: - Height of the Thumb - Height of the Progress- Height of the Base

preferredWidth = availableWidth

Page 37: Creating Custom Fields and Managers is Easier than You Think!

SliderLayout

preferredWidth = availableWidth

preferredHeight = max image height

• These values are passed to setExtent() during layout

Page 38: Creating Custom Fields and Managers is Easier than You Think!

SliderPaint

Graphics.drawBitmap()Graphics.tileRop()

• The thumb position is calculated from the current “notch”

• The set of images painted depends on the current visual state

• When the visual state needs to change, we can call invalidate() to trigger a repaint

Page 39: Creating Custom Fields and Managers is Easier than You Think!

SliderInteraction

Navigation MovementEvents

Trackpad / TrackballTouchscreen

Click EventsDown / Move Events

Up Events

Page 40: Creating Custom Fields and Managers is Easier than You Think!

SliderTouchscreen Interaction

• Down Event– When the user touches the slider, activate Pressed state

• Move Event– When the user drags left or right, change notch and notify field change

listeners

• Up Event– When the user lets go, deactivate Pressed state

Page 41: Creating Custom Fields and Managers is Easier than You Think!

SliderHandle Touch Event

case TouchEvent.CLICK:case TouchEvent.DOWN:

if( touchEventOutOfBounds( message ) ) {return false;

}// fall through

case TouchEvent.MOVE:_pressed = true;setValueByTouchPosition( message.getX( 1 ) );fieldChangeNotify( 0 );return true;

case TouchEvent.UNCLICK:case TouchEvent.UP:

_pressed = false;invalidate();return true;

default:return false;

Page 42: Creating Custom Fields and Managers is Easier than You Think!

SliderSetting Notch By Touch Position

• The width of the entire slider is given by getContentWidth()

• Clamp the x coordinate of the touch between 0 and the width

• Think of the various notches as “buckets” and figure out which bucket the x coordinate falls into

• The thumb image ends up following the user’s finger

Page 43: Creating Custom Fields and Managers is Easier than You Think!

SliderTrackpad Interaction

• Trackpad must be used to– Navigate between screen elements

– Change the slider position

• Two options– Click to enter ‘edit mode’

– Interpret vertical movement as navigation and horizontal movement as position change

• Pros and cons of each…– Dedicated edit mode requires an extra click

– Consuming all horizontal movement makes assumptions about the overall screen layout

Page 44: Creating Custom Fields and Managers is Easier than You Think!

SliderClick to Edit

• Many different types of input…

keyChar()

navigationClick()

trackwheelClick()

invokeAction()

• May choose to be selective as to which keys activate the Pressed state

– Perhaps only react to SPACE or ENTER, for example

public void togglePressed() {_pressed = !_ pressed;invalidate();

}

Page 45: Creating Custom Fields and Managers is Easier than You Think!

SliderHandle Navigation Event

• When in edit mode, intercept navigation movements, change state, and notify field change listeners

– Otherwise, just pass them up to the superclass to handle

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

if( _pressed ) {if( dx > 0 || dy > 0 ) {

incrementValue();} else {

decrementValue();}fieldChangeNotify( 0 );return true;

}return super.navigationMovement( dx, dy, status, time );

}

Page 46: Creating Custom Fields and Managers is Easier than You Think!

SliderFinished Result

Page 47: Creating Custom Fields and Managers is Easier than You Think!

MANAGER BASICSa quick overview

Page 48: Creating Custom Fields and Managers is Easier than You Think!

Managers

A few things to consider when writing a custom manager:

1. Constructor

2. Layout (most of the work)

3. Navigation

Page 49: Creating Custom Fields and Managers is Easier than You Think!

The Box Model: Margins

Margin

Border

Padding

Content

Page 50: Creating Custom Fields and Managers is Easier than You Think!

The Box Model: Margins

Margins collapse

Page 51: Creating Custom Fields and Managers is Easier than You Think!

The Box Model: Margins

Margins collapse by the smallest amount

Page 52: Creating Custom Fields and Managers is Easier than You Think!

CREATING A TOOLBARby request from last year…

Page 53: Creating Custom Fields and Managers is Easier than You Think!

Toolbar Types

Equal Space

Evenly Spaced

Page 54: Creating Custom Fields and Managers is Easier than You Think!

Toolbar Types

Equal Space

Evenly Spaced

Page 55: Creating Custom Fields and Managers is Easier than You Think!

CREATING AN EQUAL SPACE TOOLBAR

Page 56: Creating Custom Fields and Managers is Easier than You Think!

Toolbar1) Constructor

• Manager extends Field, so their constructors are similar

• Managers also take a style bit

• Some managers use the style bit to control scrolling behaviour– Our toolbar will not scroll

– We don’t have to worry about the SCROLL styles…

Page 57: Creating Custom Fields and Managers is Easier than You Think!

Toolbar2) sublayout()

• In sublayout() we need to allocate space for our children and position them within our content area

• Two important helper methods– layoutChild()

– setPositionChild()

• Typically, we keep track of remaining space as we iterate through our children and lay them out

– Each child is only allowed to use the space its older siblings have not yet consumed

– But what if the eldest sibling is greedy and takes all the space?

– (see Dev 20 for one possible solution)

Page 58: Creating Custom Fields and Managers is Easier than You Think!

Typical sublayout() procedure

• Determine how much space the child can use

• Call layoutChild(), passing in the maximum size for the child– layoutChild() looks after handling border and padding for us

• Call child.getWidth() and child.getHeight() to determine how much space the child actually used

• Determine where the child belongs relative to the others and position it using setPositionChild()

Page 59: Creating Custom Fields and Managers is Easier than You Think!

Margin Support

• A common idiom for horizontal layout (for example)thisLeftMargin = Math.max(

child.getMarginLeft(),prevRightMargin );

. . .

layoutChild( child, x + thisLeftMargin, ... );

. . .

prevRightMargin = child.getMarginRight();

Page 60: Creating Custom Fields and Managers is Easier than You Think!

Field Alignment Support

• A common idiom for horizontal layout (for example)long valign = field.getStyle() & FIELD_VALIGN_MASK;

if( valign == FIELD_BOTTOM ) {

y = managerHeight- child.getHeight() – child.getMarginBottom();

} else if( valign == FIELD_VCENTER ) {

y = child.getMarginTop() + ( managerHeight - child.getMarginTop()

- child.getHeight() - child.getMarginBottom() ) / 2;

} else { // valign == FIELD_TOP

y = currentField.getMarginTop();

}

Page 61: Creating Custom Fields and Managers is Easier than You Think!

Margins and Alignment

• Margins and alignment together are a little tricky to figure out– Possibly multiple “correct” interpretations of how they should interact

• For example, which one is correct?

Content is centeredBut what if bottom margin gets larger?

Field is centered including marginsBut content is not centered

FIELD_VCENTER

Page 62: Creating Custom Fields and Managers is Easier than You Think!

Toolbar2) sublayout()

• For our Equal Space toolbar, we might be able to make some assumptions about our children to simplify things

– No child has a margin

– All children are the same height and each child will use all the width we give it, so alignment is irrelevant

• We could check these conditions when our children are added, if we wanted to be particularly careful

– Make sure they are all instances of a special class like ToolbarButtonfor example

Page 63: Creating Custom Fields and Managers is Easier than You Think!

Toolbar2) sublayout()

protected void sublayout( int width, int height ) {

int buttonWidth = width / numFields;int maxHeight = 0;

for( int i = 0; i < numFields; i++ ) {

Field button = getField( i );

layoutChild( button, buttonWidth, height );

setPositionChild( button, i * buttonWidth, 0 );

maxHeight = Math.max( maxHeight, button.getHeight() );

}

setExtent( width, maxHeight );

}

Page 64: Creating Custom Fields and Managers is Easier than You Think!

Toolbar3) Focus Navigation

• Can we prevent vertical input from causing horizontal movement?

– The automatic translation of vertical to horizontal movement is a vestige left over from the trackwheel days…

protected int nextFocus( direction, axis ){

if( axis == AXIS_VERTICAL ||

axis == AXIS_SEQUENTIAL ) {

return -1;

}

return super.nextFocus( direction, axis );

}

Page 65: Creating Custom Fields and Managers is Easier than You Think!

ToolbarFinished Result

Page 66: Creating Custom Fields and Managers is Easier than You Think!

CREATING A TWO COLUMN MANAGERlining things up

Page 67: Creating Custom Fields and Managers is Easier than You Think!

Two Column ManagerThe Goal

Page 68: Creating Custom Fields and Managers is Easier than You Think!

Two Column ManagerThe Goal

• A set of fields arranged vertically

• Each field may be divided into two horizontal parts

• Determine an appropriate place for the division between the parts so the fields line up in columns

• Respect alignment and margins of the fields– Margins between cells won’t overlap (for simplicity) but will be

respected within each cell

Page 69: Creating Custom Fields and Managers is Easier than You Think!

Basic Strategy

• Create a custom Two Column Field (actually a Manager) that will share the layout work with the Two Column Manager

• The layout work becomes a little more involved1. Lay out the left part of each child

2. Figure out how wide to make the left column based on the size required by each child

3. Lay out the left and right part of each child

Page 70: Creating Custom Fields and Managers is Easier than You Think!

Before

Page 71: Creating Custom Fields and Managers is Easier than You Think!

Layout the Left Fields

Widest Left Field

Page 72: Creating Custom Fields and Managers is Easier than You Think!

Layout Everything

Page 73: Creating Custom Fields and Managers is Easier than You Think!

After

Page 74: Creating Custom Fields and Managers is Easier than You Think!

Two Column Manager

• Can operate as a basic vertical manager

• Lays out children top to bottom, respecting margins and alignment

• During layout, it looks for children that are TwoColumnFields

• Performs some specialized work for each one so that they are aligned in columns

Page 75: Creating Custom Fields and Managers is Easier than You Think!

Two Column Field

• Takes a left field and a right field– No reason these couldn’t be managers!

– Allows for some complicated nested structures

• Each of these fields is optional– If one isn’t provided, we create a NullField for convenience

• Two layout-related methods– layoutLeft() lays out only the left field and returns the width it would

like to consume

– sublayout() assumes that the left column width has been determined and lays out both fields accordingly

Page 76: Creating Custom Fields and Managers is Easier than You Think!

TwoColumnManager.sublayout()

• For each child that is a TwoColumnField, call layoutLeft()

• Keep track of the widest desired left column– Optionally restrict it to some maximum value so the left column can’t

take up the entire width

• For each child that is a TwoColumnField, set the left column width

• Go through all of the children and perform a ‘typical’ vertical layout

– Respect the margins and alignment of the children

Page 77: Creating Custom Fields and Managers is Easier than You Think!

TwoColumnField.layoutLeft()

• Make sure we deduct the space required by the left field’s margins

• Simply call layoutChild()

• Return the desired width of the entire left column

width = width - marginLeft - marginRight;

height = height - marginTop - marginBottom;

layoutChild( _leftField, width, height );

return marginLeft + _leftField.getWidth() + marginRight;

Page 78: Creating Custom Fields and Managers is Easier than You Think!

TwoColumnField.sublayout()

• The last piece of the puzzle!

• Calculates the width and height available for each column using the left column width provided by the manager

• Calls layoutChild() on each field to lay them out…

layoutChild( _leftField, leftWidth, leftHeight );

layoutChild( _rightField, rightWidth, rightHeight );

Page 79: Creating Custom Fields and Managers is Easier than You Think!

TwoColumnField.sublayout()

• …then positions them (just one example)long halign = field.getStyle() & FIELD_HALIGN_MASK;

if( halign == FIELD_RIGHT ) {

leftX = _leftColumnWidth- _leftField.getWidth() - leftMarginRight;

} else if( halign == FIELD_HCENTER ) {

leftX = leftMarginLeft+ ( _leftColumnWidth - leftMarginLeft

- _leftField.getWidth() - leftMarginRight ) / 2;

} else { // valign == FIELD_LEFT

leftX = leftMarginLeft;

}

• Nothing complicated here, just a bit tedious!

Page 80: Creating Custom Fields and Managers is Easier than You Think!

Two Column ManagerThe Result

Page 81: Creating Custom Fields and Managers is Easier than You Think!

OPTIMIZING LAYOUT AND PAINTknowing what happens when

Page 82: Creating Custom Fields and Managers is Easier than You Think!

Optimizations

ConstructorCache bitmaps, strings, and other static content

applyFont()Derive fontsMeasure text

layout()Cache dimensionsCalculate internal positioning

paint()Manipulate Graphics objectUse cached values to paint content

Happens Once

Happens Often

Field Created

User Changes Font

Field Added / RemovedDevice Rotated

Screen ScrollsFocus Changes

Page 83: Creating Custom Fields and Managers is Easier than You Think!

SESSION SURVEY

We value your opinion about the content in this talk and how it was presented.

See us after the talk and say “More like this!” or “I’d like to see something else!”

Please fill out the session survey.

Page 84: Creating Custom Fields and Managers is Easier than You Think!

Thank YouTerrill Dent, Michael Brown

DEV 19September 27, 2010