封装一个通用的 PopupWindow

github地址(完整Demo,欢迎下载)
https://github.com/zhouxu88/CustomPopupWindow

在我这次的项目中,用到了很多的PopupWindow,如果一个个写,会累死人不说,而且只是做了大量的重复劳动而已,于是就尝试着动手封装了一下通用的PopupWindow,在此记录一下,顺便与有需要的朋友分享一下。

效果图,上2张

![Uploading pop2_578706.jpg . . .]
pop2.jpg
lizi.jpg

1、通常的使用

一般我们配置一个 PopupWindow通常的套路如下:

 LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View popUpView = inflater.inflate(R.layout.pop_select_num_spec, null, false);
        selectNumSpecPop = new PopupWindow(popUpView, LinearLayoutCompat.LayoutParams.MATCH_PARENT, LinearLayoutCompat.LayoutParams.WRAP_CONTENT);
        selectNumSpecPop.setOutsideTouchable(true);
        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        //设置PopupWindow的动画效果
        selectNumSpecPop.setAnimationStyle(R.style.anim_popUpWindow_bottom);

然后我们还需要添加动画,监听back键等等,并且去findViewById来获取Pop内部的控件,然后,另外一个需要用到的时候,又得重复写,真心很累。

那么,封装之后的Pop如下:

 //初始化PopupWindow
    private void initPop() {
        customPopupWindow = new CustomPopupWindow.Builder(this)
                .setContentView(R.layout.pop_layout)
                .setwidth(LinearLayout.LayoutParams.MATCH_PARENT)
                .setheight(LinearLayout.LayoutParams.WRAP_CONTENT)
                .setAnimationStyle(R.style.anim_popUpWindow_bottom)
                .build();

      //获取pop内部的控件
      TextView cancelTv =  (TextView)customPopupWindow.getItemView(R.id.cancel_tv);

      //显示pop
     customPopupWindow.showAtLocation(showPopBtn, Gravity.BOTTOM, 0, 0);


}

通过Builder的形式来构建Pop,这种链式写法,有没有很熟悉,很简洁。
这里,我是把pop那些需要设置的属性,都封装在了一个自定义的Builder类中,便于自己去定义

2、封装思路

  • cnotentview ,为了避免每次都来个 LayoutInflater.from(mContext).inflate,我们封装成一个 id

  • 大小,就是给PopupWindow 设置宽高

  • 显示位置,显示就两个函数 ,showAtLocation 和 showAsLocation 我们也只需要传入 view即可

基本就可以了,至于其他附加项,比如动画,点击外部取消,监听back键,或者简单 contentview 控件的点击事件,都是变动的。这里主要是用 Builder 的模式构建Pop常用的一些属性。

3、完整的Pop的代码

/**
 * 封装的PopupWindow
 * 
 * 作者: 周旭 on 2017/7/10/0010.
 * 邮箱:374952705@qq.com
 * 博客:http://www.jianshu.com/u/56db5d78044d
 */

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);
        //设置点击外部可以取消,必须和下面这个方法配合才有效
        mPopupWindow.setOutsideTouchable(true);
        //设置一个空背景,设置了这个背景之后,设置点击外部取消才有效
        mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        //Popupwindow可以点击,PopupWindow弹出后,所有的触屏和物理按键都有PopupWindows处理。
        // 其他任何事件的响应都必须发生在PopupWindow消失之后, (home  等系统层面的事件除外)。
        // 比如这样一个PopupWindow出现的时候,按back键首先是让PopupWindow消失,
        // 第二次按才是退出activity,
        mPopupWindow.setFocusable(true);
        mPopupWindow.setAnimationStyle(builder.animStyle); //设置pop显示的动画效果
    }

    /**
     * popup 消失
     */
    public void dismiss() {
        if (mPopupWindow != null && mPopupWindow.isShowing()) {
            mPopupWindow.dismiss();
        }
    }
    

    /**
     * 相对于窗体的显示位置
     *
     * @param view 可以为Activity中的任意一个View(最终的效果一样),
     *                   会通过这个View找到其父Window,也就是Activity的Window。
     * @param gravity 在窗体中的位置,默认为Gravity.NO_GRAVITY
     * @param x 表示距离Window边缘的距离,方向由Gravity决定。
     *          例如:设置了Gravity.TOP,则y表示与Window上边缘的距离;
     *          而如果设置了Gravity.BOTTOM,则y表示与下边缘的距离。
     * @param y
     * @return
     */
    public CustomPopupWindow showAtLocation(View view, int gravity, int x, int y) {
        if (mPopupWindow != null) {
            mPopupWindow.showAtLocation(view, gravity, x, y);
        }
        return this;
    }
    

    /**
     * 显示在anchor控件的正下方,或者相对这个控件的位置
     *
     * @param anchor
     * @param xoff
     * @param yoff
     * @param gravity
     * @return
     */
    public CustomPopupWindow showAsDropDown(View anchor, int xoff, int yoff,int gravity) {
        if (mPopupWindow != null) {
            mPopupWindow.showAsDropDown(anchor, xoff, yoff,gravity);
        }
        return this;
    }

    /**
     * 根据id获取view
     *
     * @param viewId
     * @return
     */
    public View getItemView(int viewId) {
        if (mPopupWindow != null) {
            return contentView.findViewById(viewId);
        }
        return null;
    }

    /**
     * 根据id设置pop内部的控件的点击事件的监听
     *
     * @param viewId
     * @param listener
     */
    public void setOnClickListener(int viewId, View.OnClickListener listener) {
        View view = getItemView(viewId);
        view.setOnClickListener(listener);
    }

    /**
     * builder 类
     */
    public static class Builder {
        private int contentViewId; //pop的布局文件
        private int width; //pop的宽度
        private int height;  //pop的高度
        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 setAnimationStyle(int animStyle) {
            this.animStyle = animStyle;
            return this;
        }

        public CustomPopupWindow build() {
            return new CustomPopupWindow(this);
        }
    }
}

最后,附上一篇关于PopUpWindow常用方法和一些参数的详解
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0702/1627.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容