Example 3: Using Multiple Anchors with AttributeConstraint
This last example won't be discussed in nearly as much detail as the others,
but it illustrates a useful feature that might otherwise be missed.
allows you to specify the names of more than one component to use as an "anchor"
for the constraint, as a comma-delimited list. When you do this, it calculates
a bounding box, the smallest rectangle that contains all of the components
in the list, and gives you access to the attributes of this bounding box.
To show a situation in which this can be useful, imagine you're creating a styled text editor, and you want to create a formatting dialog with a bunch of check boxes representing the different styles that can be combined, and a text area showing a sample of what the resulting text would look like. With more than a few styles, you might need multiple columns of text boxes. How can you get them to line up nicely? You could probably guess which of the checkboxes is longest, and use it as the anchor. But even if you guess right, the layout will break if someone later changes the text (for example, to localize the program for a different language).
AttributeConstraint's support for multiple anchors lets you cope
with this easily. By using the bounding boxes around an entire column of choices
to build the constraint for the next column, you don't have to worry about which
item is the longest. This also lets you constrain the position of the sample
text. Here's what the resulting window looks like:
Apart from creating a different set of Swing components, the Java source for this example is very similar to Example 2. Many of the XML constraint definitions are as well, but there are a couple worth highlighting. Here's how the "strikethrough" checkbox is positioned:
<constrain name="s"> <top> <toAttribute reference="bold" attribute="top"/> </top> <left> <toAttribute reference="bold,italic,underline" attribute="right" offset="10"/> </left> </constrain>
top is aligned with the "bold" checkbox in the same
way we've been doing it all along, but the
left is constrained
to fall ten pixels past the
right of the bounding box around all
three of the "bold", "italic," and "underline" checkboxes. Since "underline" is the widest, and they're all lined up along their left edges, this positions "strikethrough" just to
the right of "underline." The sample text area uses the same approach,
but leaves a larger gap of twenty pixels between its left edge and the second
column of styles:
<constrain name="sample"> <top> <toAttribute reference="caption" attribute="bottom" offset="4"/> </top> <bottom> <toAttribute reference="apply" attribute="top" offset="-10"/> </bottom> <left> <toAttribute reference="s,tt,em,strong" attribute="right" offset="20"/> </left> <right> <toAttribute reference="_container" attribute="right" offset="-10"/> </right> </constrain>
This also nestles it below the "Sample Text:" caption and above the "Apply" button, and puts its right side ten pixels from the edge of the window.
The Java source for this example is Example3.java and the constraints are defined in example3.xml. Running it requires the same class path as Example 2.
That's all there is to using
RelativeLayout. These examples provide
an introduction to some of the practical ways it can be applied. I hope that reading
them has brought to mind an instance or two where it would have simplified building
an interface. Although there are many more useful ways to combine constraints
and anchors than we've explored here,
RelativeLayout can't handle
every imaginable situation by itself. You'll still sometimes need to nest containers
and enlist the help of other layout managers, though perhaps less often than
Should you enjoy experimenting beyond the examples, there are some pretty impractical
arrangements you can set up, too. Nothing prevents you from constraining an
attribute to a bizarrely unrelated one, even on a different axis (for example,
left of one component based on the
of another). Such arrangements can behave in very odd ways. Of course, unless
you're trying to set up puzzles for someone along the lines of "resize
this window a few times and see if you can identify the constraints I used,"
you're unlikely to do such a thing.
If you read on through the discussion of how
works, you'll also see that it can support completely new kinds of constraints,
too. If you can think up a useful addition to
AxisConstraint, I'd love to hear about it. Another exercise
that's been "left for the reader" is to add multiple-anchor support
AxisConstraint. If you do that, it would make sense to move
the supporting code to an abstract skeleton that is a new ancestor to both
AxisConstraint (and any future constraint that might want to
support multiple anchors). But I'm getting ahead of myself -- if you're interested
in this sort of discussion, be sure to read the "under the hood" section.
Origins of RelativeLayout
Before digging in to the source code and explaining how everything works, I'd like to pause to acknowledge the books and people that were most instrumental in enabling and motivating me to create this tool.
The key concepts were first introduced (to me, anyway) by the "Custom
Interdependent Layout Manager" detailed in Philip Heller and Simon Roberts'
Java 2 Developer's Handbook (SYBEX). I found their
to be a terrific idea, and immediately wanted to go further with it.
Their book predated the availability of convenient XML tools in Java, which
forced a much more awkward and cryptic configuration mechanism on them. Although
the code worked just fine in JDK 1.1, it didn't take advantage of the more modern
Collections framework, nor the kind of refined object-oriented
API that can be achieved in a mature Java program. In fact, with all due respect
to clean and working code, many pieces seemed to have been ported just far enough
from C to pass muster with the Java compiler.
I felt I owed it to the great ideas embodied by the algorithms to give them
a new expression, writing a similar layout manager while thinking "What
Would Joshua Do?" Joshua Bloch is, of course, the author of the truly indispensable
Effective Java Programming Language Guide (Addison Wesley Professional),
as well as the aforementioned
makes extensive use of such useful Java idioms as the type-safe enumeration,
interfaces, and immutability. It's designed to form an extensible API so that
you can come up with new constraint types of your own and plug them right in.
These features will be illustrated in more depth in the next part of this series.
I hope Philip and Simon like the younger sibling inspired by their own creation. (And, actually, Philip had another impact on this project: his two-day Java University course was a big help developing my expertise in the language when I finally started using Java professionally in the spring of 2000.)
Finally, I have to thank Marc Loy again for convincing me that I should start
writing for a larger audience than my project teams at work. Getting me involved
in the revision of Java Swing is what pushed me over the edge into actually creating
RelativeLayout, after thinking about it for almost
If you'd like to look at how the internals of the layout manager actually work, my next article will examine its design and source code.
James Elliott is a senior software engineer at Singlewire Software, with fifteen years' professional experience as a systems developer.
Return to ONJava.com.