倒计时的AlertDialog

来源:互联网 发布:梦里花落知多少 吧 编辑:程序博客网 时间:2024/05/29 16:43

dialog是阻塞式的提示,但是有时并不想让他一直在,可以定时自己关闭,并且帮助用户来选择其中的某个选项“确认”或者“取消”。

下面看代码吧

package com.testtimerdialog;import android.app.AlertDialog;import android.app.Dialog;import android.content.Context;import android.content.DialogInterface.OnClickListener;import android.os.Handler;import android.os.Message;import android.widget.Button;public class TimerDialog{private static final int TYPE_POSITIVE = 1;private static final int TYPE_NEGATIVE = 2;private Context mContext;private Button p = null;private Button n = null;    private int mPositiveCount = 0;private int mNegativeCount = 0;    private AlertDialog mDialog = null;public TimerDialog(Context ctx){mContext = ctx;mDialog = new AlertDialog.Builder(mContext).create();}public void setMessage(String msg){mDialog.setMessage(msg);}public void setTitle(int resId){mDialog.setTitle(resId);}public void setTitle(String title){mDialog.setTitle(title);}public void show(){//if(mPositiveCount > 0){//mHandler.sendEmptyMessageDelayed(TYPE_POSITIVE, 200);//if(p != null){//String text = (String) p.getText();//p.setText(getTimeText(text, mPositiveCount));//}//}else{//if(mNegativeCount > 0){//mHandler.sendEmptyMessageDelayed(TYPE_NEGATIVE, 200);//String text = (String) n.getText();//n.setText(getTimeText(text, mNegativeCount));//}//}mDialog.show();}public void setPositiveButton(String text, OnClickListener listener, int count){text = getTimeText(text, count);mDialog.setButton(Dialog.BUTTON_POSITIVE, text, listener);}public void setNegativeButton(String text, OnClickListener listener, int count){text = getTimeText(text, count);mDialog.setButton(Dialog.BUTTON_NEGATIVE, text, listener);}/**@param type 类型  * Dialog.BUTTON_POSITIVE * Dialog.BUTTON_NEGATIVE * @param count  * 以s为单位 * @param isDisable * 是否可点击 */public void setButtonType(int type, int count, boolean isDisable){if(count <= 0){return;}if(type == Dialog.BUTTON_POSITIVE){p = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);p.setEnabled(isDisable);mPositiveCount = count;mHandler.sendEmptyMessageDelayed(TYPE_POSITIVE, 200);}else{if(type == Dialog.BUTTON_NEGATIVE){n = mDialog.getButton(AlertDialog.BUTTON_NEGATIVE);n.setEnabled(isDisable);mNegativeCount = count;mHandler.sendEmptyMessageDelayed(TYPE_NEGATIVE, 200);}}}        private Handler mHandler = new Handler(){    public void handleMessage(Message msg){        switch(msg.what){        case TYPE_NEGATIVE:               if(mNegativeCount > 0){        mNegativeCount--;        if(n != null){        String text = (String) n.getText();        n.setText(getTimeText(text, mNegativeCount));        }        mHandler.sendEmptyMessageDelayed(TYPE_NEGATIVE, 1000);        }else{                if(n != null){        if(n.isEnabled()){        n.performClick();        }else{        n.setEnabled(true);        }        }        }        break;        case TYPE_POSITIVE:        if(mPositiveCount > 0){        mPositiveCount--;        if(p != null){        String text = (String) p.getText();        p.setText(getTimeText(text, mPositiveCount));        }        mHandler.sendEmptyMessageDelayed(TYPE_POSITIVE, 1000);        }else{                if(p != null){        if(p.isEnabled()){        p.performClick();        }else{        p.setEnabled(true);        }        }        }        break;        }        }    };            private String getTimeText(String text, int count){    if(text != null && text.length() > 0 && count > 0){    int index = text.indexOf("(");    if(index > 0){    text = text.substring(0, index);    return (text + "("+count+"s)");    }else{    return (text + "("+count+"s)");    }        }    return text;    }}

看调用的部分

        TimerDialog dialog = new TimerDialog(TimerDialogActivity.this);        dialog.setTitle("mytesttitle");        dialog.setPositiveButton("sure", new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {android.widget.Toast.makeText(getBaseContext(), "pppp", 500).show();}}, 10);        dialog.show();        dialog.setButtonType(Dialog.BUTTON_POSITIVE, 10, true);

目前还有些粗糙,在调用的时候应该更简单。


////-----------------------------------------------------------------------

有些时候再点击确认键的时候想先判断下里面有些输入不能为空之类的,但是确认键之后dialog就消失了,为了避免此情况可以自定义个view,带上button,用来取代alertdialog,并且可以保持风格一致,没有这个设计,可以考虑下下面的内容,更加了解下android的dialog机制。

参考 http://blog.csdn.net/nokiaguy/article/details/5770263

 既然要控制对放框的关闭行为,首先就得分析是哪些类、哪些代码使这个对话框关闭的。进入AlertDialog类的源代码。在AlertDialog中只定义了一个变量:mAlert。这个变量是AlertController类型。AlertController类是Android的内部类,在com.android.internal.app包中,无法通过普通的方式访问。也无法在Eclipse中通过按Ctrl键跟踪进源代码。但可以直接在Android源代码中找到AlertController.java。我们再回到AlertDialog类中。AlertDialog类实际上只是一个架子。象设置按钮、设置标题等工作都是由AlertController类完成的。因此,AlertController类才是关键。
    找到AlertController.java文件。打开后不要感到头晕哦,这个文件中的代码是很多地。不过这么多代码对本文的主题也没什么用处。下面就找一下控制按钮的代码。
    在AlertController类的开头就会看到如下的代码:

   View.OnClickListener mButtonHandler  =   new  View.OnClickListener() {
         public   void  onClick(View v) {
            Message m  =   null ;
             if  (v  ==  mButtonPositive  &&  mButtonPositiveMessage  !=   null ) {
                m  =  Message.obtain(mButtonPositiveMessage);
            }  else   if  (v  ==  mButtonNegative  &&  mButtonNegativeMessage  !=   null ) {
                m  =  Message.obtain(mButtonNegativeMessage);
            }  else   if  (v  ==  mButtonNeutral  &&  mButtonNeutralMessage  !=   null ) {
                m  =  Message.obtain(mButtonNeutralMessage);
            }
             if  (m  !=   null ) {
                m.sendToTarget();
            }

             //  Post a message so we dismiss after the above handlers are executed 
            mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
                    .sendToTarget();
        }
    };

 

 

 

从这段代码中可以猜出来,前几行代码用来触发对话框中的三个按钮( Positive 、 Negative 和 Neutral )的单击事件,而最后的代码则用来关闭对话框(因为我们发现了 MSG_DISMISS_DIALOG 、猜出来的)。

mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
                    .sendToTarget();

上面的代码并不是直接来关闭对话框的,而是通过一个 Handler 来处理,代码如下:

     private   static   final   class  ButtonHandler  extends  Handler {
         //  Button clicks have Message.what as the BUTTON{1,2,3} constant 
         private   static   final   int  MSG_DISMISS_DIALOG  =   1 ;
        
         private  WeakReference < DialogInterface >  mDialog;

         public  ButtonHandler(DialogInterface dialog) {
            mDialog  =   new  WeakReference < DialogInterface > (dialog);
        }

        @Override
         public   void  handleMessage(Message msg) {
             switch  (msg.what) {
                
                 case  DialogInterface.BUTTON_POSITIVE:
                 case  DialogInterface.BUTTON_NEGATIVE:
                 case  DialogInterface.BUTTON_NEUTRAL:
                    ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
                     break ;
                    
                 case  MSG_DISMISS_DIALOG:
                    ((DialogInterface) msg.obj).dismiss();
            }
        }
    }

 

从上面代码的最后可以找到  ((DialogInterface) msg.obj).dismiss();。现在看了这么多源代码,我们来总结一下对话框按钮单击事件的处理过程。在AlertController处理对话框按钮时会为每一个按钮添加一个onclick事件。而这个事件类的对象实例就是上面的mButtonHandler。在这个单击事件中首先会通过发送消息的方式调用为按钮设置的单击事件(也就是通过setPositiveButton等方法的第二个参数设置的单击事件),在触发完按钮的单击事件后,会通过发送消息的方式调用dismiss方法来关闭对话框。而在AlertController类中定义了一个全局的mHandler变量。在AlertController类中通过ButtonHandler类来对象来为mHandler赋值。因此,我们只要使用我们自己Handler对象替换ButtonHandler就可以阻止调用dismiss方法来关闭对话框。下面先在自己的程序中建立一个新的ButtonHandler类(也可叫其他的名)。

class  ButtonHandler  extends  Handler
{

     private  WeakReference < DialogInterface >  mDialog;

     public  ButtonHandler(DialogInterface dialog)
    {
        mDialog  =   new  WeakReference < DialogInterface > (dialog);
    }

    @Override
     public   void  handleMessage(Message msg)
    {
         switch  (msg.what)
        {

             case  DialogInterface.BUTTON_POSITIVE:
             case  DialogInterface.BUTTON_NEGATIVE:
             case  DialogInterface.BUTTON_NEUTRAL:
                ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog
                        .get(), msg.what);
                 break ;
        }
    }
}

 

 我们可以看到,上面的类和AlertController中的ButtonHandler类很像,只是支掉了switch语句的最后一个case子句(用于调用dismiss方法)和相关的代码。
    下面我们就要为AlertController中的mHandler重新赋值。由于mHandler是private变量,因此,在这里需要使用Java的反射技术来为mHandler赋值。由于在AlertDialog类中的mAlert变量同样也是private,因此,也需要使用同样的反射技术来获得mAlert变量。代码如下:

 先建立一个 AlertDialog 对象

AlertDialog alertDialog  =   new  AlertDialog.Builder( this )
        .setTitle( " abc " )
        .setMessage( " content " )
        .setIcon(R.drawable.icon)
        .setPositiveButton( “确定”,
                 new  OnClickListener()
                {
                    @Override
                     public   void  onClick(DialogInterface dialog,
                             int  which)
                    {

                    }
                }).setNegativeButton( " 取消 " ,  new  OnClickListener()
        {

            @Override
             public   void  onClick(DialogInterface dialog,  int  which)
            {
                dialog.dismiss();
            } 
        }).create()

 

 

上面的对话框很普通,单击哪个按钮都会关闭对话框。下面在调用 show 方法之前来修改一个 mHandler 变量的值, OK ,下面我们就来见证奇迹的时刻。

         try  
        {
           
            Field field  =  alertDialog1.getClass().getDeclaredField( " mAlert " );
            field.setAccessible( true );
            //   获得mAlert变量的值 
            Object obj  =  field.get(alertDialog1);
            field  =  obj.getClass().getDeclaredField( " mHandler " );
            field.setAccessible( true );
            //   修改mHandler变量的值,使用新的ButtonHandler类 
            field.set(obj,  new  ButtonHandler(alertDialog1));
        }
         catch  (Exception e)
        {
        }
       //   显示对话框 
      alertDialog.show();

  我们发现,如果加上try   catch语句,单击对话框中的确定按钮不会关闭对话框(除非在代码中调用dismiss方法),单击取消按钮则会关闭对话框(因为调用了dismiss方法)。如果去了try…catch代码段,对话框又会恢复正常了。

原创粉丝点击