温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么封装PopupWindow

发布时间:2021-12-17 13:43:54 阅读:160 作者:iii 栏目:开发技术
Windows服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

本篇内容主要讲解“怎么封装PopupWindow”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么封装PopupWindow”吧!

概述

PopupWindow 表示一个弹窗,类似于 AlertDialog,相较 AlertDialog 来说 PopupWindow 使用起来更灵活,可有任意指定要显示的位置,当然能够灵活的使用必然在某一层面有所牺牲,如 PopupWindow 相较 AlertDialog 没有默认的布局,每次都得专门创建弹窗的布局,这一点来说 AlertDialog 就比较方便了,所以在开发中没有最好的解决方案,要根据具体的需求选择最合适的解决方案。

常用设置

PopupWindow 的创建,具体如下:

 //构造方法 public PopupWindow (Context context)   public PopupWindow(View contentView)   public PopupWindow(View contentView, 
int width, 
int height)   public PopupWindow(View contentView, 
int width, 
int height, boolean focusable) 

PopupWindow 的常用属性设置,具体如下:

 //设置View(必须) window.setContentView(contentView); //设置宽(必须) window.setWidth(WindowManager.LayoutParams.MATCH_PARENT); //设置高(必须) window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT); //设置背景 window.setBackgroundDrawable(new ColorDrawable(Color.GRAY)); //设置PopupWindow之外的触摸事件 window.setOutsideTouchable(true); //设置PopupWindow消失的监听器 window.setOnDismissListener(this); //设置PopupWindow上的触摸事件 window.setTouchable(true); //设置PopupWindow弹出动画 window.setAnimationStyle(R.style.PopupWindowTranslateTheme);

PopupWindow 的显示有两种设置方式,一种是基于坐标,另一种是基于某个 View ,具体如下:

//基于坐标,参数(当前窗口的某个 View,位置,起始坐标x, 起始坐标y)void showAtLocation (View parent, 
int gravity, 
int x, 
int y)//基于某个View,参数(附着的View,x 方向的偏移量,y 方向的偏移量)void showAsDropDown (View anchor, 
int xoff, 
int yoff, 
int gravity) 
void showAsDropDown (View anchor, 
int xoff, 
int yoff)void showAsDropDown (View anchor) 
基本使用

PopupWindow 的主要内容基本如上,下面使用原生的 PopupWindow 实现一个弹窗,下面是关键代码,具体如下:

//创建PopupWindowPopupWindow 
window = 
new PopupWindow(this);//设置显示Viewwindow.setContentView(contentView);//设置宽高window.setWidth(WindowManager.LayoutParams.MATCH_PARENT);window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);//设置背景window.setBackgroundDrawable(new ColorDrawable(Color.GRAY));//设置PopupWindow之外的触摸事件window.setOutsideTouchable(true);//设置PopupWindow消失的监听器window.setOnDismissListener(new PopupWindow.OnDismissListener() {    @Override    public void onDismiss() {        //监听PopupWindow的消失    }});//设置PopupWindow上的触摸事件window.setTouchable(true);//设置PopupWindow弹出动画window.setAnimationStyle(R.style.PopupWindowTranslateTheme);window.showAtLocation(btnTarget, Gravity.BOTTOM | Gravity.CENTER, 
0, 
0);

下面是显示效果,具体如下:

怎么封装PopupWindow

封装 PopupWindow

这里对 PopupWindow 的封装主要是对 PopupWindow 常用摆放位置做进一步封装,使 PopupWindow 的调用更加灵活、简洁。

在封装过程中遇到的问题是不能正确获取到 PopupWindow 的宽高,正确获取宽高的方法是先对 PopupWindow 进行测量,然后再获取其宽高,具体如下:

//获取PopupWindow的宽高mPopupWindow.getContentView().measure(    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));int popupWidth = mPopupWindow.getContentView().getMeasuredWidth();int popupHeight = mPopupWindow.getContentView().getMeasuredHeight();

对 PopupWindow 的封装使用了建造者设计模式,下面看一下 PopupWindow 的默认配置,具体如下:

public Builder(Context context) {    this.context = context;    this.popupWindow = 
new PopupWindow(context);    //默认PopupWindow响应触摸事件    this.outsideTouchable = 
true;    //默认响应触摸事件    this.touchable = 
true;    //默认背景透明    this.backgroundDrawable = 
new ColorDrawable(Color.TRANSPARENT);    //默认宽高为WRAP_CONTENT    this.width  = WindowManager.LayoutParams.WRAP_CONTENT;    this.height = WindowManager.LayoutParams.WRAP_CONTENT;    //默认Gravity为Gravity.CENTER    this.gravity = Gravity.CENTER;    this.layoutId = 
-1;    //默认偏移量为0    this.offsetX = 
0;    this.offsetY = 
0;    //...}

由于宽高、背景、是否可点击等相关属性已经设置了默认值,使用时根据自己的需求设置相关属性,如 PopupWindow 的动画等,所以这些设置肯定是非必须的,那么那些事创建时必须的呢。

下面是对 PopupWindow 封装类 MPopupWindow 的初始化,具体如下:

private void setPopupWindowConfig(MPopupWindow 
window) {        if (contentView != 
null && layoutId != 
-1){            throw new MException("setContentView and setLayoutId can't be used together.", 
"0");        }else if (contentView == 
null && layoutId == 
-1){            throw new MException("contentView or layoutId can't be null.", 
"1");        }        if (context == 
null) {            throw new MException("context can't be null.", 
"2");        } 
else {            window.mContext = 
this.context;        }        window.mWidth  = 
this.width;        window.mHeight = 
this.height;        window.mView = 
this.contentView;        window.mLayoutId = layoutId;        window.mPopupWindow = 
this.popupWindow;        window.mOutsideTouchable   = 
this.outsideTouchable;        window.mBackgroundDrawable = 
this.backgroundDrawable;        window.mOnDismissListener  = 
this.onDismissListener;        window.mAnimationStyle = 
this.animationStyle;        window.mTouchable = 
this.touchable;        window.mOffsetX = 
this.offsetX;        window.mOffsetY = 
this.offsetY;        window.mGravity = 
this.gravity;    }}

显然,这里可以看出 context 和 contentView 或 layoutId 是必须需要设置的,如果没有设置相应的会有错误提示,当然在封装中也对 contentView 和 layoutId 不能同时使用做了限制和如果使用了两者的错误提示。

下面是对外提供的显示 PopupWindow 的方法,根据不同的枚举类型将 PopupWindow 显示在不同的位置,具体如下:

public void showPopupWindow(View v, LocationType 
type) {    if (mView!=null){        mPopupWindow.setContentView(mView);    }else if (mLayoutId != -1){        View contentView = LayoutInflater.from(mContext).inflate(mLayoutId, null);        mPopupWindow.setContentView(contentView);    }    mPopupWindow.setWidth(mWidth);    mPopupWindow.setHeight(mHeight);    mPopupWindow.setBackgroundDrawable(mBackgroundDrawable);    mPopupWindow.setOutsideTouchable(mOutsideTouchable);    mPopupWindow.setOnDismissListener(mOnDismissListener);    mPopupWindow.setAnimationStyle(mAnimationStyle);    mPopupWindow.setTouchable(mTouchable);    //获取目标View的坐标    int[] locations = new int[2];    v.getLocationOnScreen(locations);    int left = locations[0];    int top  =  locations[1];    //获取PopupWindow的宽高    mPopupWindow.getContentView().measure(            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));    int popupWidth = mPopupWindow.getContentView().getMeasuredWidth();    int popupHeight = mPopupWindow.getContentView().getMeasuredHeight();    switch (type) {        case TOP_LEFT:            mPopupWindow.showAtLocation(v,Gravity.NO_GRAVITY,left - popupWidth + mOffsetX,top - popupHeight + mOffsetY);            break;        case TOP_CENTER:            int offsetX = (v.getWidth() - popupWidth) / 2;            mPopupWindow.showAtLocation(v,Gravity.NO_GRAVITY,left + offsetX + mOffsetX,top - popupHeight + mOffsetY);            break;        case TOP_RIGHT:            mPopupWindow.showAtLocation(v,Gravity.NO_GRAVITY,left + v.getWidth() + mOffsetX,top - popupHeight + mOffsetY);            break;        case BOTTOM_LEFT:            mPopupWindow.showAsDropDown(v, -popupWidth + mOffsetX,mOffsetY);            break;        case BOTTOM_CENTER:            int offsetX1 = (v.getWidth() - popupWidth) / 2;            mPopupWindow.showAsDropDown(v,offsetX1 + mOffsetX,mOffsetY);            break;        case BOTTOM_RIGHT:            mPopupWindow.showAsDropDown(v, v.getWidth() + mOffsetX,mOffsetY);            break;        case LEFT_TOP:            mPopupWindow.showAtLocation(v, Gravity.NO_GRAVITY, left - popupWidth + mOffsetX, top - popupHeight + mOffsetY);            break;        case LEFT_BOTTOM:            mPopupWindow.showAtLocation(v, Gravity.NO_GRAVITY, left - popupWidth + mOffsetX, top + v.getHeight() + mOffsetY);            break;        case LEFT_CENTER:            int offsetY = (v.getHeight() - popupHeight) / 2;            mPopupWindow.showAtLocation(v, Gravity.NO_GRAVITY,left - popupWidth + mOffsetX,top + offsetY + mOffsetY);            break;        case RIGHT_TOP:            mPopupWindow.showAtLocation(v, Gravity.NO_GRAVITY, left + v.getWidth() + mOffsetX,top - popupHeight + mOffsetY);            break;        case RIGHT_BOTTOM:            mPopupWindow.showAtLocation(v, Gravity.NO_GRAVITY, left + v.getWidth() + mOffsetX,top + v.getHeight() + mOffsetY);            break;        case RIGHT_CENTER:            int offsetY1 = (v.getHeight() - popupHeight) / 2;            mPopupWindow.showAtLocation(v, Gravity.NO_GRAVITY,left + v.getWidth() + mOffsetX,top + offsetY1 + mOffsetY);            break;        case FROM_BOTTOM:            mPopupWindow.showAtLocation(v,mGravity,mOffsetX,mOffsetY);            break;    }}
使用封装后的PopupWindow

下面是使用封装后的 PopupWindow,只需四行代码就可以显示一个默认的 PopupWindow 了,具体如下:

private void showPopupWindow(MPopupWindow.LocationType 
type) {    MPopupWindow popupWindow = 
new MPopupWindow            .Builder(this)            .setLayoutId(R.layout.popup_window_layout)            .build();    popupWindow.showPopupWindow(btnTarget, 
type);}

由于默认 PopupWindow 背景是透明的,建议测试时设置背景。

显示效果:

下面是 PopupWindow 在各个位置的显示,具体如下:

怎么封装PopupWindow

到此,相信大家对“怎么封装PopupWindow”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:http://blog.itpub.net/69923331/viewspace-2703721/

AI

开发者交流群×