拒绝无用功,封装一个通用的PopupWindow
2017-07-10 09:38
393 查看
作者: 夏至,欢迎转载,但请保留这段申明,谢谢
https://juejin.im/post/5961e03e51882568b13c3308
为了避免重复造轮子,我们一般都会封装一个通用的控件,比如这次,项目中需要用到比较多的 popupwindow ,如果需要一个个写,那么依旧会累死人,而且还是无用功,无意义,所以,封装一个通用的,除了让同事看了直刷666之外,自己还省了很多事情。
先上效果图:
一般我们需要实现上面的基本代码,PopupWindow 才能跑起来,然后我们还需要添加动画,监听back键等等,然后,另外一个需要用到的时候,又得重复写,真的让人很绝望,这个时候,封装的思想就从脑袋冒出来了,那么,封装之后,怎么样的呢?如下:
注意上面的 showAtLocation 是在 builder 之后的,表示显示正中间;如果想让它显示在某个 view 的相应位置,也可以使用 showAsLocation() 来实现。
至于为什么在 builder() 的后面呢?因为不太确定在用的时候,是显示在父布局的位置,还是显示在某个控件的相应位置,所以,我把代码封装成下面这样:
当然,你要把它抽出来也可以的;
还有一种常见的情况,我们常用 popupwindow 作用 dialog,那么里面有 button 处理相应的逻辑。那如何想获取 PopupWindow 里面的控件怎么办?为了方便调用,这里我也采用用 id 的形式,所以,调用只要这样即可:
然后就可以用 mMonthPicker 这个 view 搞事情了。
这样就把 contentview 中的控件取出来使用了,只要知道 id 就可以了,是不是方便了很多,都挺简单的,大家自己封装一边就ok全明白了。
- cnotentview ,为了避免每次都来个 layoutinflate ,我们封装成一个 id
- 大小,我们都知道 PopupWindow 没有自己的布局,上面在给了 contentview 之后,大小也要给
- 显示位置,显示就两个函数 ,showAtLocation 和 showAsLocation ,为了方便,我们也写成 id 的方式,当然也可以传入 view
基本就可以了,至于其他附加项,比如动画,点击外部取消,监听back键,或者简单 contentview 控件的事件,都是变动的,所以,用 Builder 的模式构建比较舒服一些。具体就这些了。如果你对 Builder 这中模式不熟悉,可以看我以前文章:
模仿常用框架Builder初始化数据,如何优雅地装逼
* 动画部分:*
menushow :
menudiss :
布局就不贴出来,由于用到自定义控件,贴出来反而不好,大家根据自己的需求,编写即可。
CustomPopupWindow 完整代码:
https://juejin.im/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() .setContext(this) //设置 context .setContentView(R.layout.popup_calendar) //设置布局文件 .setwidth(LinearLayout.LayoutParams.WRAP_CONTENT) //设置宽度,由于我已经在布局写好,这里就用 wrap_content就好了 .setheight(LinearLayout.LayoutParams.WRAP_CONTENT) //设置高度 .setFouse(true) //设置popupwindow 是否可以获取焦点 .setOutSideCancel(true) //设置点击外部取消 .setAnimationStyle(R.style.popup_anim_style) //设置popupwindow动画 .builder() // .showAtLocation(R.layout.activity_calendar, Gravity.CENTER,0,0); //设置popupwindow居中显示
注意上面的 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 完成代码
以下是我现在用的代码,大家可以参考一下,根据自己的需求添加或者删除。* 动画部分:*
<style name="popup_anim_style"> <item name="android:windowEnterAnimation">@anim/menushow</item> <item name="android:windowExitAnimation">@anim/menudiss</item> </style>
menushow :
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fillAfter="true"> <scale android:fromXScale="0" android:fromYScale="0" android:pivotX="50%" android:pivotY="50%" android:toXScale="1.0" android:toYScale="1.0" /> <alpha android:fromAlpha="0" android:toAlpha="1.0" /> </set>
menudiss :
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fillAfter="true"> <scale android:fromXScale="1" android:fromYScale="1" android:pivotX="50%" android:pivotY="50%" android:toXScale="0" android:toYScale="0" /> <alpha android:fromAlpha="1.0" android:toAlpha="0" /> </set>
布局就不贴出来,由于用到自定义控件,贴出来反而不好,大家根据自己的需求,编写即可。
CustomPopupWindow 完整代码:
public class CustomPopupWindow { private PopupWindow mPopupWindow; private View contentview; private Context mContext; public CustomPopupWindow(Builder builder) { mContext = builder.context; 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; private Context context; public Builder setContext(Context context){ this.context = context; return this; } 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); } } }
相关文章推荐
- 拒绝无用功,封装一个通用的 PopupWindow
- 如何封装一个通用的PopupWindow
- 教你如何封装一个通用的PopupWindow
- Android 封装一个通用的PopupWindow
- cocos2d-x封装一个转码的工具解决中文乱码可以直接拖过去用通用跨平台
- Hibernate4 一个baseDao的封装,包含一些通用的增删改查方法
- 封装一个万能的PopupWindow
- 封装一个通用的数据库操作类
- 安卓开发 封装 一个通用 的AlertDialog,亲测好用
- 封装了一个通用的字符串模糊显示的扩展方法
- C 封装一个通用链表 和 一个简单字符串开发库
- 封装一个输入框通用的光标操作接口
- 一个通用简单线程池实现的初步封装(C语言)
- 在Hibernate中的一个对tree树节点查询封装的通用工具类
- 封装一个通用的 okhttp 库
- 使用amaze ui的分页样式封装一个通用的JS分页控件
- 分享一个Android封装精美、好用的菜单型PopupWindow
- 使用redisTemplete简单封装的一个通用操作类
- PHP封装一个通用好用的文件上传处理类
- 封装一个通用的 listview/gridview Adapter