|
建立对话框Dialog
Dialog是一个常见的显示在当前activity之上的小窗口。下面的activity会失去焦点,而dialog回接受用户输入。dialog常用在与程序直接相关联的通知和短小的activity中。
Android API支持以下几种dialog:
AlertDialog:
它可以包含0、1、2、3个按钮,或者一个列表或者多选单选按钮等,它是一个功能最强大的dialog接口,详细信息可参考下面的章节。
ProgressDialog:
它会显示一个进度条或者进度环,因为他是AlertDialog的子类,所有野支持按钮。
DatePickerDialog:
用来选择日期的对话框。
TimerPickerDialog:
用来选择时间的。
如果你想要定制自己的dialog,你可以继承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的显示调用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的创建
AlertDialog时Dialog的子类,Dilaog绝大多数是这个强大类型,你可以在以下情况下使用:@ 一个标题@ 一个文本信息@ 一个两个或者三个按钮@ 一个单选或者多选列表建立AlertDialog,使用AlertDialog.Builder子类。使用AlertDialog.Builder(Context)方法来获得一个Builder,并且使用它的公共方法来定义AlertDialog所有的属性。最后,调用create()方法来显示。下面显示了如何定义AlertDialog.Builder类的一些属性,如果在onCreateDialog()方法中使用了例子中的代码,你可以返回结果对话框来显示这个dialog。添加按钮
创建一个上图所示包含按钮的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.他们名字所显示的功能并未实现,但能帮你记住要实现的功能。
添加一个列表
如上图所示,使用setItems()方法添加可选列表:
final CharSequence[] items = {"Red", "Green", "Blue"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("ick a color");
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
}
});
AlertDialog alert = builder.create();
复制代码
首先,使用setTitle(CharSequence)方法设置标题,然后使用setItem()方法添加可选列表,这个列表会接收一个item数组来显示,DialogInterFace.OnClickListener类会定义他们的点击事件。
添加选择框和单选按钮
通过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[item], Toast.LENGTH_SHORT).show();
}
});
AlertDialog alert = builder.create();
复制代码
setSingleChoiseItems()方法的第二个参数是checkedItem的id值,从0开始对应着位置,如果返回”-1“表明没有选中任何项。
进度对话框 ProgressDialog 的建立
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;
}
}
}
复制代码
自定义dialog的建立
如果你想自定义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"
androidrientation="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,可以让你使用更高级的特性,比如管理按钮、列表、标题、图标等。 |
|