對話框是人機(jī)交互中的重要控件,在開發(fā)中也經(jīng)常會用到各式各樣的對話框,總結(jié)一下主要有以下幾種:
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/11-1.png" alt="這里寫圖片描述" />
下面通過實(shí)戰(zhàn)的方式對上面總結(jié)的幾種對話框一一進(jìn)行講解。
在進(jìn)行刪除、應(yīng)用退出等操作時,通常要進(jìn)一步提示用戶是否進(jìn)行該操作,我們以開發(fā)中最常用的連續(xù)點(diǎn)兩次返回鍵,提示用戶是否退出為例,介紹一下AlertDialog是如何使用的。 這里不需要布局文件,MainActivity.java代碼如下:
public class MainActivity extends Activity {
private long mExitTime=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK){
if((System.currentTimeMillis()-mExitTime)>1000){
showDialog();
mExitTime = System.currentTimeMillis();
}
}
return super.onKeyDown(keyCode, event);
}
private void showDialog() {
Dialog dialog=new AlertDialog.Builder(this)
.setTitle("退出程序?")//設(shè)置標(biāo)題
.setMessage("確定退出程序嗎?")//設(shè)置提示內(nèi)容
//確定按鈕
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
//取消按鈕
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.create();//創(chuàng)建對話框
dialog.show();//顯示對話框
}
}
這里有幾點(diǎn)要說明:
覆寫了onKeyDown方法,通過這個方法可以監(jiān)聽系統(tǒng)自帶按鈕的按下操作 ,通過keyCode==KeyEvent.KEYCODE_BACK進(jìn)行判斷是否是返回鍵的按下,是返回鍵按下則進(jìn)行下一步邏輯判斷。
System.currentTimeMillis()方法返回的是當(dāng)前計(jì)算機(jī)時間和GMT時間(格林威治時間)1970年1月1號0時0分0秒之差的毫秒數(shù)。因此,我們設(shè)置了一個全局變量,用于記錄第一次按下返回鍵的時間,第二次按下時,用
System.currentTimeMillis()獲取第二次按下的時間,兩者之差就可以認(rèn)為是第一次按下返回鍵和第二次按下返回鍵之間的間隔了,這里可以好好理解一下。當(dāng)時間間隔在1000毫秒內(nèi),我們可以認(rèn)為連續(xù)按了兩次返回鍵,這時調(diào)用我們自定義的showDialog方法。
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/11-2.png" alt="這里寫圖片描述" />
上面是最基本的警告對話框的樣式,下面看一下如何使用setMultiChoiceItems和setSingleChoiceItems方法,構(gòu)造一個可供選擇的對話框。 布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="singleChoiceItems"
android:text="單選框樣式" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="multiChoiceItems"
android:text="多選框樣式" />
</LinearLayout>
定義了兩個按鈕,并分別設(shè)置了對應(yīng)的onClick屬性,用以監(jiān)聽它們的單擊事件。 MainActivity.java代碼如下:
public class MainActivity extends Activity {
String single[] = {"Java", "C", "C++"};
String multi[] = {"android", "iOS", "wp"};
StringBuilder sb;
private String singleChoice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void singleChoiceItems(View view) {//單選按鈕監(jiān)聽
Dialog dialog = new AlertDialog.Builder(this)
.setTitle("單選對話框?qū)嵗?)
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
singleChoice = single[0];//默認(rèn)選擇第一項(xiàng)
Toast.makeText(MainActivity.this, "選擇了" + singleChoice, Toast.LENGTH_SHORT).show();
dialog.dismiss();
}
})
//設(shè)置單選框監(jiān)聽
.setSingleChoiceItems(single, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
singleChoice = single[which];//根據(jù)which決定選擇了哪一個子項(xiàng)
}
}).create();
dialog.show();
}
public void multiChoiceItems(View view) {//多選按鈕監(jiān)聽
sb = new StringBuilder();
Dialog dialog = new AlertDialog.Builder(this)
.setTitle("多選對話框?qū)嵗?)
.setIcon(android.R.drawable.ic_btn_speak_now)//設(shè)置圖標(biāo)
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "選擇了" + sb, Toast.LENGTH_SHORT).show();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();//隱藏對話框
}
})
//設(shè)置多選框監(jiān)聽
.setMultiChoiceItems(multi, null, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if (isChecked) {//滿足選擇條件
sb.append(multi[which] + "、");//根據(jù)which決定選擇了哪一個子項(xiàng)
}
}
}).create();
dialog.show();
}
}
這里主要用到了兩個方法:
setSingleChoiceItems:單選對話框形式,這里要傳入幾個參數(shù),第一個是數(shù)據(jù)源;第二個是默認(rèn)選擇項(xiàng),傳入數(shù)字下表;第三個是選擇事件監(jiān)聽,這里實(shí)現(xiàn)DialogInterface.OnClickListener并覆寫了其onClick方法,根據(jù)其參數(shù)值which獲得選擇項(xiàng)內(nèi)容。
setMultiChoiceItems:多選對話框形式,也要傳入幾個參數(shù),第一個是數(shù)據(jù)源;第二個是初始選擇的boolean數(shù)組,這里我們選擇傳入的null,默認(rèn)都不選;第三個是選擇事件監(jiān)聽,實(shí)現(xiàn)了DialogInterface.OnMultiChoiceClickListener,并覆寫了其onClick方法,方法中傳入了三個參數(shù),要根據(jù)isChecked和which兩個參數(shù)獲得選擇項(xiàng)內(nèi)容。
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/11-3.png" alt="這里寫圖片描述" /> http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/11-4.png" alt="這里寫圖片描述" />
選擇項(xiàng)目之后,點(diǎn)擊確定即可Toast出選擇項(xiàng)目的內(nèi)容。
顧名思義,這控件以對話框的形式設(shè)置時間和日期,下面可以通過一個實(shí)例直觀的展示它們的用法。 布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="datePickerDialog"
android:text="日期對話框" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="timePickerDialog"
android:text="時間對話框" />
</LinearLayout>
MainActivity.java代碼如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//日期選擇對話框
public void datePickerDialog(View view) {
Dialog dialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
Toast.makeText(MainActivity.this, "您選擇的是" + year + "年" + (monthOfYear + 1) + "月" + dayOfMonth + "日", Toast.LENGTH_SHORT).show();
}
}, 2016, 03, 24);
dialog.show();//顯示對話框
}
//時間選擇對話框
public void timePickerDialog(View view) {
Dialog dialog = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
Toast.makeText(MainActivity.this, "您選擇的是" + hourOfDay + "時" + minute + "分", Toast.LENGTH_SHORT).show();
}
}, 14, 20, true);
dialog.show();//顯示對話框
}
}
兩個構(gòu)造方法需要如下說明:
DatePickerDialog(Context context, DatePickerDialog.OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth)共有五個參數(shù),第一個是上下文對象,第二個是日期選擇事件監(jiān)聽,第三個是初始化年,第四個是初始化月,第五個是初始化日。實(shí)現(xiàn)日期選擇監(jiān)聽接口,同時要覆寫onDateSet方法,這個方法給我們提供選擇后的年、月、日參數(shù),這里要注意的是月要加上1,才是選擇的月份。
TimePickerDialog(Context context, TimePickerDialog.OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView)也有五個參數(shù),第一個是上下文對象,第二個是時間選擇事件監(jiān)聽,第三個是初始化小時,第四個是初始化分鐘,第五個是布爾型變量,是否是24小時制,傳入true設(shè)置24小時制,反之亦然。
進(jìn)度對話框在項(xiàng)目開發(fā)中經(jīng)常會用到,進(jìn)行耗時操作時經(jīng)常會用到,將操作進(jìn)度實(shí)時反饋給用戶,可以提高用戶體驗(yàn)。 API文檔中給我們提供的方法主要有:
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/11-5.png" alt="這里寫圖片描述" />
下面通過一個實(shí)例,對上面的方法進(jìn)行學(xué)習(xí)。 布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="progressDialog"
android:text="模擬網(wǎng)絡(luò)請求 彈出ProgressDialog" />
</RelativeLayout>
MainActivity.java代碼如下:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void progressDialog(View view) {
final ProgressDialog progressDialog = new ProgressDialog(this);//獲得ProgressDialog對象
progressDialog.setTitle("正在網(wǎng)絡(luò)請求...");
//設(shè)置進(jìn)度對話框樣式
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMax(100);//設(shè)置最大進(jìn)度
progressDialog.setProgress(10);//設(shè)置初始進(jìn)度
//設(shè)置按鈕
progressDialog.setButton( "隱藏", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
progressDialog.dismiss();
}
});
progressDialog.onStart();//啟動進(jìn)度條
new Thread() {//新開一個線程模擬網(wǎng)絡(luò)請求
@Override
public void run() {
int i = 10;
while (i <=100) {
try {
Thread.sleep(100);//線程休眠100毫秒
progressDialog.incrementProgressBy(1);//每次增加1
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
progressDialog.dismiss();//進(jìn)度條走完時,調(diào)用dismiss方法隱藏進(jìn)度對話框
}
}.start();
progressDialog.show();
}
}
這里也是新開了一個線程用以模擬網(wǎng)絡(luò)請求這一耗時操作,判斷當(dāng)進(jìn)度小于最大進(jìn)度時,調(diào)用sleep方法,休眠100毫秒,然后調(diào)用ProgressDialog的incrementProgressBy方法在原來進(jìn)度的基礎(chǔ)上加1,進(jìn)度條走到最大進(jìn)度時,調(diào)用ProgressDialog的dismiss方法,隱藏進(jìn)度對話框。 運(yùn)行實(shí)例如下:
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/11-6.png" alt="這里寫圖片描述" />
系統(tǒng)的對話框形式是有限的,一般不能滿足實(shí)際項(xiàng)目需要,這里通過一個自定義布局的進(jìn)度對話框模擬網(wǎng)絡(luò)請求的過程,并引入了動畫方面的相關(guān)知識,對這部分知識不熟悉的同學(xué)可以先行跳過,后面還會對動畫知識系統(tǒng)講解。 主布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:onClick="test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="模擬請求" />
</RelativeLayout>
非常簡單,只是一個Button,并設(shè)置其onClick屬性。 對話框布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff"
android:gravity="center"
android:minHeight="60dp"
android:minWidth="180dp"
android:orientation="vertical"
android:padding="10dp">
<ImageView
android:id="@+id/img"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@mipmap/load" />
<TextView
android:id="@+id/tv_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="數(shù)據(jù)加載中……" />
</LinearLayout>
對話框布局文件包括一個圖片控件和一個文本控件,通過src屬性引入圖片控件的圖片源。這里還自定義對話框的樣式,因此需要在styles.xml文件中的resources標(biāo)簽中加入如下代碼:
<!-- 自定義loading dialog -->
<style name="loading_dialog" parent="android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
style可以理解成一部分Android屬性的集合,因?yàn)榫哂型ㄓ眯?,所以被抽離出來放在一起,使用的時候通過R.style.*就可以調(diào)用該樣式。定義一個樣式需要style標(biāo)簽進(jìn)行包裹,parent屬性設(shè)置類似Java中繼承的概念,這個是可選的。一個item標(biāo)簽包裹一個屬性,我們這里設(shè)置了無邊框、不顯示標(biāo)題、窗口浮動等,還有很多屬性,這里就不再進(jìn)行介紹。 為了顯示轉(zhuǎn)動的效果,這里引入了動畫內(nèi)容,動畫屬性文件如下:
<?xml version="1.0" encoding="utf-8"?>
<set android:shareInterpolator="false" xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:interpolator="@android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="+360"
android:duration="1500"
android:startOffset="-1"
android:repeatMode="restart"
android:repeatCount="-1"/>
</set>
pivotX和pivotY表示旋轉(zhuǎn)基點(diǎn),50%表示圖片中心為旋轉(zhuǎn)基點(diǎn),fromDegrees是開始角度,toDegrees是結(jié)束角度。duration表示一次動畫的時間,單位為毫秒。startOffset表示延遲多少秒后開始,repeatMode表示重復(fù)模式,repeatCount設(shè)置成-1表示無窮次。這些屬性在后面的動畫部分還會再詳細(xì)介紹,不明白的同學(xué)可以看過動畫部分后再進(jìn)行學(xué)習(xí)。 MainActivity.java:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void test(View view){
final Dialog dialog=createloadDialog(MainActivity.this,"稍等,正在加載中...");
new Thread(){
@Override
public void run() {
try {
sleep(3000);
dialog.dismiss();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
dialog.show();
}
//返回一個ProgressDialog對象
public Dialog createloadDialog(Context context, String msg) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View v = layoutInflater.inflate(R.layout.load_layout, null);// 得到加載view
LinearLayout linearLayout = (LinearLayout) v.findViewById(R.id.dialog_view);// 加載布局
// 獲取view對象中的ImageView
ImageView imageView = (ImageView) v.findViewById(R.id.img);
TextView tipTextView = (TextView) v.findViewById(R.id.tv_tip);
// 加載動畫
Animation animation = AnimationUtils.loadAnimation(
context, R.anim.load_animation);
// 設(shè)置動畫
imageView.startAnimation(animation);
tipTextView.setText(msg);// 設(shè)置加載信息
Dialog loadDialog = new Dialog(context, R.style.loading_dialog);// 創(chuàng)建自定義樣式dialog
loadDialog.setCancelable(false);// 不可以用“返回鍵”取消
// 設(shè)置布局
loadDialog.setContentView(v, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
return loadDialog;
}
}
這里說明幾點(diǎn):
運(yùn)行實(shí)例:
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/11-7.png" alt="這里寫圖片描述" />