今天继续Android学习之旅之对话框Dialog的记录,主要包括三个方面:1.时间弹框;2.自定义弹框;3.等待弹框。

        1.时间弹框

        时间弹框分为日期弹框和时间弹框


        1.1日期弹框

        点击按钮的事件代码:

private class OnClickListenerDateImpl implements
		android.view.View.OnClickListener {

	@Override
	public void onClick(View v) {
		Dialog dialog = new DatePickerDialog(MainActivity.this,
				new OnDateSetListener() {

					@Override
					public void onDateSet(DatePicker view, int year,
							int monthOfYear, int dayOfMonth) {
						String info = "选择的时间为:" + year + "-"
								+ (monthOfYear + 1) + "-" + dayOfMonth;
						Toast.makeText(MainActivity.this, info,
								Toast.LENGTH_LONG).show();
					}
				}, 2014, 8, 9);// 月份需要减一,默认值2014-09-09
		dialog.show();
	}

}

        注意的是设置默认值时,月份要在原有的基础上减一,实际取值时需要加一,例如要设置2014-08-02则是(2014,7,2),具体可以看代码。


        效果如下:

android dialog类 通用 android中dialog_android

        1.2时间弹框

        跟日期弹框类似,代码如下:


private class OnClickListenerTimeImpl implements
		android.view.View.OnClickListener {

	@Override
	public void onClick(View v) {
		Dialog dialog = new TimePickerDialog(MainActivity.this,
				new OnTimeSetListener() {

					@Override
					public void onTimeSet(TimePicker view, int hourOfDay,
							int minute) {
						String info = "选择的时间为:" + hourOfDay + ":" + minute;
						Toast.makeText(MainActivity.this, info,
								Toast.LENGTH_LONG).show();
					}

				}, 15, 30, true);
		dialog.show();
	}

}

        效果如下:




android dialog类 通用 android中dialog_Dialog_02


       2.自定义弹框

        2.1简单的自定义弹框

        在实际的业务中经常会有弹框需要输入密码或者其他信息的操作,这时就需要自定义弹框。简单的说就是,在弹框中自定义一个View。我以弹框输入昵称为例,代码如下:


private class OnClickListenerNickNameImpl implements
		android.view.View.OnClickListener {

	@Override
	public void onClick(View v) {
		final EditText et = new EditText(MainActivity.this);
		Dialog dialog = new AlertDialog.Builder(MainActivity.this)
				.setIcon(R.drawable.qq)
				.setTitle("设置昵称")
				.setView(et)
				.setPositiveButton("确定",
						new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								String info = "输入的昵称是:"
										+ et.getText().toString();
								Toast.makeText(MainActivity.this, info,
										Toast.LENGTH_LONG).show();

							}
						})
				.setNegativeButton("取消",
						new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								Toast.makeText(MainActivity.this, "您已取消操作",
										Toast.LENGTH_LONG).show();
							}
						}).create();
		dialog.show();

	}

}

        注意:1.et对象需要final修饰,否则在弹框的内部类里面无法访问该对象;2.et的定义需要在onClick方法里定义而不能是是类OnClickListenerNickNameImpl中定义,否则在第二次点击按钮弹框时就会报错java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

        效果如下:



android dialog类 通用 android中dialog_自定义弹框_03


        2.2复杂的自定义弹框

         在实际业务中还有很多弹出框不是只有一个输入框的,例如登录,就需要用户名和密码(有时候还要验证码)。这时候虽然也可以通过代码构造出一个复杂的View,但总不是那么爽,这时可以通过布局文件结合LayoutInflater来实现,下面以登录框为例来讲解。


        首先定义布局文件login.xml


<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TableRow>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="用户名:" />
        <EditText
            android:id="@+id/userName"
            android:layout_width="80pt"
            android:layout_height="wrap_content" />
    </TableRow>
    <TableRow>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="密  码:" />
        <EditText
            android:id="@+id/password"
            android:layout_width="80pt"
            android:layout_height="wrap_content"
            android:password="true" />
    </TableRow>
</TableLayout>

         点击事件代码如下:

private class OnClickListenerLoginImpl implements
		android.view.View.OnClickListener {

	@Override
	public void onClick(View v) {
		LayoutInflater factory = LayoutInflater.from(MainActivity.this);
		final View loginView = factory.inflate(R.layout.login, null);
		Dialog dialog = new AlertDialog.Builder(MainActivity.this)
				.setIcon(R.drawable.qq)
				.setTitle("登录")
				.setView(loginView)
				.setPositiveButton("登录",
						new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {

								EditText userName = (EditText) loginView
										.findViewById(R.id.userName);
								EditText password = (EditText) loginView
										.findViewById(R.id.password);
								String name = userName.getText().toString();
								String pwd = password.getText().toString();
								String info = "输入的用户名是:" + name
										+ ";输入的密码是:" + pwd;
								Toast.makeText(MainActivity.this, info,
										Toast.LENGTH_LONG).show();

							}
						})
				.setNegativeButton("取消",
						new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								Toast.makeText(MainActivity.this, "您已取消操作",
										Toast.LENGTH_LONG).show();

							}
						}).create();
		dialog.show();

	}

}

        关键点就是:

LayoutInflater factory = LayoutInflater.from(MainActivity.this);
final View loginView = factory.inflate(R.layout.login, null);

        这个就将布局文件封装成一个View,其他的跟简单的自定义弹框一样。


        这里注意的是:


            a.文本框的宽度单位用的是pt(而不是px),这样看着更舒服,具体相关知识可以自行查阅;


            b.取输入的值时运用loginView.findViewById(R.id.userName);

        效果如下:

android dialog类 通用 android中dialog_自定义弹框_04

        点击登录之后显示输入的信息(实际项目就验证登录了):

android dialog类 通用 android中dialog_Android_05

        3.等待弹框

        在平时用app时常常会遇到耗时操作(比如网络不佳时),软件会进入假死状态(默认的好像是5s),这时为了提高用户体验度就需要给用户一个提示,表示程序还在运行。ProgressDialog正是为了解决这类问题的。


按钮点击事件代码:


private class OnClickListenerLongOperateImpl implements
		android.view.View.OnClickListener {

	@Override
	public void onClick(View v) {
		final ProgressDialog dialogLongOperate = new ProgressDialog(
				MainActivity.this);
		dialogLongOperate.setTitle("耗时操作");
		dialogLongOperate.setMessage("正在操作,请耐心等待......");
		dialogLongOperate.show();
		new Thread() {
			public void run() {
				try {
					System.out.println("开始Thread.sleep");
					Thread.sleep(3000);
					System.out.println("结束Thread.sleep");
				} catch (Exception e) {

				} finally {
					dialogLongOperate.dismiss();
					handlerLongOperate.sendEmptyMessage(0);
				}
			}
		}.start();

	}
}

        在代码中让线程停了三秒以模拟耗时操作,另外注意的是finally中的代码,不管线程执行的情况如何最终都会进入finally块中,dialogLongOperate.dismiss();将等待框销毁。在android4之后,非UI线程是无法直接更新UI线程的,这时需要通过handlerLongOperate.sendEmptyMessage(0)通知主线程进行弹出提醒。handlerLongOperate的定义如下:

Handler handlerLongOperate = new Handler() {
	public void handleMessage(Message msg) {
		Toast.makeText(MainActivity.this, "耗时操作执行成功", Toast.LENGTH_LONG)
				.show();
	}
};

        运行结果:



android dialog类 通用 android中dialog_自定义弹框_06


        后记:这个代码还是收获很多的,写代码时遇到好几个问题,其中印象最深的就是将线程中的run写成了Run,这个问题调了好久。后来才发现,这问题本不该出现,因为有个警告信息编译器在Run的地方有个警告信息,显示那段代码从未用过。下次遇到类似警告的信息不能直接无视,否则就得走冤枉路,浪费时间。