Skip to content


BlackBerry UI - Creating a basic field manager

If you build apps using RIM’s BlackBerry user interface classes (and if you’re trying to build professional applications on BlackBerry, you should be using them) sooner or later you’ll have to start building your own field managers.

Creating managers is actually very easy. I’ll proceed by way of illustrative example - how to code a manager from scratch.

Centering

My previous post created a simple Hello World app - containing one screen with a single LabelField.

That label field appears at the top-left of the screen. What if we wanted to center it at the top of the screen?

We could try changing a couple of things. First, by reading the BlackBerry Javadocs, you might notice that the MainScreen (from which our screen is derived) automatically uses a VerticalFieldManager - maybe what we want to do is to embed our LabelField into a HorizontalFieldManager, set the style of our LabelField to FIELD_HCENTER and add that to the screen? We’ll make the HorizontalFieldManager use all width just to be on the safe side.

Try it:

LabelField lf = new LabelField("Hello World!", Field.FIELD_HCENTER);
HorizontalFieldManager hfm = new HorizontalFieldManager(Manager.USE_ALL_WIDTH);
hfm.add(labelField);
add(hfm);

Not centered
What gives? USE_ALL_WIDTH doesn’t seem to do what it should do.

Now, I can tell you that HorizontalFieldManager can be tweaked to make it center the field in the screen, but since we’re talking about managers, let’s instead fix this problem by creating our own.

Managers

Manager is an abstract class, with one abstract method - sublayout(int width, int height)

What sublayout is passed in are the width and height of its parent - the manager that contains it, which continues up to the top level screen. This is another thing about BlackBerry UIs - you’ll probably end up dealing with nested managers, so try to visualize which manager contains which.

A little exploratory coding tells us that when we add a manager directly to the screen, it is indeed passed the full screen width. So our task is pretty easy. We have to:

1. Get our centered field (for simplicity, we’ll assume we’re only going to ever add one field to this manager)
2. Get the width and height of the field to be centered
3. Figure out where to position the field to center it, based on the field’s width
4. Make our manager take up the entire available width

The code to do this is straightforward:

public class CenteredFieldManager extends Manager {

       // ... constructor, etc

	protected void sublayout(int width, int height) {
		if (getFieldCount() > 0) {
			Field centeredField = getField(0);  // get the first (and only) field
			layoutChild(centeredField, width, height); // set the field's width and height
			setPositionChild(centeredField, (width-centeredField.getWidth())/2, 0);  // center the field horizontally
			setExtent(width, centeredField.getHeight());  // set the size of this manager to use the entire screen width
		}
	}
}

Note that we call layoutChild before setPositionChild. The order is important. Why?

layoutChild basically says: “You have this much space to draw yourself - how much will you need?” (the actual drawing happens later)
The LabelField will figure out how wide its string will be when drawn in its font, and if that is less than the width available, it will set itself to the string width - similarly for height. You can access those dimensions with getWidth and getHeight only after the field has been laid out. If we had called getWidth on the field before calling layoutChild, the field wouldn’t have calculated its necessary dimensions yet, and we would have gotten back a useless value (0, as it turns out), and couldn’t have calculated the centered position.

Now changing our earlier code to use our new manager:

LabelField lf = new LabelField("Hello World!", Field.FIELD_HCENTER);
CenteredFieldManager cfm = new CenteredFieldManager(0);
cfm.add(labelField);
add(cfm);

Centered!

And we get our desired result. Ta-da!

Generally

Coding managers generally involves the same steps as in our very simple example.
Implement sublayout in which you:
1. Iterate over all the fields
2. Call layoutChild and setPositionChild for each field
3. Call setExtent for the manager

Those are the basic building blocks - basically playing with layouts and nesting a bunch of managers can lead to something like this (a project I worked on about a year ago)

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google

Posted in basics, ui. Tagged with , , , .

12 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. idev said

    Hi Anthony

    I am trying to add multiple buttons to my HFM and want to center them on the top part of the screen. I tried creating a Manager and using it to set the buttons in title but am not getting the desired result. Can you please give some details as when the setLayout is called and how to use it in my particular case.

    Thanks.

  2. Russ said

    Wow, I have been trying to center a List of 15 BitmapFields for about a week now..This worked instantly!!! thanks

  3. Hi,
    Nice tutorial. Several examples refer to add(labelField), however they should actually read add(lf). Hope this helps!
    Jason

  4. Cijal said

    Great tutorial. Thanks !!

  5. Pankaj said

    Any one know what the constructor would be? New to Java.

  6. And that darned grail-shaped beacon. ,

  7. Charlie said

    @Pankaj Just call the super constructor and pass along the style param…that’s probably the most sensible thing to do.

  8. sahana udaya said

    I want to design a UI as below:
    1) a top manager with title and image
    2) a middle manager with left and right arrow on either ends then another manager with some information which changed data on scrolling.
    3) bottom manager with some buttons

  9. Tammy said

    Brilliant - helped very much with my understanding!!

  10. Austin Rappa said

    Excellent tutorial. For those who want to center multiple fields then the sublayout method of CenteredFieldManager would look like this:

    //Layout fields to center
    protected void sublayout(int width, int height)
    {
    if (getFieldCount() > 0)
    {
    int maxheight = 0;
    for (int i = 0; i < getFieldCount(); i++)
    {
    Field centeredField = getField(i); // get the first field
    layoutChild(centeredField, width, height); // set the field’s width and height
    setPositionChild(centeredField, ((width / (getFieldCount() + 1)) * (i + 1)) - (centeredField.getWidth() / 2), 0); // center the field horizontally
    maxheight = Math.max(maxheight, centeredField.getHeight()); //get the maximum height
    }
    setExtent(width, maxheight); // set the size of this manager to use the entire screen width
    }
    }

  11. Steve said

    Thank you for this post and blog, has been really helpful!

  12. anil said

    good work….

Some HTML is OK

(required)

(required, but never shared)

or, reply to this post via trackback.