Augmenting Activities with Dialogs

One of the difficulties in working on the Pay It Square Android app is the web experience is so rich and fluid. It is always a challenge to bring that fluidity to the mobile device because the experiences are inherently different.

I think there is a tendency amongst Android developers to overuse Activities without consider the user experience and how it is affected by going deep into a stack of activities.  This is a problem.  Inevitably you will either have to write code to finish a ton of activities, or you will have the user pressing their hardware back button to get back to the screen they want.

One of the ways that you can solve this problem, in some cases, is by creating a custom dialog.  Now, that doesn’t mean you should replace all of your activities with dialogs, only where acceptable. This is the same lesson we are learning/have learned on the web with the modal dialog UI effect everyone is favorable towards.  Learning where and when to use this, vs an Activity is a crucial skill in mobile application development for Android.

The first task is to extend the Dialog class.  Note that there is an AlertDialog class that you can also extend.  This will come with a title bar and two buttons for accepting and negating the alert.  I have also found it very difficult to theme the default dialogs in Android.  For our purpose, we are going to simply extend Dialog and generate the simplest constructor, which takes our current Context.

   1: package com.ost.PayItSquare;

   2:  

   3: import android.app.Dialog;

   4: import android.content.Context;

   5:  

   6: public class MyDialog extends Dialog

   7: {

   8:     public MyDialog(Context context) {

   9:         super(context);

  10:     }

  11: }

Dialogs behave very much like Activities, in fact many of the common calls used in Activities are used here.  We can use setContentView to set a layout for the Dialog, findViewById to look up Views in that layout.  Code update is below:

package com.ost.PayItSquare;

import android.app.Dialog;
import android.content.Context;
import android.view.ViewGroup;
import android.view.Window;

public class MyDialog extends Dialog
{
    public MyDialog(Context context) {
        super(context);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setLayout(ViewGroup.LayoutParams.FILL_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        setContentView(R.layout.custom_dialog);
    }
}
 

There are two things that I have come to find Android will try to ensure that all dialogs adhere to: wrap sizing and presence of a title bar.  For the title bar, simply requesting Window feature Window.FEATURE_NO_TITLE ensures that there is no title bar for the dialog.  The wrap sizing can be a bit hard to understand.  No matter how much you adjust your layout code, the dialog will not change.  The fix that I have found is to set the width and height programmatically as show above.

With this, you have a custom dialog that you can do anything with.  Lets add two buttons and force the user to make a selection to hide the dialog.

package com.ost.PayItSquare;

import android.app.Dialog;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;

public class MyDialog extends Dialog
{
    private Button btnOk;
    private Button btnCancel;

    public MyDialog(Context context) {
        super(context);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setLayout(ViewGroup.LayoutParams.FILL_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        setContentView(R.layout.custom_dialog);

        setCancelable(false);
        initFields();
        setFields();
    }

    private void initFields() {
        btnOk = (Button)findViewById(R.id.btnOk);
        btnCancel = (Button)findViewById(R.id.btnCancel);
    }

    private void setFields() {
        btnOk.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(View view) {
                dismiss();
            }
        });

        btnCancel.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(View view) {
                cancel();
            }
        });
    }
}
 

As a disclaimer, this is a coding style that I have adopted with Android when I cant use View Injection (as is the case with Dialogs), I really do try to avoid calling findViewById wherever possible.

Calling the built-in method setCancelable to false will disallow the user from dismissing the Dialog by hitting the hardware back key; use it when you require the user input.

One of the very nice conventions I like to use with custom dialogs is to differentiate a cancel action with an accept action by calling cancel and dismiss respectively.  The reason for this is that Dialog provides handlers for OnCancel and OnDismiss.  This is a good way, I have found, to easily differentiate what the user has done.

At this point, you can treat the Dialog much like the Activity.  Remember, it is still a dialog, so overloading it with functionality is never a good idea.  Use it for quick contextual editing, such as for list items.  It can never fully replace an Activity nor should it be considered such.  Think of it as what you would use a modal window for in the web world and generally you will be fine.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s