Monday, April 11, 2011

Color changing rounded rectangles and Android

I recently came across an interesting problem. I needed to have a rounded rectangle as the background of one of my widgets, but I needed to allow the border color of the rounded rectangle to be set by a configuration setting.

Before the color changing requirement showed up, I was using a 9-patch to create my rounded rectangle. It was simple, and worked quite well. So, after some digging I came to the conclusion that I would need to change the colors in the 9-patch image in order to achieve my goals. I ended up burning a lot of time trying to figure out how to do this. (It isn't as simple as changing the colors in a normal .png file, unfortunately.)

While digging, I came across this post that hinted that I might not need the 9-patch to do what I wanted. But, the documentation for the shape XML is pretty much non-existent. Which made things hard.

A little more digging found an article that linked to this page. This provided me the attributes for the XML that allow me to do what I needed to do. So, I set out to give it a shot. I started with a rounded rectangle with a white background and a black line around the outside. The XML looked like this :

<!--?xml version="1.0" encoding="utf-8"?-->
<shape android="http://schemas.android.com/apk/res/android" shape="rectangle">
<solid color="#ffffffff">
<stroke width="2dip" color="#ff000000">
<corners radius="75dip">
</corners></stroke></solid></shape>


When I created the XML file in eclipse, there wasn't an option to create a shape XML file. So, I picked one of the other types, and just deleted what was automatically created, and replaced it with the code above. However, I also needed to move the XML file so that it was in the drawable directory. (If you are like I was, you are thinking, "But an XML file isn't a drawable!" But, you'll just have to trust me.)

This provided me the basic rounded rectangle that I needed. But, changing colors on-the-fly was still an issue. After a bit of digging, I found that using this XML to create a drawable would give me everything I needed to get the job done.

I decided to set the background for the layout that contained everything I was going to use. (Which is why I am using a LinearLayout instead of some other widget. But, any widget that allows a background to be set should work.)

For a test, I changed my onCreate() method to include this code :

workareaLayout = (LinearLayout)findViewById(R.id.rightColumnInner);

GradientDrawable sd = (GradientDrawable)this.getResources().getDrawable(R.drawable.roundrect);
sd.setColor(0xff00ff00);
sd.setStroke(10, 0xffff0000);
workareaLayout.setBackgroundDrawable(sd);

This created a nice rounded rectangle that is suitable for Christmas. (It has a green background with a large red border.)

The sd.setColor() call sets the background color for the rectangle. The color is an ARGB value, so we start with 0xff since we don't want any transparency. The 00ff00 portion indicates that we want to be the brightest green we can have.

The sd.setStroke() call specifies the width of the border line, along with the color. For this example, the width is 10, and the color is bright red, with no transparency. The documentation isn't clear what a width of "10" means. (Is it pixels? Or one of the other measures commonly used in Android development?) But, it appears that it is probably pixels.

And with that, you should have the ability to create all kinds of crazy rounded rectangles. However, keep in mind that this same method should work for other types of shapes that can be created with the shape XML.