Ivor Android World

Oh My Android


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

Android 个性化 之 百变 Dialog

发表于 2016-05-31

title: ### 前言
  关于Dialog的使用可谓是相当的广泛,可以用来做各种处理,其中也衍生了许多种的处理方式,有好有坏,自己有必要加以拿捏,熟练了以后,便可谓是招之即来,挥之即去。
  Dialog搭配一些个性化风格与简单动画会有一些神奇效果(Pics from Baidu_Pics):

dialog1.gif
  实现类似的展示效果并不难,接下来会在页面的基础上加入一些回调设置的说明,在开始之后还是先来看下其继承结构吧:

java.lang.Object    
  ↳ android.app.Dialog

-->implements DialogInterface, KeyEvent.Callback, View.OnCreateContextMenuListener, Window.Callback

  由此可知,Dialog是一个可以独立的控件,而DialogInterface和KeyEvent.Callback也说明其是一个回调性很强的Object,在诸多的Dialog实例中,其子类AlertDialog是一种很好的实现方式,下面会具体介绍。

Dialog的初始化

  Dialog和普通的View不同,它有自己的生命周期。

  • 通过onCreate( )创建

    @Override
    protected void onCreate(Bundle savedInstanceState) {    
          super.onCreate(savedInstanceState);    
          setContentView(R.layout.my_dialog);    
    }
    

      可以看出和Activity的onCreate( )类似,也可以在其中加入一些init( )方法对layout文件中的子控件进行监听等。下面看一下调用方式:

    MyDialog myDialog = new MyDialog(this);
    myDialog.setCanceledOnTouchOutside(false);
    myDialog.show();
    // 具体逻辑
    
  • 通过构造方法创建

    public MyDialog(Activity activity, int resLayout) {    
          super(activity, R.style.myDialog);    
          this.activity = activity;
          this.resLayout = resLayout;
    }
    

      构造方法中的参数可以根据需求来定义,一般不超过5个,不然会影响性能,下面看一下调用方式:

    MyDialog myDialog = new MyDialog(this, R.style.myDialog, R.layout.my_dialog);
    myDialog.show();
    
  • 创建与销毁时的细节
      而这两种创建方法却有一点不同:onCreate( )创建的Dialog的逻辑处理需在show( )之后,相当于调用了show( )之后才会真正的创建出来,而通过构造方法创建的Dialog的show( )可以放在最后的位置,相当于一个整体的展示。
      而一般自定义的Dialog由于个性化需求较大,所以其style一般需要简单定制一下:

    <!-- 自定义Dialog的Theme定义 -->
    <style name="myDialog" parent="android: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>
          <item name="android:windowBackground">@android:color/transparent</item>
    </style>
    

      对于Dialog的销毁,有两种方法:dismiss( )和cancel( ),仔细的童鞋会发现cancel( )其实中调用了dismiss( )的,只是加了一个对mCancelMessage的判断,看下该源码:

    public void setOnCancelListener(final OnCancelListener listener) {  
          if (listener != null) {  
                mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener);  
          } else {  
                mCancelMessage = null;  
          }  
    }  
    
    public void setCancelMessage(final Message msg) {  
          mCancelMessage = msg;  
    }  
    

      也就是说,如果调用了setOnCancelListener,这个mCancelMessage变量有作用,否则dismiss( )和cancel( )等同。
      此外,还可以对Dialog的透明,展出方向(上下左右)等进行设置,如下图便是一个底部弹出的Dialog:
    dialog_bottom.png

###Dialog的回调监听
  Keep your eyes on……重点来了,关于Dialog最重要的除了展示效果外无非就是其回调的设置了,而其回调方式有很多种,有把Dialog当作Activity的方式来处理的,有使用DialogInterface来处理的,有把Dialog当作View的方式来处理,还有使用loop/handler的方式来处理的……总之有很多种方式,具体的逻辑与效率总有优劣之处,请大家自己掌控~下面来一一介绍:

  • Dialog VS Handler
      使用Handler的方式,可以通过构造函数传递参数,然后在消息队列中捕获并处理,这种方式比较简洁,在调用的位置加上:

    myDialog.setHandler(mHandler);
    

      在Dialog中:

    private void setHandler(mHandler) {
          this.mHandler = mHandler;
    }
    

      然后便是在Activity中通过handleMessage(msg)方法进行处理,当然可以在此进行优化,使用静态内部类InnerHandler + 弱引用WeakReference的方式(附参考链接),将具体的回调设置在此处处理。

  • Dialog VS DialogFragment
      DialogFragment集Dialog与Fragment于一身,貌似很强大。DialogFragment配合DialogInterface使用比较切合,在调用的位置:

    MyDialog myDialog = new MyDialog(this, R.style.myDialog, R.layout.my_dialog);
    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
    myDialog.show(fragmentTransaction, null);
    

      而此时的MyDialog需要继承自DialogFragment,即按Fragment的方式来初始化Dialog,在我们需要回调处理的地方:

    MyActivity instance = (MyActivity) getActivity();
    instance.onDialogBack();
    

      即相当于回调了Activity中的onDialogBack( )方法:

    public void onDialogBack() {   
          // 具体逻辑
    }
    
  • Dialog VS setListener( )
      看过我以前自定义View的童鞋一定也了解其实现思路,即在Dialog中加入一些setListener( )方法,然后在实例化后直接该用内部的setListener( )方法即可,两种创建方式都可行,只需将myDialog对象调用MyDialog中的方法:

    Dialog中:
    public void setMyVisibility(boolean visibility) {    
          mView.setVisibility(visibility ? View.VISIBLE : View.GONE);
    }
    
    Activity中:
    myDialog.setMyVisibility(true);
    
  • Example
      结合了以上各个思路,下面给出两种可以拿来封装的样式,底部弹出的Dialog与居中弹出的Dialog:
    dialog_style1.png
    dialog_style2.png

###AlertDialog初探
  AlertDialog是一种极其个性化的Dialog,相当于一个样式封装好的Dialog,便于调用,默认的风格便是一种最简单的处理,当然也可以自定义,在其初始化时使用了强大且神奇的Build-建造者模式。
  AlertDialog的构造方法全部是Protected的,所以不能直接通过new一个AlertDialog来创建出一个AlertDialog,需要用到AlertDialog.Builder中的create()方法:

Dialog alertDialog = new AlertDialog.Builder(this)   
      .setTitle("Title")                                    // 标题
      .setMessage("Content")                                // 内容
      .setPositiveButton("OK", this)                        // Positive Button
      .setNegativeButton("Cancel", this);                   // Negative Button
      .setNeutralButton("Neutral", this);                   // Neutral Button
      .setItems(new String[] {"A", "B", "C"}, this);        // 条目
      .setIcon(R.drawable.ic_launcher)                      // 图标
      .create();
alertDialog.show(); 

  因为是建造者模式,所以上面这些Build的内容都是Optional的,而其中若想添加监听,可以这样实现:

 .setPositiveButton("OK", new DialogInterface.OnClickListener() {                                                    
      @Override                     
      public void onClick(DialogInterface dialog, int which) {                         
            // TODO Auto-generated method stub                      
      }                 
})

  针对于其中的setItem( ),也可以有这样的扩展,效果如下:

.setSingleChoiceItems(new String[] {"A", "B", "C", "D"}, 0, this);       // 单选条目      

single_item.png

.setMultiChoiceItems(new String[] {"A", "B", "C", "D"}, 0, this);        // 多选条目

multi_item.png
  此外值得一说的是,若是继承了DialogFragment,则在使用了AlertDialog的setButton( )后,可以重写父类的onClick( )方法直接回调,感觉很强大的样子:

@Override
public void onClick(DialogInterface dialog, int which) {    
       switch(which) {
              case AlertDialog.BUTTON_NEGATIVE:
                     // TODO
                     break;
              case AlertDialog.BUTTON_NEGATIVE:
                     // TODO
                     break;
              // TODO
       }    
}

  当然AlertDialog还有很多方法,这里就不一一介绍了,其中pedant大神对其有仔细研究,有兴趣的可以去看看他的sweet-alert-dialog。我以前也参考过一些用例,简单写过一个AlertDialogDemo,大家也可以参考一下~

尾声

  关于Dialog这部分自己是一点一点踩过了许多坑,然后总结了许多种实现方式从而最终Get到其强大之处,由此写来给大家分享一下小小的心得~

  • 附Android手机录视频转Gif格式与Video 转 Gif 实战
  • Github地址:
    https://github.com/Ivorfason
  • Github博客:
    http://ivorfason.github.io
  • 新浪博客
    http://blog.sina.com.cn/u/1780835484
  • 个人网站:
    http://www.ivorfason.site
  • 个人邮箱:(我觉得QQ邮箱很高大上,You can you up!)
    justforyouymr@qq.com

  • 杂谈一下
      关于Dialog的实现与自定义控件、自定义View其实也有一定的相似之处,当然更多的是Dialog的整体性较高,回调性与多元性可以很复杂,具体逻辑需要自己结合项目实际需求加以调控,这样的Personality便会很有意义。后期会不定期更新自己的学习心得,欢迎大家查漏补缺……

  最后再来看一张很好看的效果~
dialog_sweet.gif

Hello World

发表于 2016-05-31

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

Ivor

Ivor

Android Application Communication

2 日志
Links
  • DIY-green简书
© 2016 Ivor
由 Hexo 强力驱动
主题 - NexT.Pisces