Implementing Custom Alert DialogFragments
So, I've been working on further revisions to my app. The most notable of these revisions involves switching action bar implementations from GreenDroid to ActionBarSherlock. While this will benefit me tremendously as I'll be able to use native Android 3.0+ components when running on those platforms, it means that I need to start using Fragments as well as the rest of the Android Support Package.
I've be saving much of what I have learned for another post, but I felt like sharing this tidbit right now. One thing that quickly became apparent was that a custom dialog that I was using (with positive/negative buttons) was not going to cut it, as the system dialogs were rendering the button strip differently...
This is implemented via...
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:minWidth="280dip" android:padding="10dip" android:id="@+id/layoutPageDialogRoot" > <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/editTextPageNumber" android:inputType="number" /> <TextView android:id="@+id/textViewMaxPages" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" android:gravity="right" > <requestFocus></requestFocus> </TextView> <LinearLayout android:layout_height="wrap_content" android:id="@+id/linearLayout1" android:layout_width="fill_parent" > <Button android:text="Go!" android:id="@+id/buttonOk" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginTop="3dip" android:layout_width="0dip" /> <Button android:text="Nevermind" android:id="@+id/buttonCancel" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginTop="3dip" android:layout_width="0dip" /> </LinearLayout> </LinearLayout>
While this may seem like a minor UI issue at first, there's something more to it - Android versions 3.0 and above switched the order of the default dialog button actions, placing the positive button on the right and the negative on the left. The dialog above is using the pre-2.0 order. When you're dealing with muscle memory, such UX concerns become important (especially for deletion dialogs).
So, when refactoring the PaginationDialog
into its own DialogFragment
, I decided to do more than port my code. I realized that the native AlertDialog
class uses the operating system order, and is styled to match the OS version's conventions. If only there was a way I could throw my layout into that... wait! There is - AlertDialog.Builder()
has a setView()
method!
By removing the buttons from the layout XML file and manually inflating it, I can stuff my Views into the dialog and piggyback off its functionality.
My buttonless layout...
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layoutPageDialogRoot" android:layout_width="fill_parent" android:layout_height="fill_parent" android:minWidth="280dip" android:orientation="vertical" android:padding="10dip" > <EditText android:id="@+id/editTextPageNumber" android:layout_width="fill_parent" android:layout_height="wrap_content" android:inputType="number" /> <TextView android:id="@+id/textViewMaxPages" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="right" android:text="" > <requestFocus></requestFocus> </TextView> </LinearLayout>
The important lines in the code snippet displayed above are 28, 29 and 32. On 28, the app gets the inflater being used by the Activity]. Remember, you should never instantiate a LayoutInflater
directly. After that, it's pretty trivial to generate the dialog's content (29) and then insert it into an AlertDialog
's View hierarchy.
Run it and what do you get?
Now, run it in Froyo to see if the buttons are automagically reordered…
Disclaimer: Yes, I know I'm inlining strings that would be best stored in an external file. That's a step I put off until I'm ready to make a release build.