Android UI: Colored dialogs
This document can be read in Google Docs (http://docs.google.com/View?id=ddwc44gs_232dw6nf66h), cut and paste link if you have problems accessing it. If you have problems seeing the images, like the icon in this box don't blame me, it seems to be an issue when you publish to Blogspot from Google Docs. |
introduction
Sometimes you need a stronger visual cue for a very special situation that may arise during the lifecycle of your application.
One approach is to copy <ANDROID-SDK>/platforms/android-2.1/data/res/drawable-mdpi/panel_background.9.png, change its color and then use it as the dialog background in your theme.
For example, extending the default Theme
1 <style name="MyColorDialogTheme" parent="android:Theme.Dialog"> 2 <item name="android:windowBackground">@drawable/color_panel_background/item> 3 </style> |
This was discussed in stackoverflow, but I though there should be a better solution. Copying and changing images is not very attractive if you want to have several colors or even decide it at runtime.
colored dialogs
We will be trying to discover the simplest yet usable way of colorizing AlertDialogs.
Some standard behavior should be changed, so we need to extend AlertDialog.
MyColorDialog and Builder
What we are going to do is to extend AlertDialog to create a class that given a theme that defines the android:tint attribute then all the Views in the dialog are tinted with this specific color.
We need to iterate over the Views so a simple iterator is also defined.
1 public static class MyColorDialog extends AlertDialog { 2 private static int NONE = -1; 3 private int tint = NONE; 4 5 /** 6 * @param context 7 * @param theme 8 */ 9 protected MyColorDialog(Context context) { 10 super(context); 11 init(); 12 } 13 14 /** 15 * @param context 16 * @param theme 17 */ 18 protected MyColorDialog(Context context, int theme) { 19 super(context, theme); 20 init(); 21 } 22 23 /** 24 * 25 */ 26 private void init() { 27 final Theme theme = getContext().getTheme(); 28 final TypedArray attrs = theme.obtainStyledAttributes(new int[] { android.R.attr.tint }); 29 tint = attrs.getColor(0, NONE); 30 } 31 32 /* (non-Javadoc) 33 * @see android.app.Dialog#show() 34 */ 35 @Override 36 public void show() { 37 super.show(); 38 setTint(tint); 39 } 40 41 /** 42 * @param tint 43 */ 44 public void setTint(int tint) { 45 this.tint = tint; 46 47 if ( tint != NONE ) { 48 Iterator<View> vi = iterator(android.R.id.content); 49 while ( vi.hasNext() ) { 50 tintView(vi.next(), tint); 51 } 52 } 53 } 54 55 /** 56 * Set the {@link tint} color for the {@link View} 57 * 58 * @param v the {@link View} to change the tint 59 * @param tint color tint 60 */ 61 private static void tintView(final View v, final int tint) { 62 if ( v != null ) { 63 final Mode mode = PorterDuff.Mode.SRC_ATOP; 64 65 if ( v instanceof ImageView ) { 66 final Drawable d = ((ImageView)v).getDrawable(); 67 if ( d != null ) { 68 d.mutate().setColorFilter(tint, mode); 69 } 70 } 71 else { 72 final Drawable d = v.getBackground(); 73 if ( d != null ) { 74 d.setColorFilter(tint, mode); 75 } 76 } 77 } 78 } 79 80 81 /** 82 * @param button 83 */ 84 public void setCancelButton(Button button) { 85 button.setOnClickListener(new View.OnClickListener() { 86 87 @Override 88 public void onClick(View v) { 89 cancel(); 90 } 91 92 }); 93 } 94 95 /** 96 * @param button 97 */ 98 public void setPositiveButton(Button button) { 99 button.setOnClickListener(new View.OnClickListener() { 100 101 @Override 102 public void onClick(View v) { 103 dismiss(); 104 } 105 106 }); 107 } 108 109 110 /** 111 * Return a {@link ChildrenIterator} starting at the {@link ViewGroup} 112 * identified by the specified resource id. 113 * 114 * @param res resource id of the {@link ViewGroup} to start the iteration 115 * @return iterator 116 */ 117 public Iterator<View> iterator(int res) { 118 final ViewGroup vg = (ViewGroup)findViewById(res); 119 return new ChildrenIterator<View>(vg); 120 } 121 122 123 public static class Builder extends AlertDialog.Builder { 124 125 private MyColorDialog dialog; 126 127 public Builder(Context context) { 128 super(context); 129 dialog = new MyColorDialog(context); 130 } 131 132 public Builder(Context context, int theme) { 133 super(context); 134 dialog = new MyColorDialog(context, theme); 135 } 136 137 @Override 138 public MyColorDialog create() { 139 return dialog; 140 } 141 142 @Override 143 public Builder setMessage(CharSequence message) { 144 dialog.setMessage(message); 145 return this; 146 } 147 148 @Override 149 public Builder setTitle(CharSequence title) { 150 dialog.setTitle(title); 151 return this; 152 } 153 154 @Override 155 public Builder setPositiveButton(CharSequence text, 156 OnClickListener listener) { 157 dialog.setButton(BUTTON_POSITIVE, text, listener); 158 return this; 159 } 160 161 @Override 162 public Builder setIcon(int iconId) { 163 dialog.setIcon(iconId); 164 return this; 165 } 166 167 } 168 } |
Iterator
This is the iterator used in MyColorDialog.
1 public static class ChildrenIterator<V extends View> implements Iterator<V> { 2 ArrayList<V> list; 3 private int i; 4 5 public ChildrenIterator(ViewGroup vg) { 6 super(); 7 8 if ( vg == null ) { 9 throw new RuntimeException("ChildrenIterator needs a ViewGroup != null to find its children"); 10 } 11 init(); 12 findChildrenAndAddToList(vg, list); 13 } 14 15 private void init() { 16 list = new ArrayList<V>(); 17 i = 0; 18 } 19 20 @Override 21 public boolean hasNext() { 22 return ( i < list.size() ); 23 } 24 25 @Override 26 public V next() { 27 return list.get(i++); 28 } 29 30 @Override 31 public void remove() { 32 list.remove(i); 33 } 34 35 @SuppressWarnings("unchecked") 36 private void findChildrenAndAddToList(final ViewGroup root, final ArrayList<V> list) { 37 for (int i=0; i < root.getChildCount(); i++) { 38 V v = (V)root.getChildAt(i); 39 list.add(v); 40 if ( v instanceof ViewGroup ) { 41 findChildrenAndAddToList((ViewGroup)v, list); 42 } 43 } 44 } 45 46 } |
styles
Let's just define some styles to colorize our dialogs using android:style/Theme.Dialog as the parent.
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <!-- Orange --> 4 <style name="OrangeDialogTheme" parent="@android:style/Theme.Dialog"> 5 <item name="android:tint">@color/orange_tint</item> 6 </style> 7 8 <style name="OrangeAlertDialogTheme" parent="OrangeDialogTheme"> 9 <item name="android:windowBackground">@color/transparent</item> 10 </style> 11 12 13 <!-- Red --> 14 <style name="RedDialogTheme" parent="@android:style/Theme.Dialog"> 15 <item name="android:tint">@color/red_tint</item> 16 </style> 17 18 <style name="RedAlertDialogTheme" parent="RedDialogTheme"> 19 <item name="android:windowBackground">@color/transparent</item> 20 </style> 21 </resources> |
colors
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <color name="red_tint">#88FF0000</color> 4 <color name="blue_tint">#880000FF</color> 5 <color name="yellow_tint">#88FFFF00</color> 6 <color name="purple_tint">#88995f86</color> 7 <color name="orange_tint">#aaffbf00</color> 8 <color name="magenta_tint">#88ff33cc</color> 9 <color name="transparent">#0000</color> 10 </resources> |
usage
From our Activities we can use MyColorDialog as any other AlertDialog, in this case we will be using a custom theme defined previously
1 dialog = (new MyColorDialog.Builder(this, R.style.RedAlertDialogTheme)) 2 .setTitle("Warning") 3 .setMessage("This phone will self-destruct in five seconds.\nPlease stay back.") 4 .setPositiveButton("Dismiss", null) 5 .create(); 6 dialog.show(); |
samples
These are some dialogs created using different color variations.
conclusion
We introduced a simple way of changing the appearance of your dialogs just from styles.
These classes are oversimplifications from the ones that are part of auito, formerly known as autoandroid. More information and samples will be provided soon.
Comments are gladly welcome.
Copyright © 2010 Diego Torres Milano. All rights reserved.
4 comments:
Diego
I'm looking for the source of your
LifeCycleDemo ,New York love your code!
THX
This is great. I just saw a review of Professional Android 2 Application Development and thought I would get into programming again.
This is cool.
Helen Neely
Thank you for the tutorial about Dialogs
but away from that could you please help show me how to read the previous line in a text file of an unnumbered lines
@Ruyonga Dan,
I see all lines numbered in the examples, so I don't understand what you mean.
Can you please be more specific?
Post a Comment