假坚强 发表于 2013-8-28 16:30

《Android Dev Guide》系列教程12:用户界面之建立对话框Dialogs

>Dialog是一个常见的显示在当前activity之上的小窗口。下面的activity会失去焦点,而dialog回接受用户输入。dialog常用在与程序直接相关联的通知和短小的activity中。Android API支持以下几种dialog:它可以包含0、1、2、3个按钮,或者一个列表或者多选单选按钮等,它是一个功能最强大的dialog接口,详细信息可参考下面的章节。它会显示一个进度条或者进度环,因为他是AlertDialog的子类,所有野支持按钮。用来选择日期的对话框。用来选择时间的。如果你想要定制自己的dialog,你可以继承Dialog对象,或者它的任何一个子类,并且定义一个新的布局。Dialog 总是被当做activity的一部分来创建和显示。你可以在activity的onCreateDialog(int)方法中创建一个dialog。当你使用这个方法,android系统会自动的管理每个dialog的状态并且关联到所在的activity中,让这个activity成为dialog的管理者。每个dialog都会继承activity的某些特性。例如,当dialog打开时,按下menu弹出的是所在activity的菜单,调节的是所在activity的音量。注意:如果你决定在onCreateDialog()方法之外建立dialog,他将不会连接到activity中,此时,你可以使用setOwnerActivity(Activity)方法来绑定activity。当你显示dialog时,调用showDialog(int)来传递一个dialog的id句柄。当一个dialog首次显示时,android会在实例化dialog的activity中调用onCreateDialog(int)方法。回调方法会传递相同的id给showDialog(int)。当 创建完一个dialog后,会再方法的最后返回这个对象。在dialog显示前,android回调用可选的方法 :onPrepareDialog(int,Dialog)。如果你想在每次调用dialog时改变一些配置的话,你可以定义这个方法。OnPrepareDialog(int,Dialog)方法会在每次调用dialog时调用,而onCreateDialog(int)方法只会调用一次。如果你不定义onPrepareDialog()方法,那么打开的dialog会保持上一次的状态。这个方法也会传递dialog的id句柄。定义这两个onXXX()方法最好使用一个switch结构来检测Id参数,每一个case项都应该创建自己的dialog。例如。想象一个游戏使用两个不同的dialog,一个暂停一个结束游戏:   
    static final int DIALOG_PAUSED_ID = 0;   
static final int DIALOG_GAMEOVER_ID = 1;然后,再onCreateDialog(int)里根据id创建dialog:    protected Dialog onCreateDialog(int id) {   
    Dialog dialog;   
    switch(id) {   
    case DIALOG_PAUSED_ID:   
      // do the work to define the pause Dialog   
      break;   
    case DIALOG_GAMEOVER_ID:   
      // do the work to define the game over Dialog   
      break;   
    default:   
      dialog = null;   
    }   
    return dialog;   
}注意:在例子中没有详写,因为定义dialog属于另外的章节。现在可以调用showDilaog(int)来显示一个dialog了:    showDialog(DIALOG_PAUSED_ID);调用dialog的dismiss()方法可以隐藏正在显示的dialog,如果必要的话,可以调用activity的dismissDialog(int)方法,他俩效果是一样的。如果使用的onCreateDialog(int)方法来管理dialog的状态,那么每次当你的dialog消失时,对话框的状态都会被activity保存着。如果不太需要这个对话框或者不希望activity保留dialog的状态,可以调用removeDialog(int)方法。它会删除任何关于dialog的引用,如果dialog正在显示,此方法会让dialog隐藏。隐藏dialog监听器的使用如果你想让activity在dialog隐藏时执行某些动作,那么你可以建立一个监听器。首先定义DialogInterface.OnDismissListerner 接口,这个接口只有一个方法,onDismiss(DialogInterface),当dialog隐藏时被调用,然后传递OnDismissListener 对象给setOnDismissLister()方法。然而,注意dialog也可以是取消,用户让这个dialog取消也是一种特殊的情况。当用户按下back键时,或者调用cancel()方法时会发生这种情况。当一个dialog被取消时,OnDismissLister监听器仍然会收到通知,但如果你喜欢的到明确的取消消息,可以注册DialogInterface.OnCancelLister监听器。   
AlertDialog时Dialog的子类,Dilaog绝大多数是这个强大类型,你可以在以下情况下使用:@ 一个标题@ 一个文本信息@ 一个两个或者三个按钮@ 一个单选或者多选列表建立AlertDialog,使用AlertDialog.Builder子类。使用AlertDialog.Builder(Context)方法来获得一个Builder,并且使用它的公共方法来定义AlertDialog所有的属性。最后,调用create()方法来显示。下面显示了如何定义AlertDialog.Builder类的一些属性,如果在onCreateDialog()方法中使用了例子中的代码,你可以返回结果对话框来显示这个dialog。   
http://www.apkbus.com/data/attachment/forum/201105/06/195249xeyx9rdw9db4ddod.jpg   
创建一个上图所示包含按钮的AlertDialog,可以使用setXXXButton()方法:    AlertDialog.Builder builder = new AlertDialog.Builder(this);   
builder.setMessage("Are you sure you want to exit?")   
       .setCancelable(false)   
       .setPositiveButton("Yes", new DialogInterface.OnClickListener() {   
         public void onClick(DialogInterface dialog, int id) {   
                MyActivity.this.finish();   
         }   
       })   
       .setNegativeButton("No", new DialogInterface.OnClickListener() {   
         public void onClick(DialogInterface dialog, int id) {   
                dialog.cancel();   
         }   
       });   
AlertDialog alert = builder.create();首先,通过setMessage(CharSequence)为dialog添加一个message,然后通过setCancelable(boolean)方法让此dialog无法通过按back键来取消。每个按钮都需要调用setXXXButton()方法,例如setPositiveButton()方法,DialogInterface.OnClickListener()类会定义按下按钮所要做的处理。注意:每种类型的按钮只能加一个,这就是说,你不能添加多于一个的positive按钮。最多能添加三个按钮,positive, neutral, 和 negative.他们名字所显示的功能并未实现,但能帮你记住要实现的功能。http://www.apkbus.com/data/attachment/forum/201105/06/195251nmomm9kz9guwuvko.jpg   
   
如上图所示,使用setItems()方法添加可选列表:    final CharSequence[] items = {"Red", "Green", "Blue"};   
AlertDialog.Builder builder = new AlertDialog.Builder(this);   
builder.setTitle("Pick a color");   
builder.setItems(items, new DialogInterface.OnClickListener() {   
    public void onClick(DialogInterface dialog, int item) {   
      Toast.makeText(getApplicationContext(), items, Toast.LENGTH_SHORT).show();   
    }   
});   
AlertDialog alert = builder.create();首先,使用setTitle(CharSequence)方法设置标题,然后使用setItem()方法添加可选列表,这个列表会接收一个item数组来显示,DialogInterFace.OnClickListener类会定义他们的点击事件。http://www.apkbus.com/data/attachment/forum/201105/06/1952540oyhoym0jja8oay7.jpg通过setMultiChoiceItems()方法或 setSingleChoiceItems()方法来分别建立一个多选按钮列表或者单选列表,如果再onCreateDialog()方法中建立了其中一种列表,android会为你管理这个list。当activity处于活动状态时,dialog会记住当才选中项,如果退出了程序,选择结果便会丢失。注意:当用户离开或者暂停activity时,如果你想保存选择状态,你必须在整个activity的生命周期中保存这个设置。永久的保存所选项,甚至当前进程完全被关闭,你需要使用数据存储方式来保存。建立一个如上图所示的列表dialog,代码和上面的例子相同,只需要把setItems()方法改为setSingleChoiceItems()方法即可。    final CharSequence[] items = {"Red", "Green", "Blue"};   
AlertDialog.Builder builder = new AlertDialog.Builder(this);   
builder.setTitle("Pick a color");   
builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {   
    public void onClick(DialogInterface dialog, int item) {   
      Toast.makeText(getApplicationContext(), items, Toast.LENGTH_SHORT).show();   
    }   
});   
AlertDialog alert = builder.create();setSingleChoiseItems()方法的第二个参数是checkedItem的id值,从0开始对应着位置,如果返回”-1“表明没有选中任何项。   
http://www.apkbus.com/data/attachment/forum/201105/06/1952587j57lxhjl5cdbtj5.jpg   
ProgressDialog时AlertDialog的子类,它会显示一个表示进度的圆形动画,来表示一个进度或者任务正在运行,也可以时一个进度条,能清晰的表示出进度。他也能添加按钮,比如取消一个下载进程。调用ProgressDialog.show()方法可以显示进程对话框,例如,上图的对话框可通过如下代码生成:    ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "",      
                        "Loading. Please wait...", true);第一个参数是程序的Context引用,四二个为标题,第三个为显示的信息,最后一个为类型,(当创建进度条时才会用到,下节讨论)。默认的进度条为圆形的样式,如果你想生成一个通过具体数值来显示任务的加载情况的进度条,下一节会讨论。进度条的显示显示一个进度条要经过以下几个步骤:1-使用ProgressDialog(Context)方法初始化2-使用setProgressStyle(int)方法设置类型。3-调用show()方法显示,或者在onCreateDialog(int)方法里返回一个ProgressDialog。4-你可以调用setProgress(int)方法,根据整体的任务完成度来设置一个具体进度值,或者使用incrementPressBy(int)来设置一个增长值。例如:    ProgressDialog progressDialog;   
progressDialog = new ProgressDialog(mContext);   
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);   
progressDialog.setMessage("Loading...");   
progressDialog.setCancelable(false);设置代码非常简单,大部分代码是在dialog参与进程并且更新的功能里。你会发现,另起一个线程来做这个工作是很有必要的,要把消息传递给activity的UI线程里需要用到 Handler 消息机制。如果你并不熟悉使用额外的线程,那么看这个例子:这个例子使用了第二个线程来跟踪任务的进度(实际上只是在数值上加到100),线程通过 Handler 发了一个Message 给主activity,然后主activity更新ProgressDialog。    package com.example.progressdialog;   
import android.app.Activity;   
import android.app.Dialog;   
import android.app.ProgressDialog;   
import android.os.Bundle;   
import android.os.Handler;   
import android.os.Message;   
import android.view.View;   
import android.view.View.OnClickListener;   
import android.widget.Button;   
public class NotificationTest extends Activity {   
    static final int PROGRESS_DIALOG = 0;   
    Button button;   
    ProgressThread progressThread;   
    ProgressDialog progressDialog;   
      
    /** Called when the activity is first created. */   
    public void onCreate(Bundle savedInstanceState) {   
      super.onCreate(savedInstanceState);   
      setContentView(R.layout.main);   
      // Setup the button that starts the progress dialog   
      button = (Button) findViewById(R.id.progressDialog);   
      button.setOnClickListener(new OnClickListener(){   
            public void onClick(View v) {   
                showDialog(PROGRESS_DIALOG);   
            }   
      });      
    }   
      
    protected Dialog onCreateDialog(int id) {   
      switch(id) {   
      case PROGRESS_DIALOG:   
            progressDialog = new ProgressDialog(NotificationTest.this);   
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);   
            progressDialog.setMessage("Loading...");   
            progressThread = new ProgressThread(handler);   
            progressThread.start();   
            return progressDialog;   
      default:   
            return null;   
      }   
    }   
    // Define the Handler that receives messages from the thread and update the progress   
    final Handler handler = new Handler() {   
      public void handleMessage(Message msg) {   
            int total = msg.getData().getInt("total");   
            progressDialog.setProgress(total);   
            if (total >= 100){   
                dismissDialog(PROGRESS_DIALOG);   
                progressThread.setState(ProgressThread.STATE_DONE);   
            }   
      }   
    };   
    /** Nested class that performs progress calculations (counting) */   
    private class ProgressThread extends Thread {   
      Handler mHandler;   
      final static int STATE_DONE = 0;   
      final static int STATE_RUNNING = 1;   
      int mState;   
      int total;   
            
      ProgressThread(Handler h) {   
            mHandler = h;   
      }   
            
      public void run() {   
            mState = STATE_RUNNING;      
            total = 0;   
            while (mState == STATE_RUNNING) {   
                try {   
                  Thread.sleep(100);   
                } catch (InterruptedException e) {   
                  Log.e("ERROR", "Thread Interrupted");   
                }   
                Message msg = mHandler.obtainMessage();   
                Bundle b = new Bundle();   
                b.putInt("total", total);   
                msg.setData(b);   
                mHandler.sendMessage(msg);   
                total++;   
            }   
      }   
            
      /* sets the current state for the thread,   
         * used to stop the thread */   
      public void setState(int state) {   
            mState = state;   
      }   
    }   
}http://www.apkbus.com/data/attachment/forum/201105/06/195301rx4tpxecxpvmz9x1.jpg如果你想自定义dialog的布局,你可以自己创建一个dialog布局。定义好之后,传递根View对象或者资源ID到setContextView(View)方法。例如,如上图的dialog:1-建立一个xml布局文件custom_dialog.xml;   
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   
            android:id="@+id/layout_root"   
            android:orientation="horizontal"   
            android:layout_width="fill_parent"   
            android:layout_height="fill_parent"   
            android:padding="10dp"   
            >   
    <ImageView android:id="@+id/image"   
               android:layout_width="wrap_content"   
               android:layout_height="fill_parent"   
               android:layout_marginRight="10dp"   
               />   
    <TextView android:id="@+id/text"   
            android:layout_width="wrap_content"   
            android:layout_height="fill_parent"   
            android:textColor="#FFF"   
            />   
</LinearLayout>   这个xml在LinearLayout里定义了一个ImageView和TextView。2-设置上面的布局为dialog的context view ,并且定义ImageView和TextView两个元素。   
    Context mContext = getApplicationContext();   
Dialog dialog = new Dialog(mContext);   
dialog.setContentView(R.layout.custom_dialog);   
dialog.setTitle("Custom Dialog");   
TextView text = (TextView) dialog.findViewById(R.id.text);   
text.setText("Hello, this is a custom dialog!");   
ImageView image = (ImageView) dialog.findViewById(R.id.image);   
image.setImageResource(R.drawable.android);实例化dialog后,使用setContextView(int)方法设置自定义的布局。现在dialog便有了一个自定义的布局,你可以使用findViewById(int)方法来获得或者修改布局。3-完成了,现在你可以显示自定义的dialog了。一个dialog必须有一个title,如果你没有调用setTitile()方法,那么会标题处会显示空,但dialog仍然可见,如果你不想显示标题,只有写一个自己的dialog类了。然而,因为一个AlertDialog使用AlertDialog.builder类创建起来非常简单,你不必使用setContextView(int)方法。但必须使用setView(view)方法代替。这个方法会接受一个view参数,你需要从xml中得到根view元素。得到xml布局,通过LayoutInflater类的getLayoutflater()方法(或者getSystemService()方法),然后调用inflate(int,ViewGroup)方法,第一个参数是xml文件id,第二个参数是根view的id,在这点上,你可以使用inflated 布局来获得xml中的view对象并且定义ImageView和TextView对象,然后实例化AlertDialog.Builder类并且使用setView(View)方法来设置布局。这有一个自定义dialog布局文件的例子:    AlertDialog.Builder builder;   
AlertDialog alertDialog;   
Context mContext = getApplicationContext();   
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);   
View layout = inflater.inflate(R.layout.custom_dialog,   
                               (ViewGroup) findViewById(R.id.layout_root));   
TextView text = (TextView) layout.findViewById(R.id.text);   
text.setText("Hello, this is a custom dialog!");   
ImageView image = (ImageView) layout.findViewById(R.id.image);   
image.setImageResource(R.drawable.android);   
builder = new AlertDialog.Builder(mContext);   
builder.setView(layout);   
alertDialog = builder.create();使用自定义布局这种方式来生成dialog,可以让你使用更高级的特性,比如管理按钮、列表、标题、图标等。   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
页: [1]
查看完整版本: 《Android Dev Guide》系列教程12:用户界面之建立对话框Dialogs