Fork us on GitHub

Round Border

A new border type for smoother round UI's
Post Image

Round Border

Circles and completely round border sides are problematic for multi-resolutions. You need to draw them dynamically and can’t use image borders which can’t be tiled/cut to fit round designs. Up until now we recommended using background images or changing the design entirely but now we have a new option: RoundBorder.

We designed the RoundBorder to enable two distinct types of borders:

  • Circular borders - e.g. Android floating action

  • Rectangles with round (not rounded) sides

Notice that this border doesn’t address the case of rounded corner border.

Currently we don’t have a way to define this border from the theme and we are still ironing out all the features that will go into it but we already have the basic underpinnings.

Border Builder

A round border is created using the builder pattern. You can get a new instance using RoundBorder.create(), this will produce a red circular border with no shadow or stroke. You can then chain operations together to produce various effects e.g. this is our starting point:

Form hi = new Form("Round", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_CENTER));
Label l = new Label("X");
l.getUnselectedStyle().setAlignment(Component.CENTER);
l.getUnselectedStyle().setBorder(
        RoundBorder.create()
);
hi.add(BorderLayout.CENTER, l);
hi.show();
Plain round border with no options
Figure 1. Plain round border with no options

We can set the color:

RoundBorder.create().color(0xff)
Round border with blue color
Figure 2. Round border with blue color

We can change the opacity:

RoundBorder.create().color(0xff).opacity(100)
Round border with blue color and transparency
Figure 3. Round border with blue color and transparency

Border can have drop shadows, however since they increase the size required for the border we also added some padding to the code:

Form hi = new Form("Round", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_CENTER));
Label l = new Label("X");
l.getUnselectedStyle().setAlignment(Component.CENTER);
l.getUnselectedStyle().setPaddingUnit(Style.UNIT_TYPE_DIPS);
l.getUnselectedStyle().setPadding(5, 5, 5, 5);
l.getUnselectedStyle().setBorder(
        RoundBorder.create().shadowOpacity(90)
);
hi.add(BorderLayout.CENTER, l);
hi.show();
Round border with dropshadow
Figure 4. Round border with dropshadow

You can control the shadow spread (how big it is), its opacity, blur & x/y position (to create light source perspective).

So if we want a slightly larger shadow from a light source coming from the top right we can do something like this:

l.getUnselectedStyle().setPadding(3, 8, 8, 3);
l.getUnselectedStyle().setBorder(
        RoundBorder.create().shadowOpacity(90).
                shadowSpread(Display.getInstance().convertToPixels(4)).
                shadowX(1).
                shadowY(0)
);
Notice that we had to change the padding so the X will remain the center as the border is now larger on the bottom left sides due to the shadow.
Larger dropshadow that is cast to the bottom left
Figure 5. Larger dropshadow that is cast to the bottom left

Round borders can also be used for more rectangular shapes such as this:

Label l = new Label("Label Text");
l.getUnselectedStyle().setAlignment(Component.CENTER);
l.getUnselectedStyle().setBorder(
        RoundBorder.create().rectangle(true)
);
Rectangle mode in the round border
Figure 6. Rectangle mode in the round border

We can even stroke round borders with a line around the edges & all of the operations work on circles/rectangles etc! To stroke we need to define the Stroke object and can optionally define color/opacity for the stroke:

RoundBorder.create().rectangle(true).stroke(new Stroke(2, Stroke.CAP_SQUARE, Stroke.JOIN_MITER, 4)).
        strokeColor(0xff).strokeOpacity(120)
Stroked round rectangle
Figure 7. Stroked round rectangle

Putting it all Together

The sample below puts all of these features together into a single UI that works well in portrait/landscape and all DPI’s. We chose to use hardcoded style settings so the sample will be self contained:

Form hi = new Form("Round", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_CENTER));

Button ok = new Button("OK");
Button cancel = new Button("Cancel");

Label loginLabel = new Label("Login", "Container");
loginLabel.getAllStyles().setAlignment(Component.CENTER);

Label passwordLabel = new Label("Password", "Container");
passwordLabel.getAllStyles().setAlignment(Component.CENTER);

TextField login = new TextField("", "Login", 20, TextArea.ANY);
TextField password = new TextField("", "Password", 20, TextArea.PASSWORD);
Style loginStyle = login.getAllStyles();
Stroke borderStroke = new Stroke(2, Stroke.CAP_SQUARE, Stroke.JOIN_MITER, 1);
loginStyle.setBorder(RoundBorder.create().
        rectangle(true).
        color(0xffffff).
        strokeColor(0).
        strokeOpacity(120).
        stroke(borderStroke));
loginStyle.setMarginUnit(Style.UNIT_TYPE_DIPS);
loginStyle.setMargin(Component.BOTTOM, 3);
Style passwordStyle = password.getAllStyles();
passwordStyle.setBorder(RoundBorder.create().
        rectangle(true).
        color(0xffffff).
        strokeColor(0).
        strokeOpacity(120).
        stroke(borderStroke));


Container box = BoxLayout.encloseY(
        loginLabel,
        login,
        passwordLabel,
        password,
            GridLayout.encloseIn(2, cancel, ok));

Button closeButton = new Button();
Style closeStyle = closeButton.getAllStyles();
closeStyle.setFgColor(0xffffff);
closeStyle.setBgTransparency(0);
closeStyle.setPaddingUnit(Style.UNIT_TYPE_DIPS);
closeStyle.setPadding(3, 3, 3, 3);
closeStyle.setBorder(RoundBorder.create().shadowOpacity(100));
FontImage.setMaterialIcon(closeButton, FontImage.MATERIAL_CLOSE);

Container layers = LayeredLayout.encloseIn(box, FlowLayout.encloseRight(closeButton));
Style boxStyle = box.getUnselectedStyle();
boxStyle.setBgTransparency(255);
boxStyle.setBgColor(0xeeeeee);
boxStyle.setMarginUnit(Style.UNIT_TYPE_DIPS);
boxStyle.setPaddingUnit(Style.UNIT_TYPE_DIPS);
boxStyle.setMargin(4, 3, 3, 3);
boxStyle.setPadding(2, 2, 2, 2);

hi.add(BorderLayout.CENTER, layers);

hi.show();
Sample containing round border variants
Figure 8. Sample containing round border variants
Share this Post:

Posted by Shai Almog

Shai is the co-founder of Codename One. He's been a professional programmer for over 25 years. During that time he has worked with dozens of companies including Sun Microsystems.
For more follow Shai on Twitter & github.