前段时间在设计UI的时候看到UC的弹出菜单设计挺好 如图效果:
于是就小小的模仿了下自己写了这个这样的效果,
主要代码如下:
dlg = new AlertDialog.Builder(context).create();
dlg.show();
dlg.getWindow().setContentView(R.layout.alert_style);
LayoutInflater factory = LayoutInflater.from(context);
View view = factory.inflate(R.layout.alert_style, null);
gv = (GridView) view.findViewById(R.id.myGrid);
gv.setAdapter(new ImageAdapter(context, new Integer[] {R.drawable.menu_mark_editor,R.drawable.menu_delete}));
dlg.getWindow().setContentView(gv);
其实原理很简单,就是在弹出框AlertDialog上给他加一个自己的View 我这里使用的是GridView显示的一排图片,效果和UC的差不多!!你也可以使用ListView代替GridView,原理都是一样!
在开始本章之前,首先要感谢一下几篇文章的作者,本文正是在前人的努力下找出完全重载android alertdialog 的方法
1. AlertDialog基本用法:http://wenku.baidu.com/view/2054551910a6f524ccbf85ba.html
看了该文后,大家第一感觉重写AlertDialog的方法是 setView(View view)
不久你就可以发现一下三个问题:
1) 一旦设定setMessage和setTitle后,您将不能达到你要的效果
原因:查看android源码,AlertDialog使用的xml资源文件时alert_dialog.xml,文件位置在framework/base/core/res/value
您也可以用sourceinsight去搜索。打开文件,AlertDialog是将setView传入的View放到Message所在的view之下,而并不是覆盖原有的布局
解决方法:不能设定setMessage和setTitle,将对话框所需要的信息,卸载自己定义的view中,当然这种方法仍然不能解决alertdialog的theme和style等的设定。仅仅解决了布局问题。
2)不能有button,即不能设定setPositiveButton相应的响应函数,否则布局失效。这是相当要命的一点。
3)如上所述,不能解决风格设定,即无法贴图
否定之。。。。。。。。(郁闷中。。。。)
2. AlertDialog进阶http://wenku.baidu.com/view/2054551910a6f524ccbf85ba.html
作者通过反射技术拿到view的实例,在通过findviewbyId得到子控件的实例,从而设定Message 和title,甚至可以自己加上button以及响应函数。 解决的上述问题1、2。 但是仍然有两个问题,
1)无法去除边缘的白框,没有完全实现自定义
2)这样的AlertDialog如果加上button的响应将使其变为阻塞式的了,会卡UI,因为他们都在UI主线程做事情
继续否定之。。。。。。(狂躁。。。。)
3. AlertDialog高级http://crazier9527.javaeye.com/blog/729034 和 http://dev.10086.cn/blog/index.php?uid-634946-action-viewspace-itemid-4494
作者通过setContentView实现了完全的 布局和资源的自定应,灵活度相当高。但还是存在问题
1)扩展性不佳。代码集中在一个类中,不利于维护。读者自行思考原因,这里不展开。
2)这样的AlertDialog如果加上button的响应将使其变为阻塞式的了,会卡UI,因为他们都在UI主线程做事情
再次否定之。。。。。。。(我排山倒海。。。。问候android十八辈祖上)
4. AlertDialog精通http://www.blogjava.net/nokiaguy/archive/2010/07/27/327270.html
一看该文,就知道作者非泛泛之辈,该文冲源码入手,的确深入。虽然没有解决我们的问题,但是可以帮助我们开拓思路。
我要的就是这个,重写AlertDialog的button响应行为,并且是多线程,非阻塞式的。 好文。。。。
看了以上几篇,我来整理一下思路,得出最后的解决方案:
一、 要实现布局资源的完全自定义,android提供的API完全不够用(想起当初搞WPF全无此顾虑)
二、 要实现button行为的自定义,android没有API
三、 要实现非阻塞式的AlertDialog, android更是没有提供框架。
四、 要利用重载和反射技术,拿到AlertDialog的私有变量的访问权限,android没有参考资料
以上是难点,也是思路。
方法如下:
第一、采用反射技术,动态拿到View的资源
第二、采用自定义的布局,实现资源,样式的灵活设定和动态加载。getWindow.setContentView实现
第三、通过重载AlertDialog实现自己的主题加载,不懂的可以看看AlertDialog的私有构造函数:两个参数的那个,源码里面有。
第四、重载常用的函数,或者说必须的几个函数,实现,控件的参数化设定。
第五、仿造android 的实现方式,实现布局文件的多分辨率支持
第六、仿造android的实现方式,实现button响应的多线程实现。
核心代码:
public class MyAlertDialog extends AlertDialog {
private final static String TAG = "MyAlertDialog";
protected MyAlertDialog(Context context) {
super(context);
}
/**
* @param context
* @param theme
*/
protected MyAlertDialog(Context context, int theme) {
super(context, theme);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
return super.onKeyDown(keyCode, event);
}
public static class Builder extends AlertDialog.Builder {
@Override
public AlertDialog show(){
Log.d(TAG, "show");
this.create();
dialog.show();
installContent();
return dialog;
}
private void installContent() {
Log.d(TAG, "installContent");
mDialogInterface = (DialogInterface)dialog;
if(title != null)
((TextView)view.findViewById(R.id.title)).setText(this.title);
if(title != null)
((TextView)view.findViewById(R.id.message)).setText(this.message);
if(iconId != -1)
((ImageView)view.findViewById(R.id.icon)).setImageResource(iconId);
if(view != null)
dialog.getWindow().setContentView(view);
mButtonPositive = (Button)view.findViewById(R.id.button1);
mButtonPositive.setOnClickListener(mButtonHandler);
mButtonPositive.setText(mButtonPositiveText);
mButtonNegative = (Button)view.findViewById(R.id.button2);
mButtonNegative.setOnClickListener(mButtonHandler);
mButtonNegative.setText(mButtonNegativeText);
}
public void setButton(int whichButton, CharSequence text,
DialogInterface.OnClickListener listener, Message msg) {
if (msg == null && listener != null) {
msg = mHandler.obtainMessage(whichButton, listener);
}
switch (whichButton) {
case DialogInterface.BUTTON_POSITIVE:
mButtonPositiveText = text;
mButtonPositiveMessage = msg;
break;
case DialogInterface.BUTTON_NEGATIVE:
mButtonNegativeText = text;
mButtonNegativeMessage = msg;
break;
// case DialogInterface.BUTTON_NEUTRAL:
// mButtonNeutralText = text;
// mButtonNeutralMessage = msg;
// break;
default:
throw new IllegalArgumentException("Button does not exist");
}
}
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();
}
};
}
public 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();
}
}
}
调用:
LayoutInflater factory = LayoutInflater.from(context);
View view = factory.inflate(R.layout.alertdialoglayout, null);
new MyAlertDialog.Builder(context)
.setTitle(getString(R.string.warning))
.setMessage(message)
.setView(view)
.setIcon(R.drawable.dialog_icon)
.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialoginterface, int i) {
。。。。。。。。。。。。
}
})
.setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
。。。。。。。。。。。。
}
})
.show();