今天继续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),具体可以看代码。
效果如下:
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();
}
}
效果如下:
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.
效果如下:
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);
效果如下:
点击登录之后显示输入的信息(实际项目就验证登录了):
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();
}
};
运行结果:
后记:这个代码还是收获很多的,写代码时遇到好几个问题,其中印象最深的就是将线程中的run写成了Run,这个问题调了好久。后来才发现,这问题本不该出现,因为有个警告信息编译器在Run的地方有个警告信息,显示那段代码从未用过。下次遇到类似警告的信息不能直接无视,否则就得走冤枉路,浪费时间。