Android 个性化 之 百变Dialog
前言
关于Dialog的使用可谓是相当的广泛,可以用来做各种处理,其中也衍生了许多种的处理方式,有好有坏,自己有必要加以拿捏,熟练了以后,便可谓是招之即来,挥之即去。
Dialog搭配一些个性化风格与简单动画会有一些神奇效果(Pics from Baidu_Pics):
dialog2.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_style1.png
结合了以上各个思路,下面给出两种可以拿来封装的样式,底部弹出的Dialog与居中弹出的Dialog:
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到其强大之处,由此写来给大家分享一下小小的心得~
-
Github地址:
https://github.com/Ivorfason -
Github博客:
http://ivorfason.github.io -
个人邮箱:(我觉得QQ邮箱很高大上,You can you up!)
justforyouymr@qq.com -
杂谈一下
关于Dialog的实现与自定义控件、自定义View其实也有一定的相似之处,当然更多的是Dialog的整体性较高,回调性与多元性可以很复杂,具体逻辑需要自己结合项目实际需求加以调控,这样的Personality便会很有意义。后期会不定期更新自己的学习心得,欢迎大家查漏补缺......
最后再来看一张很好看的效果~
dialog_sweet.gif