Popupwindow封装

来源:互联网 发布:淘宝什么技巧 编辑:程序博客网 时间:2024/06/01 08:28
1,  废话不多说,先来介绍一下什么是Popupwindow?

    (1)Google官方文档给出的介绍:popup window 是一个出现在当前Activity顶层的悬浮容器,可以用来展示任意的View。
    (2)常用API:
  1. 构造函数
  2. public PopupWindow(int width, int height)
  3. public PopupWindow(View contentView, int width, int height)
  4. public PopupWindow(View contentView, int width, int height, boolean focusable)
  5. public void setContentView(View contentView)
  6. 设置宽高
  7. // 设置宽,其实构造函数也是调用的这个方法 
  8. public void setWidth(int width)//设置高public void setHeight(int height)
  9. 设置是否获取焦点
  10. public void setFocusable(boolean focusable)
  11. 显示popupwindow
  12. //直接显示在参照View 的左下方public void showAsDropDown(View anchor)// 显示在参照View的左下方,可以通过xoff,yOff,来调节x,y方向的偏移public void showAsDropDown(View anchor, int xoff, int off)public void showAsDropDown(View anchor, int xoff, int yoff, int gravity)//显示在指定位置,相对于整个屏幕的window而言,通过gravity调解显示在左、上、右、下、中. x,y调整两个方向的偏移public void showAtLocation(View parent, int gravity, int x, int y)
    来源: http://www.jianshu.com/p/9304d553aa67
2,为了避免重复造轮子,封装一个通用的popupwindow
    (1)使用方法
  1. CustomPopWindow popWindow = new CustomPopWindow.PopupWindowBuilder(this)
  2. .setView(R.layout.pop_layout1)//显示的布局,还可以通过设置一个View
  3. // .size(600,400) //设置显示的大小,不设置就默认包裹内容
  4. .setFocusable(true)//是否获取焦点,默认为ture
  5. .setOutsideTouchable(true)//是否PopupWindow 以外触摸dissmiss
  6. .create()//创建PopupWindow
  7. .showAsDropDown(mButton1,0,10);//显示PopupWindow
    (2)展示一个PopupWindow 弹窗菜单(像手机QQ,微信的顶部菜单)
  1. View contentView = LayoutInflater.from(this).inflate(R.layout.pop_menu,null);
  2. //处理popWindow 显示内容
  3. handleLogic(contentView);
  4. //创建并显示popWindow
  5. mCustomPopWindow= new CustomPopWindow.PopupWindowBuilder(this)
  6. .setView(contentView)
  7. .create()
  8. .showAsDropDown(mButton3,0,20);
    如果popupwindow需要在代码中设置点击事件,可以先获取这个view处理一些事件逻辑,再交给CustomPopupwindow创建显示。
    (3)在popupwindow中展示listview
        
private void showPopListView(){        View contentView = LayoutInflater.from(this).inflate(R.layout.pop_list,null);        //处理popWindow 显示内容        handleListView(contentView);        //创建并显示popWindow        mListPopWindow= new CustomPopWindow.PopupWindowBuilder(this)                .setView(contentView)                .size(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)//显示大小                .create()                .showAsDropDown(mButton4,0,20);    }
 private void handleListView(View contentView){        RecyclerView recyclerView = (RecyclerView) contentView.findViewById(R.id.recyclerView);        LinearLayoutManager manager = new LinearLayoutManager(this);        manager.setOrientation(LinearLayoutManager.VERTICAL);        recyclerView.setLayoutManager(manager);        MyAdapter adapter = new MyAdapter();        adapter.setData(mockData());        recyclerView.setAdapter(adapter);        adapter.notifyDataSetChanged();    }

    最后放上CustomPopupwindow源码
  1. /**
  2. *
  3. * 自定义PopWindow类,封装了PopWindow的一些常用属性,用Builder模式支持链式调用
  4. * Created by li on 17/7/8.
  5. */
  6. public class CustomPopWindow implements PopupWindow.OnDismissListener{
  7. private static final String TAG = "CustomPopWindow";
  8. private static final float DEFAULT_ALPHA = 0.7f;
  9. private Context mContext;
  10. private int mWidth;
  11. private int mHeight;
  12. private boolean mIsFocusable = true;
  13. private boolean mIsOutside = true;
  14. private int mResLayoutId = -1;
  15. private View mContentView;
  16. private PopupWindow mPopupWindow;
  17. private int mAnimationStyle = -1;
  18. private boolean mClippEnable = true;//default is true
  19. private boolean mIgnoreCheekPress = false;
  20. private int mInputMode = -1;
  21. private PopupWindow.OnDismissListener mOnDismissListener;
  22. private int mSoftInputMode = -1;
  23. private boolean mTouchable = true;//default is ture
  24. private View.OnTouchListener mOnTouchListener;
  25. private Window mWindow;//当前Activity 的窗口
  26. /**
  27. * 弹出PopWindow 背景是否变暗,默认不会变暗。
  28. */
  29. private boolean mIsBackgroundDark = false;
  30. private float mBackgroundDrakValue = 0;// 背景变暗的值,0 - 1
  31. /**
  32. * 设置是否允许点击 PopupWindow之外的地方,关闭PopupWindow
  33. */
  34. private boolean enableOutsideTouchDisMiss = true;// 默认点击pop之外的地方可以关闭
  35. private CustomPopWindow(Context context){
  36. mContext = context;
  37. }
  38. public int getWidth() {
  39. return mWidth;
  40. }
  41. public int getHeight() {
  42. return mHeight;
  43. }
  44. /**
  45. *
  46. * @param anchor
  47. * @param xOff
  48. * @param yOff
  49. * @return
  50. */
  51. public CustomPopWindow showAsDropDown(View anchor, int xOff, int yOff){
  52. if(mPopupWindow!=null){
  53. mPopupWindow.showAsDropDown(anchor,xOff,yOff);
  54. }
  55. return this;
  56. }
  57. public CustomPopWindow showAsDropDown(View anchor){
  58. if(mPopupWindow!=null){
  59. mPopupWindow.showAsDropDown(anchor);
  60. }
  61. return this;
  62. }
  63. @RequiresApi(api = Build.VERSION_CODES.KITKAT)
  64. public CustomPopWindow showAsDropDown(View anchor, int xOff, int yOff, int gravity){
  65. if(mPopupWindow!=null){
  66. mPopupWindow.showAsDropDown(anchor,xOff,yOff,gravity);
  67. }
  68. return this;
  69. }
  70. /**
  71. * 相对于父控件的位置(通过设置Gravity.CENTER,下方Gravity.BOTTOM等 ),可以设置具体位置坐标
  72. * @param parent 父控件
  73. * @param gravity
  74. * @param x the popup's x location offset
  75. * @param y the popup's y location offset
  76. * @return
  77. */
  78. public CustomPopWindow showAtLocation(View parent, int gravity, int x, int y){
  79. if(mPopupWindow!=null){
  80. mPopupWindow.showAtLocation(parent,gravity,x,y);
  81. }
  82. return this;
  83. }
  84. /**
  85. * 添加一些属性设置
  86. * @param popupWindow
  87. */
  88. private void apply(PopupWindow popupWindow){
  89. popupWindow.setClippingEnabled(mClippEnable);
  90. if(mIgnoreCheekPress){
  91. popupWindow.setIgnoreCheekPress();
  92. }
  93. if(mInputMode!=-1){
  94. popupWindow.setInputMethodMode(mInputMode);
  95. }
  96. if(mSoftInputMode!=-1){
  97. popupWindow.setSoftInputMode(mSoftInputMode);
  98. }
  99. if(mOnDismissListener!=null){
  100. popupWindow.setOnDismissListener(mOnDismissListener);
  101. }
  102. if(mOnTouchListener!=null){
  103. popupWindow.setTouchInterceptor(mOnTouchListener);
  104. }
  105. popupWindow.setTouchable(mTouchable);
  106. }
  107. private PopupWindow build(){
  108. if(mContentView == null){
  109. mContentView = LayoutInflater.from(mContext).inflate(mResLayoutId,null);
  110. }
  111. // 2017.3.17 add
  112. // 获取当前Activity的window
  113. Activity activity = (Activity) mContentView.getContext();
  114. if(activity!=null && mIsBackgroundDark){
  115. //如果设置的值在0 - 1的范围内,则用设置的值,否则用默认值
  116. final float alpha = (mBackgroundDrakValue > 0 && mBackgroundDrakValue < 1) ? mBackgroundDrakValue : DEFAULT_ALPHA;
  117. mWindow = activity.getWindow();
  118. WindowManager.LayoutParams params = mWindow.getAttributes();
  119. params.alpha = alpha;
  120. mWindow.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
  121. mWindow.setAttributes(params);
  122. }
  123. if(mWidth != 0 && mHeight!=0 ){
  124. mPopupWindow = new PopupWindow(mContentView,mWidth,mHeight);
  125. }else{
  126. mPopupWindow = new PopupWindow(mContentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  127. }
  128. if(mAnimationStyle!=-1){
  129. mPopupWindow.setAnimationStyle(mAnimationStyle);
  130. }
  131. apply(mPopupWindow);//设置一些属性
  132. if(mWidth == 0 || mHeight == 0){
  133. mPopupWindow.getContentView().measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
  134. //如果外面没有设置宽高的情况下,计算宽高并赋值
  135. mWidth = mPopupWindow.getContentView().getMeasuredWidth();
  136. mHeight = mPopupWindow.getContentView().getMeasuredHeight();
  137. }
  138. // 添加dissmiss 监听
  139. mPopupWindow.setOnDismissListener(this);
  140. //2017.6.27 add:fix 设置 setOutsideTouchable(false)点击外部取消的bug.
  141. // 判断是否点击PopupWindow之外的地方关闭 popWindow
  142. if(!enableOutsideTouchDisMiss){
  143. //注意这三个属性必须同时设置,不然不能disMiss,以下三行代码在Android 4.4 上是可以,然后在Android 6.0以上,下面的三行代码就不起作用了,就得用下面的方法
  144. mPopupWindow.setFocusable(true);
  145. mPopupWindow.setOutsideTouchable(false);
  146. mPopupWindow.setBackgroundDrawable(null);
  147. //注意下面这三个是contentView 不是PopupWindow
  148. mPopupWindow.getContentView().setFocusable(true);
  149. mPopupWindow.getContentView().setFocusableInTouchMode(true);
  150. mPopupWindow.getContentView().setOnKeyListener(new View.OnKeyListener() {
  151. @Override
  152. public boolean onKey(View v, int keyCode, KeyEvent event) {
  153. if (keyCode == KeyEvent.KEYCODE_BACK) {
  154. mPopupWindow.dismiss();
  155. return true;
  156. }
  157. return false;
  158. }
  159. });
  160. //在Android 6.0以上 ,只能通过拦截事件来解决
  161. mPopupWindow.setTouchInterceptor(new View.OnTouchListener() {
  162. @Override
  163. public boolean onTouch(View v, MotionEvent event) {
  164. final int x = (int) event.getX();
  165. final int y = (int) event.getY();
  166. if ((event.getAction() == MotionEvent.ACTION_DOWN)
  167. && ((x < 0) || (x >= mWidth) || (y < 0) || (y >= mHeight))) {
  168. Log.e(TAG,"out side ");
  169. Log.e(TAG,"width:"+mPopupWindow.getWidth()+"height:"+mPopupWindow.getHeight()+" x:"+x+" y :"+y);
  170. return true;
  171. } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
  172. Log.e(TAG,"out side ...");
  173. return true;
  174. }
  175. return false;
  176. }
  177. });
  178. }else{
  179. mPopupWindow.setFocusable(mIsFocusable);
  180. mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
  181. mPopupWindow.setOutsideTouchable(mIsOutside);
  182. }
  183. // update
  184. mPopupWindow.update();
  185. return mPopupWindow;
  186. }
  187. @Override
  188. public void onDismiss() {
  189. dissmiss();
  190. }
  191. /**
  192. * 关闭popWindow
  193. */
  194. public void dissmiss(){
  195. if(mOnDismissListener!=null){
  196. mOnDismissListener.onDismiss();
  197. }
  198. //如果设置了背景变暗,那么在dissmiss的时候需要还原
  199. if(mWindow!=null){
  200. WindowManager.LayoutParams params = mWindow.getAttributes();
  201. params.alpha = 1.0f;
  202. mWindow.setAttributes(params);
  203. }
  204. if(mPopupWindow!=null && mPopupWindow.isShowing()){
  205. mPopupWindow.dismiss();
  206. }
  207. }
  208. public PopupWindow getPopupWindow() {
  209. return mPopupWindow;
  210. }
  211. public static class PopupWindowBuilder{
  212. private CustomPopWindow mCustomPopWindow;
  213. public PopupWindowBuilder(Context context){
  214. mCustomPopWindow = new CustomPopWindow(context);
  215. }
  216. public PopupWindowBuilder size(int width,int height){
  217. mCustomPopWindow.mWidth = width;
  218. mCustomPopWindow.mHeight = height;
  219. return this;
  220. }
  221. public PopupWindowBuilder setFocusable(boolean focusable){
  222. mCustomPopWindow.mIsFocusable = focusable;
  223. return this;
  224. }
  225. public PopupWindowBuilder setView(int resLayoutId){
  226. mCustomPopWindow.mResLayoutId = resLayoutId;
  227. mCustomPopWindow.mContentView = null;
  228. return this;
  229. }
  230. public PopupWindowBuilder setView(View view){
  231. mCustomPopWindow.mContentView = view;
  232. mCustomPopWindow.mResLayoutId = -1;
  233. return this;
  234. }
  235. public PopupWindowBuilder setOutsideTouchable(boolean outsideTouchable){
  236. mCustomPopWindow.mIsOutside = outsideTouchable;
  237. return this;
  238. }
  239. /**
  240. * 设置弹窗动画
  241. * @param animationStyle
  242. * @return
  243. */
  244. public PopupWindowBuilder setAnimationStyle(int animationStyle){
  245. mCustomPopWindow.mAnimationStyle = animationStyle;
  246. return this;
  247. }
  248. public PopupWindowBuilder setClippingEnable(boolean enable){
  249. mCustomPopWindow.mClippEnable =enable;
  250. return this;
  251. }
  252. public PopupWindowBuilder setIgnoreCheekPress(boolean ignoreCheekPress){
  253. mCustomPopWindow.mIgnoreCheekPress = ignoreCheekPress;
  254. return this;
  255. }
  256. public PopupWindowBuilder setInputMethodMode(int mode){
  257. mCustomPopWindow.mInputMode = mode;
  258. return this;
  259. }
  260. public PopupWindowBuilder setOnDissmissListener(PopupWindow.OnDismissListener onDissmissListener){
  261. mCustomPopWindow.mOnDismissListener = onDissmissListener;
  262. return this;
  263. }
  264. public PopupWindowBuilder setSoftInputMode(int softInputMode){
  265. mCustomPopWindow.mSoftInputMode = softInputMode;
  266. return this;
  267. }
  268. public PopupWindowBuilder setTouchable(boolean touchable){
  269. mCustomPopWindow.mTouchable = touchable;
  270. return this;
  271. }
  272. public PopupWindowBuilder setTouchIntercepter(View.OnTouchListener touchIntercepter){
  273. mCustomPopWindow.mOnTouchListener = touchIntercepter;
  274. return this;
  275. }
  276. /**
  277. * 设置背景变暗是否可用
  278. * @param isDark
  279. * @return
  280. */
  281. public PopupWindowBuilder enableBackgroundDark(boolean isDark){
  282. mCustomPopWindow.mIsBackgroundDark = isDark;
  283. return this;
  284. }
  285. /**
  286. * 设置背景变暗的值
  287. * @param darkValue
  288. * @return
  289. */
  290. public PopupWindowBuilder setBgDarkAlpha(float darkValue){
  291. mCustomPopWindow.mBackgroundDrakValue = darkValue;
  292. return this;
  293. }
  294. /**
  295. * 设置是否允许点击 PopupWindow之外的地方,关闭PopupWindow
  296. * @param disMiss
  297. * @return
  298. */
  299. public PopupWindowBuilder enableOutsideTouchableDissmiss(boolean disMiss){
  300. mCustomPopWindow.enableOutsideTouchDisMiss = disMiss;
  301. return this;
  302. }
  303. public CustomPopWindow create(){
  304. //构建PopWindow
  305. mCustomPopWindow.build();
  306. return mCustomPopWindow;
  307. }
  308. }
  309. }
参考:http://www.jianshu.com/p/9304d553aa67
了解背景控制和设置动画:http://www.jianshu.com/p/46d13fe78099