拒绝无用功,封装一个通用的 PopupWindow,无用功popupwindow,先上效果图:1、如何使用
拒绝无用功,封装一个通用的 PopupWindow,无用功popupwindow,先上效果图:1、如何使用
作者: 夏至,欢迎转载,但请保留这段申明,谢谢
https://rcyd.net/post/5961e03e51882568b13c3308
为了避免重复造轮子,我们一般都会封装一个通用的控件,比如这次,项目中需要用到比较多的 popupwindow ,如果需要一个个写,那么依旧会累死人,而且还是无用功,无意义,所以,封装一个通用的,除了让同事看了直刷666之外,自己还省了很多事情。
先上效果图:
1、如何使用
那么,一般我们配置一个 PopupWindow 正常步骤需要多少代码呢?如下:
PopupWindow popupWindow = new PopupWindow(this); View contentview = LayoutInflater.from(this).inflate(R.layout.popup_calendar,null); popupWindow = new PopupWindow(contentview, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); //设置取消 popupWindow.setOutsideTouchable(true); popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); //设置位置 View rootview = LayoutInflater.from(this).inflate(R.layout.activity_main,null); popupWindow.showAtLocation(rootview,Gravity.CENTER,0,0);
一般我们需要实现上面的基本代码,PopupWindow 才能跑起来,然后我们还需要添加动画,监听back键等等,然后,另外一个需要用到的时候,又得重复写,真的让人很绝望,这个时候,封装的思想就从脑袋冒出来了,那么,封装之后,怎么样的呢?如下:
CustomPopupWindow popupWindow = new CustomPopupWindow.Builder(this) .setContentView(R.layout.popup_calendar) .setwidth(LinearLayout.LayoutParams.WRAP_CONTENT) .setheight(LinearLayout.LayoutParams.WRAP_CONTENT) .setFouse(true) .setOutSideCancel(true) .setAnimationStyle(R.style.popup_anim_style) .builder() .showAtLocation(R.layout.activity_calendar, Gravity.CENTER,0,0);
注意上面的 showAtLocation 是在 builder 之后的,表示显示正中间;如果想让它显示在某个 view 的相应位置,也可以使用 showAsLocation() 来实现。
至于为什么在 builder() 的后面呢?因为不太确定在用的时候,是显示在父布局的位置,还是显示在某个控件的相应位置,所以,我把代码封装成下面这样:
/** * 根据父布局,显示位置 * @param rootviewid * @param gravity * @param x * @param y * @return */ public CustomPopupWindow showAtLocation(int rootviewid,int gravity,int x,int y){ if (mPopupWindow != null){ View rootview = LayoutInflater.from(mContext).inflate(rootviewid,null); mPopupWindow.showAtLocation(rootview,gravity,x,y); } return this; }
当然,你要把它抽出来也可以的;
还有一种常见的情况,我们常用 popupwindow 作用 dialog,那么里面有 button 处理相应的逻辑。那如何想获取 PopupWindow 里面的控件怎么办?为了方便调用,这里我也采用用 id 的形式,所以,调用只要这样即可:
mMonthPicker = (PickerView) popupWindow.getItemView(R.id.picker_month);
然后就可以用 mMonthPicker 这个 view 搞事情了。
这样就把 contentview 中的控件取出来使用了,只要知道 id 就可以了,是不是方便了很多,都挺简单的,大家自己封装一边就ok全明白了。
封装思路
相比封装 listview 和 recyclerview ,这个算是比较简单的,就是观察最原始的代码,提取最核心不变的;无非就是 PopupWindow 的最要布局
cnotentview ,为了避免每次都来个 layoutinflate ,我们封装成一个 id
大小,我们都知道 PopupWindow 没有自己的布局,上面在给了 contentview 之后,大小也要给
显示位置,显示就两个函数 ,showAtLocation 和 showAsLocation ,为了方便,我们也写成 id 的方式,当然也可以传入 view
基本就可以了,至于其他附加项,比如动画,点击外部取消,监听back键,或者简单 contentview 控件的事件,都是变动的,所以,用 Builder 的模式构建比较舒服一些。具体就这些了。如果你对 Builder 这中模式不熟悉,可以看我以前文章:
模仿常用框架Builder初始化数据,如何优雅地装逼
3、CustomPopupWindow 完成代码
以下是我现在用的代码,大家可以参考一下,根据自己的需求添加或者删除。
public class CustomPopupWindow { private PopupWindow mPopupWindow; private View contentview; private static Context mContext; public CustomPopupWindow(Builder builder) { contentview = LayoutInflater.from(mContext).inflate(builder.contentviewid,null); mPopupWindow = new PopupWindow(contentview,builder.width,builder.height,builder.fouse); //需要跟 setBackGroundDrawable 结合 mPopupWindow.setOutsideTouchable(builder.outsidecancel); mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); mPopupWindow.setAnimationStyle(builder.animstyle); } /** * popup 消失 */ public void dismiss(){ if (mPopupWindow != null){ mPopupWindow.dismiss(); } } /** * 根据id获取view * @param viewid * @return */ public View getItemView(int viewid){ if (mPopupWindow != null){ return this.contentview.findViewById(viewid); } return null; } /** * 根据父布局,显示位置 * @param rootviewid * @param gravity * @param x * @param y * @return */ public CustomPopupWindow showAtLocation(int rootviewid,int gravity,int x,int y){ if (mPopupWindow != null){ View rootview = LayoutInflater.from(mContext).inflate(rootviewid,null); mPopupWindow.showAtLocation(rootview,gravity,x,y); } return this; } /** * 根据id获取view ,并显示在该view的位置 * @param targetviewId * @param gravity * @param offx * @param offy * @return */ public CustomPopupWindow showAsLaction(int targetviewId,int gravity,int offx,int offy){ if (mPopupWindow != null){ View targetview = LayoutInflater.from(mContext).inflate(targetviewId,null); mPopupWindow.showAsDropDown(targetview,gravity,offx,offy); } return this; } /** * 显示在 targetview 的不同位置 * @param targetview * @param gravity * @param offx * @param offy * @return */ public CustomPopupWindow showAsLaction(View targetview,int gravity,int offx,int offy){ if (mPopupWindow != null){ mPopupWindow.showAsDropDown(targetview,gravity,offx,offy); } return this; } /** * 根据id设置焦点监听 * @param viewid * @param listener */ public void setOnFocusListener(int viewid,View.OnFocusChangeListener listener){ View view = getItemView(viewid); view.setOnFocusChangeListener(listener); } /** * builder 类 */ public static class Builder{ private int contentviewid; private int width; private int height; private boolean fouse; private boolean outsidecancel; private int animstyle; public Builder(Context context){ mContext = context; } public Builder setContentView(int contentviewid){ this.contentviewid = contentviewid; return this; } public Builder setwidth(int width){ this.width = width; return this; } public Builder setheight(int height){ this.height = height; return this; } public Builder setFouse(boolean fouse){ this.fouse = fouse; return this; } public Builder setOutSideCancel(boolean outsidecancel){ this.outsidecancel = outsidecancel; return this; } public Builder setAnimationStyle(int animstyle){ this.animstyle = animstyle; return this; } public CustomPopupWindow builder(){ return new CustomPopupWindow(this); } } }
用户评论