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
            }
        });

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 对话框 对话框是提示用户作出决定或输入额外信息的小窗口。 对话框不会填充屏幕,通常用于需要用户采取行动才能继续执行...
    牧童遥指2000阅读 3,799评论 6 11
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,062评论 25 707
  • title: Dialog官方文档总结date: 2016-03-14 21:38:14tags: Dialogc...
    Passon_Fang阅读 2,999评论 0 7
  • 本文会不定期更新,推荐watch下项目。 如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可...
    天之界线2010阅读 13,528评论 10 124
  • 今天我要讲的童话故事 其实还没有完全想好 它既不发生在未来遥远的星球 也不开始于很久很久以前的小岛 话说故事里的王...
    郑愚阅读 170评论 0 1