Developing widgets for the Android platform involves a slightly different set of tasks than standard app development. In this series of tutorials, we will work through the process of developing a customizable analog clock widget. The clock will be based on the Android AnalogClock class and customized with your own graphics.
In this tutorial series we are developing a customizable Android analog clock widget using the AnalogClock class and custom graphics. In the first part of the series, we create the project, preparing the Manifest file and other resources. In this part, we will work on the widget design. This will involve creating graphics for the clock dial and hands, as well as implementing the layout in XML. We will create graphics for different device densities. In the final part of the series, we are going to implement letting the user choose from a selection of designs for the clock, so we will create three design options here.
This is Part 2 of our series on Building a Customizable Android Analog Clock Widget over four tutorials:
- Android Widget Project Setup
- Designing the Clock
- Receiving Updates and Launching
- Implementing User Configuration
The Android AnalogClock widget uses three images: the clock dial, the minute hand, and the hour hand. We will therefore create three design elements for each version of the clock widget we want users to be able to choose between. We will also create alternative design options with dial, hour, and minute hands. For this project, we will need to target different device screen densities, for which we will create image files at four different scales.
Step 1: Create Images for the Clock Dial
We are going to create three clock designs, each with a dial, minute hand, and hour hand. You can of course use your own designs instead, but feel free to use the image files we are using here to get started. The image files for each design at each density are included in the download link for this tutorial and will also be included in the download for Part 4.
First up is the clock dial. Remember that we specified the widget as being two cells wide and two cells high, resulting in a maximum size of 146dp (density-independent pixels). For this tutorial series we will create four versions of each image to suit the four density categories.
Instead of creating images for each density, you can alternatively use NinePatch graphics, which are bitmaps that can be scaled up and down to suit device densities, allowing you to create a single image for each design. The feasibility of using NinePatch depends partly on the content of the designs you are using but there are tools to help you create them if you wish.
It's easiest if you start with the medium density, which should be a maximum of 146px on both axes. Here is the default clock dial we are using at medium density, which you can use either as a reference for your own designs or if you don't want to create your own until later:
In this case, the image is 146px on both axes, but you can make it smaller if you wish. We will specify a margin for devices running Android APIs less than 14 but will not supply a margin for devices on 14-plus, because at the more recent API levels an automatic margin is placed between widgets. You can use pretty much any design you like - your clock doesn't even have to be circular. Including either marks or numbers indicating the hours on the dial is advisable from a usability perspective although it is not essential.
Here are the two alternative clock dial designs we will be using, one stone style and the other metallic, displayed here at medium density:
Once you have your clock dials designed, you can create alternative versions of each image for the different densities. Depending on your designs this may not be necessary, but we will be including tailored versions of each image for the designs in this tutorial. The following indicates the maximum size we are using for our widget on both the X and Y axes at each density:
- Low density: 110px
- Medium density: 146px
- High density: 220px
- Extra high density: 292px
When you have image files for each clock dial design you want to use (and versions for each density if appropriate), copy them to the drawable folders in your Android widget project workspace. Eclipse will normally create a folder for each density category automatically, but, if you are only using one image for all densities, you can create a folder simply named "drawable" and place the image there. The folders for each density level are:
- Low: drawable-lpdi
- Medium: drawable-mpdi
- High: drawable-hpdi
- Extra high: drawable-xhpdi
The Android AVD Manager will allow you to test your finished widget project at each of these densities. After you have your images saved into the various drawable folders make sure you have used the same names in each of them. For example, one of the dial designs we are using is named "clock_dial_stone" -this is the image filename for the stone dial in each density folder although the content of each version is different if only in size. If you're still in doubt about how this should work, just download the image files using the download link at the top of this tutorial and browse the folders to get the idea.
Step 2: Create the Clock Hand Images
Next create an image for your clock widget hour and minute hands, including images for each design and each density you are targeting. Here are our medium density minute hands for each design:
Again, feel free to use these to start with or to work out your own. Notice that these image files contain transparent space around the hand. You need to design each of your hand images with the full height of the clock dial they are going to be used with. Each hand needs to be in the exact position it would be in when pointing to twelve, laid over the clock dial image and half-way across it. The hand must also be in the center of its image file horizontally, as it will be rotated from its central point when displaying the time. The length of the hands within the image file is really up to you, as long as the full height of the image is the same as the height of the dial image.
The following diagram shows the full scale of the hand images with the minute hand at twelve and the hour hand at three (the hour hand has been rotated 90 degrees clockwise on its central point):
Once you have your minute hand designs sorted, save one for each density again, scaling them up and down to match the clock dial height in each case. Copy them into your drawable folders again, using the same name for each design across the density folders as with the dial images.
Next carry out the same process for your hour hands. Here are the hour hands for the three designs we are using:
The principle here is the same as for the minute hands, except that the hour hands should typically be shorter. Design your hour hands pointing to 12 o'clock and prepare versions for each density, copying them into your drawable folders as you did for the minute hands.
Step 3: Define Widget Margins
The widget design is going to use some data we will include in our project "values" folders. On Android API 14 and onwards, the system automatically includes margins between widgets as they appear on the user's homescreen. However, on previous API versions this was not the case. For this reason we want to specify a margin to include around the clock widget on devices running Android levels less than 14. This is a case where we can exploit the fact that we have values folders targeting these two categories of user API levels.
We will define the margins in our XML layout file by referring to a dimension resource. In the "values" directory, create a new file named "dimensions.xml" - select the "values" folder in Eclipse and right-click or choose "File", then "New", "File" and enter the file name.
When you click the "Finish" button, Eclipse will create and open the file. Select the "dimensions.xml" tab to edit the code. Enter the following:
<resources> <dimen name="clock_margin">8dp</dimen> </resources>
This code simply lists a dimension value using density-independent pixels along with a name so that we can refer to it elsewhere.
Save the file. Now copy it by right-clicking it in the "values" folder or selecting it and choosing "Edit" - then select "Copy". Paste it into the "values-v14" folder we created last time - right-click or select the folder and choose "Edit", then select "Paste". The file will appear in the "values-v14" folder, which targets API levels from 14 onwards. Open this new copy of the file and edit the dimension value to indicate a margin of zero as follows:
<resources> <dimen name="clock_margin">0dp</dimen> </resources>
Now when the XML layout refers to this dimension value using its name, a value of zero will be used on devices running API 14 plus and a value of 8dp will be used otherwise.
Step 4: Implement the Widget Layout
Now let's define our widget in XML. Remember that we specified an initial layout for the widget in the XML file in which we defined its basic properties. The layout we referred to there was "clock_widget_layout" so create this file now. Right-click or select your "layout" folder and choose "File" then "New," "File". Enter "clock_widget_layout.xml" as the file name and click "Finish".
Select the "clock_widget_layout.xml" tab when Eclipse opens the file so that you can edit the XML. We are using a Relative Layout for our widget - if you wish to use a different design, you can alternatively use either a Linear or a Frame Layout, as these are the only ones supported by widgets. To use the Relative Layout, add the following outline to your XML layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/custom_clock_widget" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="@dimen/clock_margin" android:gravity="center"> </RelativeLayout>
Here we specify an ID for the widget, which we will use to implement clicks on it in our Java code in Part 4. Notice that the code also refers to the dimension value we created, using the standard syntax - the name of the "dimensions.xml" file does not actually matter, you just need to list a "dimen" element in a values file to refer to it in this way.
Inside the Relative Layout, add your AnalogClock widget as follows:
<AnalogClock android:id="@+id/AnalogClock0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:dial="@drawable/clock_dial" android:hand_hour="@drawable/clock_hour_hand" android:hand_minute="@drawable/clock_minute_hand" />
This is the standard Android Analog Clock element, which allows us to customize the display. We use an ID attribute so that we can refer to the widget in Java. The final three attributes specify the drawable resources we created for the dial, minute, and hour hands. If you saved yours with different file names, alter this code to reflect them. Android will select the drawable file from the relevant density folder on each user device.
Since we are allowing users to choose a design, we are actually going to include all three designs in our XML, setting all except one to be initially invisible. Make sure the first design you include is the one you want to display by default, then add the others as follows:
<AnalogClock android:id="@+id/AnalogClock1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:dial="@drawable/clock_dial_stone" android:hand_hour="@drawable/clock_hour_hand_stone" android:hand_minute="@drawable/clock_minute_hand_stone" android:visibility="invisible" /> <AnalogClock android:id="@+id/AnalogClock2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:dial="@drawable/clock_dial_metal" android:hand_hour="@drawable/clock_hour_hand_metal" android:hand_minute="@drawable/clock_minute_hand_metal" android:visibility="invisible" />
Again, alter the drawable names to reflect the names for the dials, minute, and hour hand images for each of your designs. You can include more than three designs if you wish - make sure all except one of them has the visibility set to invisible, so that only one design (the default option) appears initially. We will be able to implement user choice between these designs in Java using the Analog Clock element ID attributes, which all end with integers starting at zero and incrementing with each design. Save your layout file.
Here are screengrabs of how each of our designs will look when the widget is complete:
That's the design process for our clock widget complete. If you don't want to create your own design images at this stage, just use the images in the download folder at first. In the next tutorial we will use the AppWidgetProvider class to implement our widget in Java. In the final part of the series we will implement user clicks on the widget, presenting a choice between the designs and updating the user preferences to continuously display their chosen option.