Dialog使用介紹

對話框

本文Github Demo地址

Dialog是Android裏面用於讓用戶確認或輸入信息的簡單的UI展現形式,本文將通過Demo講解如何使用Dialog。通常,我們不應該直接使用Dialog,而是應該使用Dialog的子類AlertDialogDatePickerDialog以及TimePickerDialog。這三個子類對Dialog進行了封裝,並定義了它們各自的外觀結構。其中[AlertDialog]的樣式通常包含了確定和取消按鈕,以及標題和一小段描述文字。DatePickerDialogTimePickerDialog用於選擇日期和時間。

通常我們應該使用Dialogfragment作爲Dialog的容器,Dialogfragment提供了對Dialog的封裝以及生命週期的管理,可以自動處理屏幕旋轉後DialogFragment的重建(Dialog則不能),下面給出了一個DialogFragment的典型用法。

簡單的對話框

一個最簡單的對話框

public class MyDialogFragment extends DialogFragment {
    @Override    
    public Dialog onCreateDialog(Bundle savedInstanceState) {        
        // 設置Dialog樣式和theme        
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), 0);        
        builder.setTitle("提示") 
              .setMessage("確定繼續?")                
              .setPositiveButton("確定", new DialogInterface.OnClickListener() {                      
                    @Override                    
                    public void onClick(DialogInterface dialog, int which) {                        
                        communicateInterface.positiveClicked();                        
                        dismiss();                    
                    }                
                })                
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {                    
                    @Override                    
                    public void onClick(DialogInterface dialog, int which) {                        
                        communicateInterface.negativeClicked();                        
                        dismiss();                    
                     }                
                });        

        Dialog dialog = builder.create();        
        return dialog;    
    }
}

含列表的對話框

可以在對話框裏添加簡單的列表:
含列表的對話框

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {    
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());    
    builder.setTitle(R.string.pick_color)           
           .setItems(R.array.colors_array, new DialogInterface.OnClickListener() {               
                public void onClick(DialogInterface dialog, int which) {               
                    // The 'which' argument contains the index position               
                    // of the selected item           
                }    
            });    

    return builder.create();
}

自定義view樣式

自定義樣式的對話框

如果需要定製對話框的展現樣式,可以通過自定義view的方式實現。方法有兩種,調用AlertDialog.Builder的setView方法,或者重寫Fragment的onCreateView方法。

方法一:重寫onCreateDialog,調用AlertDialog.Builder的setView方法
這種方法不能修改PositiveButton或NegativeButton樣式。

@Override   
public Dialog onCreateDialog(Bundle savedInstanceState) {       
    // 設置Dialog樣式和theme       
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), 0);       
    builder.setTitle("提示")           
        .setView(getActivity().getLayoutInflater().inflate(R.layout.custom_view, null))               
        .setPositiveButton("確定", new DialogInterface.OnClickListener() {                   
            @Override                   
            public void onClick(DialogInterface dialog, int which) {                       
                dismiss();                   
            }               
        })               
        .setNegativeButton("取消", new DialogInterface.OnClickListener() {                   
            @Override                   
            public void onClick(DialogInterface dialog, int which) {                       
                dismiss();                   
            }               
        });       

    Dialog dialog = builder.create();       
    return dialog;   
}

方法二:重寫Fragment的onCreateView方法,這樣就不會使用默認的Dialog樣式,而是完全的自定義樣式

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {    
    View view = getActivity().getLayoutInflater().inflate(R.layout.custom_view_2, container, false);    
    TextView cancel = (TextView) view.findViewById(R.id.cancel_action);    
    TextView confirm = (TextView) view.findViewById(R.id.confirm_action);    
    
    cancel.setOnClickListener(new View.OnClickListener() {        
        @Override        
        public void onClick(View v) {            
            dismiss();        
        }    
    });    

    confirm.setOnClickListener(new View.OnClickListener() {        
        @Override        
        public void onClick(View v) {              
            dismiss();        
        }    
    });    

    return view;
}

Dialog和Activity交互

通過DialogFragment的onAttach方法,可以將宿主Activity/Fragment的實例傳進來,從而能在DialogFragment中調用宿主Activity/Fragment的函數。

public interface CommunicateInterface {    
    void positiveClicked();    
    void negativeClicked();
}
public class MainActivity extends AppCompatActivity implements CommunicateInterface {
    ...
    @Override
    public void positiveClicked() {    
        Toast.makeText(this, "繼續下一關", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void negativeClicked() {    
        Toast.makeText(this, "取消", Toast.LENGTH_SHORT).show();
    }
    ...
}
public class MyDialogFragment2 extends DialogFragment {
    private CommunicateInterface communicateInterface;
    ...
    @Override
    public void onAttach(Activity activity) {      
        super.onAttach(activity);    
        communicateInterface = (CommunicateInterface) activity;
    }

    @Nullable    
    @Override    
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        
        ...        
        cancel.setOnClickListener(new View.OnClickListener() {            
            @Override            
            public void onClick(View v) {                
                communicateInterface.negativeClicked();                
                dismiss();            
            }        
        });        

        confirm.setOnClickListener(new View.OnClickListener() {            
            @Override            
            public void onClick(View v) {                
                communicateInterface.positiveClicked();                
                dismiss();            
            }        
        });        
    
          return view;    
      }
}

Dialog展示

DialogFragment既可以作爲Dialog佔用一部分屏幕空間展示,也可以作爲一個Fragment全屏展示,通過不同的添加方式實現這兩種展示。

通過DialogFragment的show方法,會使Dialog佔用一部分屏幕空間展示:

@OnClick(R.id.show_as_dialog_tv)
public void onShowAsDialogTVClicked(View v) {    
    DialogFragment dialogFragment = new MyDialogFragment2();    
    dialogFragment.show(getFragmentManager(), "dialog3");
}

通過FragmentTransation添加DialogFragment可以實現全屏展示:

@OnClick(R.id.show_as_fragment_tv)
public void onShowAsFragmentTVClicked(View v) {    
    DialogFragment dialogFragment = new MyDialogFragment2();    
    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();    
    fragmentTransaction.add(dialogFragment, "diglog4") 
        .addToBackStack(null)            
        .commit();
}

這種情況有個限制,只能通過重寫onCreateView方法實現自定義view,而不能通過AlertDialog.build方式。

[Note]: 雖然Android Developer文檔提到,可以通過FragmentTransation添加DialogFragment實現全屏,但是實際測試結果表明,展示的Dialog仍然不是全屏,可參照Demo裏的實現運行查看效果。具體原因未知。如果要全屏展示直接使用Fragment就行了,也不需要使用DialogFragment,所以此處未深究原因。

普通的Activity也可以作爲Dialog展示,比如在超大屏幕上,不適合滿屏展示的情況下。如下設置theme即可。

<activity android:theme="@android:style/Theme.Holo.DialogWhenLarge" >

Dialog取消展示

可以通過dismiss函數停止Dialog的展示,或者通過cancel取消Dialog的展示,前者發生在點擊確定或取消按鈕的時候,後者發生在按返回鍵或者點擊Dialog之外的屏幕範圍的時候。通過在DialogFragment中重寫onDismiss和onCancel方法,可以加入對這兩種事件的處理。注意,這裏不能直接調用Dialog的setOnCancelListener或者setOnDismissListener方法設置回調函數,必須重寫onDismiss或onCancel,否則報錯:

java.lang.IllegalStateException:  You can not set Dialog's OnCancelListener or OnDismissListener

Android Develop文檔的描述:

Note: 
DialogFragment own the Dialog.setOnCancelListener and Dialog.setOnDismissListener callbacks. 
You must not set them yourself. 
To find out about these events, override onCancel(DialogInterface) and onDismiss(DialogInterface)

當調用DialogFragment的cancel方法時,兩個回調函數都會被調用;當調用dismiss方法時,只調用onDismiss會被調用。

Dialog展示WebView,監聽後退鍵

如果在Dialog裏嵌入WebView進行頁面展示,那需要對返回鍵進行監聽,以確定按返回鍵的時候是後退到上一個頁面還是退出dialog,通過重寫onDismiss或onCancel都無法實現這個功能,會直接退出dialog。正確的寫法是對dialog進行設置onKeyListener,代碼如下:

dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
            @Override
            public boolean onKey(DialogInterface dialogInterface, int keyCode, KeyEvent keyEvent) {
                if (keyCode == KeyEvent.KEYCODE_BACK
                        && keyEvent.getAction() == MotionEvent.ACTION_UP
                        && webView.canGoBack()) {
                    webView.goBack();
                    return true; // pretend we've processed it
                }
                else
                    return false; // pass on to be processed as normal
            }
        });

本文Github Demo地址

參考:
https://developer.android.com/guide/topics/ui/dialogs.html
https://developer.android.com/reference/android/app/DialogFragment.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章