There are numerous types of dialogs available within the Android SDK, such as DatePickerDialogs, ProgressDialogs, and generic dialogs like AlertDialogs. You can also create your own custom dialogs for use within your applications.
Custom dialogs like a password confirmation dialog (Figure 1) are generated from a special AlertDialog class (android.app.AlertDialog). The custom aspect of the dialog comes from the fact that instead of using the built-in dialog types, with their default layouts, you load a developer-defined layout to use instead. In this quick tutorial, we provide the steps required to implement a custom password confirmation dialog to collect a new password from the user.
Prerequisites: Dialog Basics
We’ve already discussed how to add basic dialog controls to your Activity classes. This quick tutorial builds upon your knowledge from the Android User Interface Design: Working With Dialogs tutorial. You can either add this dialog to the dialog sample application provided in the above-mentioned tutorial, or create your own application.
Step 1: Design the Custom Dialog Layout
First you need to design the content of your custom dialog in a layout resource file. In this case, our custom layout will be a password confirmation dialog, which means we will need two EditText controls for inputting the password. We will also want some other text controls for labels and the like.
Create a layout resource called /res/layout/password_dialog.xml. The contents of this resource file are shown below:
<?xml version="1.0" encoding="UTF-8"?> <LinearLayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" android:id="@+id/root" xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/TextView_Pwd1" android:text="@string/settings_password" android:textStyle="bold" /> <EditText android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/EditText_Pwd1" android:inputType="textPassword" /> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/TextView_Pwd2" android:text="@string/settings_password2" android:textStyle="bold" /> <EditText android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/EditText_Pwd2" android:inputType="textPassword" /> <TextView android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/TextView_PwdProblem" android:textStyle="bold" android:gravity="center" /> </LinearLayout>
This simple layout file relies upon a few other string resources you’ll need to define (labels, see the full source code for details if you need help defining string resources) as well as the EditText input type attribute called textPassword, which masks the password as it is typed into the control. This figure shows what the layout design looks like:
Step 2: Define a New Password Dialog within your Activity Class
Now let’s add the new Dialog to your basic Activity class.
Begin by editing your Activity class and adding the following class member variable:
private static final int MY_PASSWORD_DIALOG_ID = 4;
This defines a unique Dialog identifier for our Activity class. The value is an arbitrary number, but needs to be unique within the Activity.
Step 3: Inflate the Custom Dialog Layout
To create Dialog instances, you must provide a case for your custom password confirmation dialog in the onCreateDialog() method of your Activity class. When the showDialog() method is called, it triggers a call to this method, which must return the appropriate Dialog instance. Therefore, we begin the specific case statement for your new Dialog within the onCreateDialog() method here by inflating our custom layout file that was designed in the previous step and retrieving the important controls we will want to interact with from within it using the findViewById() method.
case MY_PASSWORD_DIALOG_ID: LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); final View layout = inflater.inflate(R.layout.password_dialog, (ViewGroup) findViewById(R.id.root)); final EditText password1 = (EditText) layout.findViewById(R.id.EditText_Pwd1); final EditText password2 = (EditText) layout.findViewById(R.id.EditText_Pwd2); final TextView error = (TextView) layout.findViewById(R.id.TextView_PwdProblem); // TODO: Create Dialog here and return it (see subsequent steps)
As you can see, we grab the two EditText controls that will store the password data, as well as the TextView control where we can display the password error text (passwords either match or do not match).
Step 4: Implement the Password TextWatcher
The next step of our onCreateDialog() case statement implementation for the custom dialog is to register a TextWatcher on the second EditText control so that we can listen for and detect password matches as the user types in order to display the proper string text in the error TextView control (matches/does not match).
Here’s the implementation of the TextWatcher, which is assigned to the second password EditText control using the addTextChangedListener() method.
password2.addTextChangedListener(new TextWatcher() { public void afterTextChanged(Editable s) { String strPass1 = password1.getText().toString(); String strPass2 = password2.getText().toString(); if (strPass1.equals(strPass2)) { error.setText(R.string.settings_pwd_equal); } else { error.setText(R.string.settings_pwd_not_equal); } } public void beforeTextChanged(CharSequence s, int start, int count, int after) {} public void onTextChanged(CharSequence s, int start, int before, int count) {} });
The TextWatcher has three callback methods, but we’re really only interested in the afterTextChanged() method implementation. Here we check the text of the two EditText controls, compare them, and set the error text in the TextView. Here is what the TextWatcher might show when the passwords match:
Step 5: Use the Dialog Builder to Configure the Dialog
The next step of our onCreateDialog() case statement implementation for the custom password confirmation dialog is to use the AlertDialog.Builder class to begin to configure the dialog settings.
AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Enter Password"); builder.setView(layout);
We set the title of the dialog using the setTitle() method, but the most important thing we do here is use the setView() method to attach our custom layout we just inflated to the dialog. This is how we modify the controls used within our dialog, making it have custom display and developer-defined behavior.
Step 6: Set the Positive and Negative Button Handlers for the Custom Password Dialog
Next, we need to configure the positive and negative buttons associated with our dialog. Recall that dialogs will be reused if displayed more than once. With our password confirmation dialog, we want to make sure to forcefully remove the dialog from the Activity’s dialog pool so that it cannot be reused. We do not want any residual password information being stored after our password dialog is dismissed, whether it is confirmed or dismissed.
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { removeDialog(MY_PASSWORD_DIALOG_ID); } }); builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { String strPassword1 = password1.getText().toString(); String strPassword2 = password2.getText().toString(); if (strPassword1.equals(strPassword2)) { Toast.makeText(SuperSimpleDialogsActivity.this, "Matching passwords="+strPassword2, Toast.LENGTH_SHORT).show(); } removeDialog(MY_PASSWORD_DIALOG_ID); } });
We get rid of the dialog in both the negative and positive button click handlers using the removeDialog() method. However, in the positive button handler, we also retrieve the contents of the EditText controls and, if they match, display the password as a Toast message. In most cases, you would not use a Toast, but would save off the password using the method of your choice (preferences, etc.).
Step 7: Generate the Custom AlertDialog from the Builder
Your dialog is completely configured. Now use the create() method of the AlertDialog.Builder class to generate the appropriate AlertDialog and return it, thus ending your case statement for this dialog within the onCreateDialog() method of the Activity class.
AlertDialog passwordDialog = builder.create(); return passwordDialog;
Step 8: Triggering the Password Confirmation Dialog to Display
Finally, you are ready to trigger your password confirmation dialog to display as required. For example, you might add another Button control to your Activity’s screen to trigger your dialog to display. Its click handler might look something like this:
public void onPasswordDialogButtonClick(View v) { showDialog(MY_PASSWORD_DIALOG_ID); }
Conclusion
Dialogs are a powerful user interface tool that can help you keep your application user interface flexible and uncluttered. Dialogs can contain your own layout resources with different controls, allowing you to create custom controls like password confirmation dialogs. Custom dialogs are generally created using the AlertDialog class, with all its features.
About the Authors
Mobile developers Lauren Darcey and Shane Conder have coauthored several books on Android development: an in-depth programming book entitled Android Wireless Application Development, Second Edition and Sams Teach Yourself Android Application Development in 24 Hours, Second Edition. When not writing, they spend their time developing mobile software at their company and providing consulting services. They can be reached at via email to [email protected], via their blog at androidbook.blogspot.com, and on Twitter @androidwireless.
Comments