自定义dialog的方式,以及需要注意事项
来源:互联网 发布:淘宝怎么进淘宝客 编辑:程序博客网 时间:2024/06/04 19:35
上一次总结记录了dialog的载体是什么(window),在某种情况下setContentView会重置LayoutParams导致我们之前设置好的LayoutParams无效,为什么dialog依赖于activity;
这次总结一下自定义dialog的一些方式,以及需要注意的一些事项,好吧下面就来记录一下自定义dialog的方式:
方式一:
public static AlertDialog showAddProductDialog(Context context, View.OnClickListener clickListener) { final AlertDialog dialog = new AlertDialog.Builder(context).setCancelable(false).create(); dialog.show(); Window window = dialog.getWindow(); window.setContentView(R.layout.dialog_price_add); window.findViewById(R.id.dialog_price_cancel).setOnClickListener(clickListener); window.findViewById(R.id.dialog_price_confirm).setOnClickListener(clickListener); return dialog; }
上面这种方式类自动dialog,个人觉得是最简单不过的了,也是用的比较多的方式。好了这种方式简单归简单其实也是有需要我们注意的地方的。
比如在上一次dialog的总结中说到的,在show()之前设置LayoutParams,在show()后setContentView()就会重置了原来设置的LayoutParams;那么肯能有人会提出质疑,为什么不可以在show()之前去setContentView呢?下面就是要说说为什么不在show()之前去setContentView,其实是因为会抛出
throw new AndroidRuntimeException(“requestFeature() must be called before adding content”);这个异常,所以不可以在show()之前调用,那到底为什么呢?看下面的源码:
@Override public void setContentView(int layoutResID) { ... if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } ... }
当这mContentParent == null就去调用installDecor();接着看:
private void installDecor() { if (mDecor == null) { mDecor = generateDecor(); ... } if (mContentParent == null) { mContentParent = generateLayout(mDecor); ... } }
由上面可以看出当mDecor == null创建mDecor这里不是我们的重点滤过,接着看当mContentParent为空的时候调用generateLayout(mDecor);创建mContentParent,好了setContentView介绍到此为止,毕竟后面的个人觉得都不重要;
这个时候问题就来了,就上面的那部分源码还不足以说明在show()之前setContentView会抛出异常的问题,这个时候我们回归到setContentView执行完以后调用的show()方法,从上一次总结提到过onCreate()方法是在show()里面调用的,我们就去看看AlertDialog的onCreate方法,如下:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAlert.installContent(); }
下面接着看mAlert.installContent();代码如下:
public void installContent() { /* We use a custom title so never request a window title */ mWindow.requestFeature(Window.FEATURE_NO_TITLE); int contentView = selectContentView(); mWindow.setContentView(contentView); setupView(); setupDecor(); }
这里我们就看第一句mWindow.requestFeature(Window.FEATURE_NO_TITLE);其实异常就是从这里面抛出来的,看看里面的代码:
@Override public boolean requestFeature(int featureId) { if (mContentParent != null) { throw new AndroidRuntimeException("requestFeature() must be called before adding content"); } ... }
到这里也就明朗了,当我们调用setContentView以后mContentParent已经创建完成了,但是show方法里面经过层层调用最终调用到了mWindow.requestFeature(Window.FEATURE_NO_TITLE);这个方法,它里面里有这么一个判断mContentParent != null的时候就抛出异常,由于mContentParent在onCreate前就已经存在了所以,当调用requestFeature的时候就会破除异常,所以不可以在show()之前调用setContentView方法。
同理如果要需要设置mWindow.requestFeature那就必须要在onCreate之前去掉调用,也就是在show之前去调用,不也会因为mContentParent已经存而导致抛出异常;
至于LayoutParams的设置时期在这里就不多讲了,在这里写链接内容 就已经讲述过了。
下面就继续说说第二种自定义dialog的方式:
第二种自定义dialog的方式就是继承dialog或者alertDialog,下面就看一个例子:
public class StockDialog extends AlertDialog implements View.OnClickListener { private Context context; private TextView title, tv1, tv2; private EditText ed1, ed2, ed3; private Button btn; private ImageView img; private BasicVHolder holder; public StockDialog(Context context) { super(context); this.context = context; } public StockDialog(Context context, int theme) { super(context, theme); this.context = context; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); View view = LayoutInflater.from(context).inflate(R.layout.dialog_stock_info, null); setContentView(view); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); } public void setTitle(String str) { holder.setText(R.id.stock_info_dialog_title, str); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.stock_info_dialog_img: dismiss(); break; case R.id.stock_info_dialog_btn: String str1 = ((EditText) holder.getChildeView(R.id.stock_info_dialog_ed1)).getText().toString(); String str2 = ((EditText) holder.getChildeView(R.id.stock_info_dialog_ed2)).getText().toString(); String str3 = ((EditText) holder.getChildeView(R.id.stock_info_dialog_ed3)).getText().toString(); dismiss(); break; } }}
上面这个例子是通过继承AlertDialog来实现自定义dialog需求的,下面就讲一下其中需要注意的地方,首先继承AlertDialog如果你需要设置dialog的Feature(调用requestFeature)的话,那么久不许要注意requestFeature的调用时期了,要在super.onCreate之前调用,至于为什么这里就不在细讲了,上面已经接绍过了,但是如果你继承的是dialog,就可以不必再super.onCreate方法前调用,因为dialog中的onCreate方法是一个空方法。
如果继承AlertDialog来自定义那么如果需要用到EditText的话,那么还需要加上上这么一句:
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);FLAG_NOT_FOCUSABLE 表示window不会拦截所有的焦点FLAG_ALT_FOCUSABLE_IM 表示window不会拦截键盘输入时间的焦点
如果不设置这一句的话EditText就无法获得焦点,也就是无法输入信息,那么到底是为什么呢?下面就来看看以下这个方法:
private void setupCustomContent(ViewGroup customPanel) { final View customView; if (mView != null) { customView = mView; } else if (mViewLayoutResId != 0) { final LayoutInflater inflater = LayoutInflater.from(mContext); customView = inflater.inflate(mViewLayoutResId, customPanel, false); } else { customView = null; } final boolean hasCustomView = customView != null; if (!hasCustomView || !canTextInput(customView)) { mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); } ... }
从上面的代码可以看出来一般情况下customView!=null,说以就会给Window设置Flags,来看看setFlags中的传入参数FLAG_ALT_FOCUSABLE_IM,这个常量表示Window拦截了所有的焦点,说以要想对EditText进行输入操作,你就必须释放焦点的拦截,所有需要调用上面的那一句话,如果继承的是dialog就不需要释放焦点拦截。
对应继承父类来实现自定义dialog,如果需设置LayoutParams只要在setContentView以后调用就可以了,这里就不详细说了,阅读全文就可以知道了。
关于继承dialog来实现自定义,可以去参考参考一下AlertDialog,关于AlertDialog里面的实现是通过一个构建者模式来完成AlertDialog的创建过程,AlertDialog.Bulider类把创建过程委托给了AlertController,所有负责的创建操作都是在这个类里面实现的,Bulider类就相当于一个桥梁的作用。这样可以似的构建与表现分离开来,可以通过同样的构建过程创建不同的表现形态。
到这里,本次的总结就告一段落。希望我的个人记录可以对其他人也带来帮助。
- 自定义dialog的方式,以及需要注意事项
- 自定义Dialog以及Dialog的相关问题
- 【Android】Dialog以及自定义Dialog
- Dialog对话框以及自定义Dialog
- Android 自定义Dialog以及参数的传递
- 自定义Dialog,并设定Dialog的大小以及位置
- Android中的Dialog的使用以及自定义Dialog
- 自定义Dialog的几种实现方式
- 自定义dialog的两种方式
- 自定义Dialog的两种实现方式
- 自定义 Dialog方式的加载动画
- Android 推荐的自定义 Dialog 实现方式
- 再看Dialog,用继承的方式自定义Dialog
- 自定义Dialog实现方式
- ExpandableListView的自定义布局以及注意事项
- 自定义surfaceview的步奏以及注意事项
- 自定义Dialog以及Dialog之间跳转
- Dialog和自定义Dialog以及日期对话框
- Volley
- 设计模式分类及介绍
- 添加重启和飞行模式
- Graham's Scan法求凸包
- 解析QT多线程程序详细设计之QObject可重入性 下篇
- 自定义dialog的方式,以及需要注意事项
- OpenCV : 基于切线方向的边缘增强算法
- react
- [Linux] 内核的 /proc 文件系统介绍及使用方法
- 05 简单的字符设备驱动操作
- 输入任意正整数a,b,c,返回最大值
- Java Serialization/序列化/反序列化 及 transient Java关键字详解
- eclipse自动调整代码格式
- 专题四1011