2. Who? What? Why?
Hi, I’m Matt Gaunt (@gauntface) I’ve been developing on Android, on and off, for the past 2
years (starting from the 0.9 SDK).
The reason I’ve put this document together is to help others with things I struggled with when
I first started out, to help others learn new things with Android UI and to inform people about
some of the new Android design patterns.
This presentation will be suitable for learning, for reference and also great for people just
wondering what Android UI is all about.
If you spot something wrong or disagree, then let me know :)
E-mail Address: matt@gauntface.co.uk
3. What Google Want - Dashboard
Lets start off with what Google want
developers to do.
The Dashboard
This is a nice simple, clean and frankly
easy to follow design pattern.
Have a panel with 4 - 6 of your app’s main
functions.
Example Apps: Twitter, Facebook, Google
Places
Note: You don’t have to open your app on
this screen
4. What Google Want - Action Bar
The Action Bar
One thing many dev’s do, is needlessy fill the
screen, removing the notification bar from the
UI.
The only reason I can think of why someone
might do this, is to get rid of the, not so
pretty, title bar.
Instead Google are recommending the Action
Bar. The logo on the right should link to the
dashboard and the left side should have
buttons relevant to that activity - Perfect :)
Examples - Facebook, Twitter and many more
5. What Google Want - Quick Action
The Quick Action
This one I have some reservations about.
It’s a very kool and fun way to give extra functionality in an
intuitive way, especially for specific elements on screen (i.e. a list
item or for displaying extra info).
The issue I have is that Twitter has since dropped this, the only
other app I know of which uses this is the official Android
Contacts App.
To implement you’re own you’ll most likely want to use an open
source library.
Fun, useful and a great idea, but not readily available.
6. So now what?
Well now I’m going to go through *roughly* the development of this UI.
It’s something I’ve been working on recently and this presentation represents the rough process I
went through, from start to finish.
7. Before We Start
Every View should have at least the following states:
Normal
Focused
Pressed
Disabled
For those wondering “What is the focused state?” this is when a user uses the trackball to select a
view on the screen. Better to add it in from the start, it’s extra functionality, with little (if any) extra
work.
Making each of these states can be a little tedious, but if you make them all when you first make
each View, it isn’t too bad :P
Boring bit said and done, lets get on with it.
8. Once there was a Button...
Focused & Pressed
The most simple and most widely used View is the Button.
dark_std_button_pressed_bg
So how do we make one? Using the following XML with the
following images.
Pressed
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="true" dark_std_button_pressed_bg
These actually
android:drawable="@drawable/dark_std_button_pressed_bg" /> look different on a
<item android:state_focused="false" android:state_pressed="true"
android:drawable="@drawable/dark_std_button_pressed_bg" />
Focused device
<item android:state_focused="true"
android:drawable="@drawable/dark_std_button_focused_bg" /> dark_std_button_focused_bg
<item android:drawable="@drawable/dark_std_button_bg" />
</selector> Std.
dark_std_button_bg
9. ...Who met an EditText...
Most apps will need to use an EditText at some point, the Focused & Pressed
reason I wanted to customise mine is to avoid Manufacturer’s
custom colour schemes (Orange, Green, Purple and then the std_edit_text_focused_pressed_bg
various ROM’s). Pressed
<selector xmlns:android="http://schemas.android.com/apk/res/android">
std_edit_text_pressed_bg
<item android:state_focused="true" android:state_pressed="true"
android:drawable="@drawable/std_edit_text_focused_pressed_bg" /> Focused
<item android:state_focused="false" android:state_pressed="true"
android:drawable="@drawable/std_edit_text_pressed_bg" />
<item android:state_focused="true" std_edit_text_focused_bg
android:drawable="@drawable/std_edit_text_focused_bg" />
<item android:drawable="@drawable/std_edit_text_bg" />
Std.
</selector>
std_edit_text_bg
10. ...Who visited the CheckBox...
CheckBox is a little bit of extra work, having checked and non-checked
<selector xmlns:android="http://schemas.android.com/apk/res/android"> Focused & Pressed
<item android:state_checked="true" android:state_focused="true"
android:state_pressed="true"
android:drawable="@drawable/ std_checkbox_unchecked std_checkbox_checked
std_checkbox_checked_focused_pressed" />
_focused_pressed _focused_pressed
Pressed
<item android:state_checked="false" android:state_focused="true"
android:state_pressed="true"
android:drawable="@drawable/
std_checkbox_unchecked_focused_pressed" />
<item android:state_checked="true" android:state_focused="true" std_checkbox_unchecked std_checkbox_checked
android:drawable="@drawable/std_checkbox_checked_focused" /> _pressed _pressed
<item android:state_checked="false" android:state_focused="true"
android:drawable="@drawable/std_checkbox_unchecked_focused" /> Focused
<item android:state_checked="true" android:state_pressed="true"
android:drawable="@drawable/std_checkbox_checked_pressed" />
<item android:state_checked="false" android:state_pressed="true" std_checkbox_unchecked std_checkbox_checked
android:drawable="@drawable/std_checkbox_unchecked_pressed" /> _focused _focused
<item android:state_checked="true"
android:drawable="@drawable/std_checkbox_checked" /> Std.
<item android:state_checked="false"
android:drawable="@drawable/std_checkbox_unchecked" />
</selector> std_checkbox_unchecked std_checkbox_checked
11. ...But the CheckBox was Fussy...
There is one thing you may struggle with when customising your CheckBox.
The View has a Background & a Button property, the difference?
The Background defines where content can go (i.e. the text you can set as the CheckBox label)
For my app I have the following:
Button Background label here
=
12. Where do I put all this stuff?
With a new Android project you’ll get a standard file structure. This is what each folder means :)
All your images (i.e. for buttons, checkbox etc.) should have a copy of each
+src graphic in drawable-hdpi, -mdpi, -ldpi. (Each copy is for different screen
- All your awesome source code resolutions (1.5, 1, 0.75 x the graphic size for hdpi, mdpi, ldpi).
+res The point of this is the displayed image should be roughly the same physical size.
- anim [Animation XML files]
- drawable Then any xml (the stuff on the previos slides) should be placed in the drawable
-Put all your XML drawables here (Button, Checkbox etc.) folder.
- drawable-hdpi
- 1.5 * MDPI graphic size (PNG, JPG, Nine-Patch PNG) In the XML you’ll notice references to @drawable/some_img_name this tells
-drawable-mdpi the Android platform to find a drawable with the name some_img_name in one
- 1 * MDPI graphic size (PNG, JPG, Nine-Patch PNG) of the drawable folders. Which folder is determined by the system, based on the
-drawable-ldpi screen resolution of the device.
- 0.75 * MDPI graphic size (PNG, JPG, Nine-Patch PNG)
-layout Roman Nurik has said that all XML should go into the drawable folder, I’m sure I
-layout-land have seen gradients appear scaled / manipulated if I put it inside the drawable
-values folder rather than individually in each folder. So do as Roman says, he’s far wiser
-values-land than I, but bare in mind it could be the cause of some issues.
+assets
+bin I Can Haz Screen Sizes? *For most devices
+gen HDPI - 480 x 800
AndroidManifest.xml MDPI - 320 x 480
LDPI - 240 x 320
13. Wow - Can I Code Now?
One last bit of XML based fun, but this step will save you a lot of time and frustration.
At the moment to apply your background to a Button, you have to set the background of the
button in the layout file, you then have to do that for EACH of your buttons. Wouldn’t it be cool if
you could tell Android to use the same background for all your buttons, but only do it once?
In comes Themes and Styles.
We’ll start with Styles and then move on to themes.
14. Ok, No Code - Styles huh...
Lets carry on with our Button, we want a style we can apply to our button.
So what exactly is a style?
<style name="admobBtnStyle" parent="android:style/Widget.Button">
<item name="android:background">@drawable/std_btn_stateful</item>
<item name="android:textColor">@color/btn_text</item>
<item name="android:paddingLeft">@dimen/btn_padding_left_right</item>
<item name="android:paddingRight">@dimen/btn_padding_left_right</item>
<item name="android:paddingTop">@dimen/btn_padding_top_bottom</item>
<item name="android:paddingBottom">@dimen/btn_padding_top_bottom</item>
<item name="android:textSize">@dimen/btn_text_size</item>
<item name="android:minHeight">@dimen/btn_min_height</item>
<item name="android:minWidth">@dimen/btn_min_width</item>
</style>
Imagine what you might want to set on a button, the background, textColor, textSize, padding . . .
you get the picture. Do it in a style, then in a layout you can apply the “style” to a button, rather
than each field individually. This means, one change here applies to all your buttons using this style
AND the layout is free to override these values.
I know what you’re thinking - you still need to apply the style to ALL your buttons . . well . . .
15. Themes FTW
... if you apply the style to a Button widget in a Theme, the system automatically applies the style
to all your Buttons - Simples.
<style name="AdmobTheme" parent="android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">@color/activity_bg</item>
<item name="android:editTextStyle">@style/admobEditText</item>
<item name="android:buttonStyle">@style/admobBtnStyle</item>
<item name="android:checkboxStyle">@style/admobCheckboxStyle</item>
</style>
So why have I made you do all this?
In the long run you’ll thank me, there is nothing more soul destroying than going through all your
code, altering Buttons to have padding of 2 pixels to the left and right.
For reference, the Styles for the CheckBox & EditText are on the next two slides (Useful for
parent styles, the rest you can work out).
18. Last Style Trick - Then Pictures
The last little thing I want to make you aware of.
Say you have two buttons, one is light, one is dark, you want them to share the same parameters apart from
the background drawable. Well you can achieve this by having one style being the parent, and the other
extending the parent.
The standard method of doing this is to create a style with same name plus an extension and setting the
parent attrib:
<style name="admobBtnStyle" parent="android:style/Widget.Button">
<item name="android:background">@drawable/std_btn_stateful</item>
<item name="android:textColor">@color/btn_text</item>
<item name="android:paddingLeft">@dimen/btn_padding_left_right</item>
<item name="android:paddingRight">@dimen/btn_padding_left_right</item>
<item name="android:paddingTop">@dimen/btn_padding_top_bottom</item>
<item name="android:paddingBottom">@dimen/btn_padding_top_bottom</item>
<item name="android:textSize">@dimen/btn_text_size</item>
<item name="android:minHeight">@dimen/btn_min_height</item>
<item name="android:minWidth">@dimen/btn_min_width</item>
</style>
<style name="admobBtnStyle.Dark" parent="style/admobBtnStyle">
<item name="android:background">@drawable/dark_std_btn_stateful</item>
</style>
19. The Action Bar - Code Code Code
The logo shoud take the user to the dashboard - when this
happens you’ll want the other Activities in your app to finish
so be sure to start your Activity with the
FLAG_ACTIVITY_CLEAR_TOP flag (See intent.setFlag())
Modal Dialogs - Pah - Utter Rubbish.
Instead, hit my refresh button and it changes to a Progress Bar.
Custom Views aren’t too bad, give them a shot if nothing does
what you want. [But use Adapters where you can]
20. ListViews - Mix it Up a Little
ListView 101
1. Personally, I’m not a fan of ListActivity
2. Personally, I’m not a fan of helper Adapters
3. Use convertView in the getView() method or a kitten will
die for every view you fail to recycle
Hints:
cacheColorHint
Set this to an invisible color to stop the fading edges from turning black - #00000000
dividerDrawable
You can change the dividers so they are colored or just a bit different
background
The drawable set to the background will react to different states (pressed, focused, focused pressed)
listSelector
Ever wanted to stop the orange highlighting? listSelector = #00000000
21. Landscape is Easy in Android
One thing many developers turn off is landscape rotation. I understand that it’s a little tricky when
you’re Activity dies and starts again, but handle it and you can get some cool effects.
Check out Mark Murphy’s posts on the matter:
www.androidguys.com/2008/10/14/rotational-forceson-your-android-app/
22. Dialogs - Oh God the Dialog
You’re not using modal Dialog’s, good, but you do still kinda want to use them, but they kinda
don’t really suite your app.
For me this is a step in the right direction (but not complete), the background image is just a
shape (shape is a drawable defined in XML). This is then used in a Theme which is applied in the
AndroidManifest.xml to a reusable Activity.
Background
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/dialog_rounded_corners" />
<solid android:color="@color/dialog_container_bg_color" />
<stroke android:width="@dimen/dialog_stroke_width"
android:color="@color/dialog_stroke_color" />
</shape>
Theme
<style name="AdmobDialogTheme" parent="android:style/Theme.Dialog">
<item name="android:windowBackground">@drawable/generic_dialog_bg</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:textViewStyle">@style/admobTextView</item>
<item name="android:windowNoTitle">true</item>
<item name="android:buttonStyle">@style/admobBtnStyle</item>
</style>
23. Last Tid Bit - Cos. . .
...it took me ages to find this out!
How to switch the ProgressBar between dark and light (depending on your parent theme).
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"></ProgressBar>
<ProgressBar
android:layout_width="@dimen/action_bar_btn_size"
android:layout_height="@dimen/action_bar_btn_size"
style="?android:attr/progressBarStyleInverse"></ProgressBar>