Borders, Corners and Shadows, Oh My!

Ever have the problem of getting a UI composite and wondering how you are going to implement it? I had one such example come across an internal Flex questions list the other day. I’ve been helped countless times by the list, so I try to at least put some thought into every question that comes across. This one however had screenshots of the problem inline with the question. It caught my attention and I couldn’t help but think that “we should be able to do that with Flex.”

The challenge was to provide an embossed look to a user-selected portion of the user interface. There were places where some corners were rounded and others were not. Along the edge of the selection region were also different color lines for horizontal and vertical orientation. The embossed feel needed to be maintained evenly across control/containers as well.

Here’s a Captivate recording of the final result to give you an idea of what needed to be accomplished:

While Flex does provide for having rounded corners via CSS, it doesn’t give you the ability to specify which corners, or to have corners of varying radius’s. The CSS options are also limited to a single border color (in most cases). If you’re like me this means you’re looking at making a skin. I prefer programmatic skinning where I can, and in this case of just a few lines and a fill, it seemed to add the least weight.

Using a programmatic skin gets a lot of this problem out of the way - or so it seems.

How about that embossed look? You might think that this would be a simple DropShadowFilter with the “inner” property set to “true”. The problem with this is that the inner option is applied to the inside of the DisplayObject. That means our nicely drawn border lines are going to be replaced by the shadow, which will start at the edges of our DisplayObject.

To get around this problem I stacked visual effects. I first created a programmatic skin for just the border lines and rounded corners. I applied that skin to one container. Then I made another skin that made the same lines, but also filled the space. I placed the second, filled, skin on another container which was then placed under the first container (z-order). Finally the filter is applied to the lower of the two containers.

You might think that this would be enough, but there’s another problem that the filter introduces.

Given the filled the dimensions of lower container, the inner shadow isn’t going to be carried nicely over to any other components - remember that we need multiple components to look like they’re part of the same selected area. This is especially important as the shadow goes to wrap itself around corners of “connecting” components.

To address this problem I had the skin draw the connecting edges to include the corners, and then to extend to “overlap” any connecting area. Then I applied a mask to the entire component, and intentionally left out the space that was extended as an overlap. This let the shadow be applied to everything, including the extended connecting edge, but only revealed those parts we were interested in displaying visually.

As it turns out, as I went to implement this solution, I came up with at least two different ways to address the problems that surfaced. Since I had already completed this approach however, I decided to stick with it. I have no doubt that this could be further refined.

I built in some fun states to allow the “button” to have different [complex] views depending on user selection. Again with hindsight being what it is, I could have parameterized the different states as children components. This would have allowed for more reusability. I was really only interested in the embossed part though, and it’s time to move on to the next project.

I’m guessing that following all of this is probably pretty challenging. We’re looking at layered programmatic skins with filters and masking. That’s a lot to say not to mention to understand with limited visuals. Well, it’s source code to the rescue then, which you should feel free to play with and explore. I’ve also posted the application itself which for your viewing pleasure.

WordPress database error: [Can't open file: 'wp_comments.MYI' (errno: 145)]
SELECT * FROM wp_comments WHERE comment_post_ID = '26' AND comment_approved = '1' ORDER BY comment_date

Leave a Reply