In this tutorial I’ll show you how to create a dialog fragment that can be used for general purpose dialogs where you want to show the user a message and just have one option for them to acknowledge the message.
The unique thing about this tutoral is you can add an object to your dialog and this is passed back to the calling activity. This allows you to use the Dialog on custom views like a ListView, when the user presses the item the dialog is popped up, when the user acknowledges this dialog the activity will receive that item from your list.
Inspiration taken from Android Developers API – Dialog Fragment
What we’re going to do:
- Create a Fragment Dialog
- Allow this dialog to be customisable
- Add any type of extra object to the dialog
- Call this dialog from a button
In short this dialog is kind of like an Android Intent. You can add an ‘extra’ to the dialog that is passed back when the dialog is acknowledged.
Ok Here .. we .. go
First, no need to change your AndroidManifest.xml woo. Just add a button to the Activity to show the dialog. This is the simplest example, you can use this dialog anywhere (examples at the bottom), so anywhere your onClick imagination can take you. The onClick is actually declared in the XML layout file:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="onShowDialog" android:text="Show Dialog" /> </LinearLayout>
MainActivity.java:
package com.blundell.tut.ui.phone; import com.blundell.tut.R; import com.blundell.tut.domain.UserDetails; import com.blundell.tut.ui.fragment.OneOptionDialogFragment; import com.blundell.tut.ui.fragment.OneOptionDialogFragment.OnDialogOptionClickListener; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.util.Log; import android.view.View; import android.widget.Toast; public class MainActivity extends FragmentActivity implements OnDialogOptionClickListener<UserDetails> { private UserDetails userDetails; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.userDetails = new UserDetails(1, "Paul"); } public void onShowDialog(View button){ String title = userDetails.getName(); String message = "Are you sure you want to delete this user?"; String buttonText = "Delete Permanently"; OneOptionDialogFragment<UserDetails> dialogFragment = OneOptionDialogFragment.newInstance(title, message, buttonText); dialogFragment.addItem(userDetails); dialogFragment.setOnDialogOptionClickListener(this); dialogFragment.show(getSupportFragmentManager(), "TAG"); } @Override public void onDialogOptionPressed(UserDetails object) { Toast.makeText(this, "Dialog button was pressed. Received user: "+ userDetails.getName(), Toast.LENGTH_LONG).show(); Log.i("TUT", "onDialogOptionPressed"); Log.i("TUT", "User: "+ userDetails.getName()); } }
Notice that the Activity implements our Dialog’s onClick listener. This is a callback for when the Dialog button is pressed. The Interface uses generics to allow us to state what type of data we want to pass to and from the Dialog.
Skipping forward a bit, you can imagine a scenario where you have a bunch of users in a listview, when one of these users is clicked you would like to delete that user from your database, the Activity should deal with the delete but the listview wants to show the dialog. Therefore the dialog needs to pass back the details of the user that was pressed. This is where generics come in. When we create our dialog we use generics to tell the dialog we will be passing round ‘UserDetails’ objects.
Here is one of those objects it’s pretty simple:
package com.blundell.tut.domain; public class UserDetails { private final int id; private final String name; public UserDetails(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public String getName() { return name; } }
And here is the awesome dialog itself! You can use this in any occasion where you want to display a message with one button to acknowledge that message:
package com.blundell.tut.ui.fragment; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; import android.support.v4.app.DialogFragment; public class OneOptionDialogFragment<T> extends DialogFragment implements OnClickListener { private static final String ARG_TITLE = "com.blundell.tut.ui.fragment.OneOptionDialogFragment.ARG_TITLE"; private static final String ARG_MESSAGE = "com.blundell.tut.ui.fragment.OneOptionDialogFragment.ARG_MESSAGE"; private static final String ARG_BUTTON_TEXT = "com.blundell.tut.ui.fragment.OneOptionDialogFragment.ARG_BUTTON_TEXT"; private OnDialogOptionClickListener<T> clickListener; private T item; public interface OnDialogOptionClickListener<T extends Object> { void onDialogOptionPressed(T object); } public static <T> OneOptionDialogFragment<T> newInstance(String title, String message, String buttonText){ OneOptionDialogFragment<T> fragment = new OneOptionDialogFragment<T>(); Bundle args = new Bundle(); args.putString(ARG_TITLE, title); args.putString(ARG_MESSAGE, message); args.putString(ARG_BUTTON_TEXT, buttonText); fragment.setArguments(args); return fragment; } public void addItem(T item){ this.item = item; } public void setOnDialogOptionClickListener(OnDialogOptionClickListener<T> clickListener){ this.clickListener = clickListener; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Bundle args = getArguments(); String title = args.getString(ARG_TITLE); String message = args.getString(ARG_MESSAGE); String buttonText = args.getString(ARG_BUTTON_TEXT); return new AlertDialog.Builder(getActivity()) .setIcon(android.R.drawable.ic_dialog_info) .setTitle(title) .setMessage(message) .setPositiveButton(buttonText, this).create(); } @Override public void onClick(DialogInterface dialog, int which) { if(this.clickListener != null){ this.clickListener.onDialogOptionPressed(item); } } }
I don’t think I’ve explained this too well but it’s kind of a tough one without me rambling, hopefully if you check out the example source project and run it up, you can see what is going on and find it useful.
I wrote this DialogFragment for ease of use, you can create multiple dialogs without having to write loads of code over and over. Here are a few examples:
String title = "Question"; String message = "Are you sure you want to delete this user?"; String buttonText = "Delete Permanently"; OneOptionDialogFragment<UserDetails> dialogFragment = OneOptionDialogFragment.newInstance(title, message, buttonText); dialogFragment.addItem(userDetails); dialogFragment.setOnDialogOptionClickListener(this); dialogFragment.show(getSupportFragmentManager(), "DeleteFragTag");
String title = "Buy Me Shop"; String message = "We are going to take payment now."; String buttonText = "Ok"; OneOptionDialogFragment<Object> dialogFragment = OneOptionDialogFragment.newInstance(title, message, buttonText); dialogFragment.addItem(userDetails); // No extra's needed for an ok dialog dialogFragment.show(getSupportFragmentManager(), "OkFragTag");
String title = "Registration"; String message = "Thank you for your details. Do you want to enter our prize draw?"; String buttonText = "Hell Yeah!"; OneOptionDialogFragment<FormData> dialogFragment = OneOptionDialogFragment.newInstance(title, message, buttonText); dialogFragment.addItem(userDetails); dialogFragment.setOnDialogOptionClickListener(new OnDialogOptionClickListener<FormData>() { public void onDialogOptionPressed(FormData object) { // Do something with the form data }; }); dialogFragment.show(getSupportFragmentManager(), "ContinueFragTag");
Enjoy and please ask any questions you like!
Github repo:
https://github.com/blundell/GenericDialogTut
Eclipse source:
Generic Dialog Tutorial Eclipse Source
Would the clickListener be null after rotation such that onClick() will not call the listener’s onDialogOptionPressed() method?
Yes it would be null. You can attach the click listener in onAttach to avoid this. (remove the explicit setter)