鍍金池/ 教程/ Android/ 第十一章-各種對話框Dialog集錦
第十八章-ViewPager+FragmentStatePagerAdapter實(shí)現(xiàn)仿微信Tab
第十五章-GridView實(shí)現(xiàn)動態(tài)添加和刪除子項(xiàng)
第九章-進(jìn)度條ProgressBar
第十二章-經(jīng)典的ListView
第十四章-GridView控件
第八章-時間相關(guān)控件
第七章-下拉框Spinner控件
第二章-EditText探秘
第二十章-Android菜單之上下文菜單
第十一章-各種對話框Dialog集錦
第二十一章-Android菜單之子菜單
第六章-切換類TextSwitcher和ImageSwitcher
第十七章-ViewPager切換界面
第五章-開關(guān)按鈕ToggleButton和Switch
第二十二章-PopupWindow浮動窗
第十六章-幻燈片ViewFlipper
第二十四章-RecyclerView動態(tài)添加、刪除及點(diǎn)擊事件
第三章-交互之王Button控件
第二十三章-全新控件RecyclerView
第一章-好玩的TextView
第十三章-ListView擴(kuò)展(多選、全選、反選)
第四章-玩轉(zhuǎn)單選和多選按鈕
第十章-可以拖動的ProgressBar-SeekBar
第十九章-Android菜單之選項(xiàng)菜單

第十一章-各種對話框Dialog集錦

對話框是人機(jī)交互中的重要控件,在開發(fā)中也經(jīng)常會用到各式各樣的對話框,總結(jié)一下主要有以下幾種:

  • AlertDialog :警告對話框是最常見的對話框形式,是Dialog的直接子類,如果想要實(shí)例化AlertDialog類,往往需要依靠其內(nèi)部類AlertDialog.Builder類完成。
  • DatePickerDialog和TimePickerDialog:日期選擇對話框和時間選擇對話框,前面我們降到了DatePicker和TimePicker控件,這兩種控件都比較占用布局界面,導(dǎo)致布局很不美觀,而以對話框的形式展示可以大大較少界面占用。
  • ProgressDialog:進(jìn)度對話框,在進(jìn)行網(wǎng)絡(luò)請求或文件操作等耗時操作時常常會用到。
  • 定制對話框,對于一些復(fù)雜的界面想做成對話框的形式,可以自行定制一個對話框。 總結(jié)一下常用的方法主要有:

http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/11-1.png" alt="這里寫圖片描述" />

下面通過實(shí)戰(zhàn)的方式對上面總結(jié)的幾種對話框一一進(jìn)行講解。

AlertDialog

在進(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方法。

  • showDialog是我們自定義的方法,里面調(diào)用了對話框的很多常用方法用以構(gòu)造一個警告對話框,已經(jīng)在代碼中做了詳細(xì)注釋。這里需要說明的是,調(diào)用create方法構(gòu)造對話框之前是一個語句,采用分行可以更好理解創(chuàng)建步驟及每一步的含義。最后記得調(diào)用show方法顯示對話框。 運(yùn)行實(shí)例如下:

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)容。

  • 我們可以看出,這兩個方法參數(shù)內(nèi)容和監(jiān)聽都是較為相似的,學(xué)習(xí)技術(shù)就是要分析出事物的相似性,辨別其不同性,這樣才能舉一反三,增進(jìn)理解,并提高學(xué)習(xí)速度。 運(yùn)行如下:

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)容。

DatePickerDialog和TimePickerDialog

顧名思義,這控件以對話框的形式設(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構(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構(gòu)造方法

TimePickerDialog(Context context, TimePickerDialog.OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView)也有五個參數(shù),第一個是上下文對象,第二個是時間選擇事件監(jiān)聽,第三個是初始化小時,第四個是初始化分鐘,第五個是布爾型變量,是否是24小時制,傳入true設(shè)置24小時制,反之亦然。

ProgressDialog

進(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):

  • createloadDialog方法返回一個ProgressDialog對象,這里使用了LayoutInflater類的inflate獲得了進(jìn)度框的View對象,并使用findViewById方法獲取了View對象中的控件。加載動畫文件時用到了AnimationUtils的loadAnimation方法,可以得到一個動畫對象,開始動畫使用了Animation類的startAnimation方法。
  • 對于Dialog的實(shí)例化,第一個參數(shù)是上下文對象,第二個是主題樣式,設(shè)置了setCancelable方法的參數(shù)為false,表示不可以用返回鍵取消對話框,最后調(diào)用Dialog的setContentView方法,傳入對話框布局文件對象和布局方式以渲染對話框布局界面。
  • 采用了線程睡眠的方式,讓線程睡眠3秒后調(diào)用Dialog的dismiss方法關(guān)閉對話框,模擬請求完成。

運(yùn)行實(shí)例:

http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/11-7.png" alt="這里寫圖片描述" />