溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么封裝PopupWindow

發(fā)布時(shí)間:2021-12-17 13:43:54 來源:億速云 閱讀:145 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“怎么封裝PopupWindow”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么封裝PopupWindow”吧!

概述

PopupWindow 表示一個(gè)彈窗,類似于 AlertDialog,相較 AlertDialog 來說 PopupWindow 使用起來更靈活,可有任意指定要顯示的位置,當(dāng)然能夠靈活的使用必然在某一層面有所犧牲,如 PopupWindow 相較 AlertDialog 沒有默認(rèn)的布局,每次都得專門創(chuàng)建彈窗的布局,這一點(diǎn)來說 AlertDialog 就比較方便了,所以在開發(fā)中沒有最好的解決方案,要根據(jù)具體的需求選擇最合適的解決方案。

常用設(shè)置

PopupWindow 的創(chuàng)建,具體如下:

 //構(gòu)造方法
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 的常用屬性設(shè)置,具體如下:

 //設(shè)置View(必須)
window.setContentView(contentView);
//設(shè)置寬(必須)
window.setWidth(WindowManager.LayoutParams.MATCH_PARENT);
//設(shè)置高(必須)
window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
//設(shè)置背景
window.setBackgroundDrawable(new ColorDrawable(Color.GRAY));
//設(shè)置PopupWindow之外的觸摸事件
window.setOutsideTouchable(true);
//設(shè)置PopupWindow消失的監(jiān)聽器
window.setOnDismissListener(this);
//設(shè)置PopupWindow上的觸摸事件
window.setTouchable(true);
//設(shè)置PopupWindow彈出動(dòng)畫
window.setAnimationStyle(R.style.PopupWindowTranslateTheme);

PopupWindow 的顯示有兩種設(shè)置方式,一種是基于坐標(biāo),另一種是基于某個(gè) View ,具體如下:

//基于坐標(biāo),參數(shù)(當(dāng)前窗口的某個(gè) View,位置,起始坐標(biāo)x, 起始坐標(biāo)y)
void showAtLocation (View parent, int gravity, int x, int y)
//基于某個(gè)View,參數(shù)(附著的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 的主要內(nèi)容基本如上,下面使用原生的 PopupWindow 實(shí)現(xiàn)一個(gè)彈窗,下面是關(guān)鍵代碼,具體如下:

//創(chuàng)建PopupWindow
PopupWindow window = new PopupWindow(this);
//設(shè)置顯示View
window.setContentView(contentView);
//設(shè)置寬高
window.setWidth(WindowManager.LayoutParams.MATCH_PARENT);
window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
//設(shè)置背景
window.setBackgroundDrawable(new ColorDrawable(Color.GRAY));
//設(shè)置PopupWindow之外的觸摸事件
window.setOutsideTouchable(true);
//設(shè)置PopupWindow消失的監(jiān)聽器
window.setOnDismissListener(new PopupWindow.OnDismissListener() {
   @Override
   public void onDismiss() {
       //監(jiān)聽PopupWindow的消失
   }
});
//設(shè)置PopupWindow上的觸摸事件
window.setTouchable(true);
//設(shè)置PopupWindow彈出動(dòng)畫
window.setAnimationStyle(R.style.PopupWindowTranslateTheme);
window.showAtLocation(btnTarget, Gravity.BOTTOM | Gravity.CENTER, 0, 0);

下面是顯示效果,具體如下:

怎么封裝PopupWindow

封裝 PopupWindow

這里對(duì) PopupWindow 的封裝主要是對(duì) PopupWindow 常用擺放位置做進(jìn)一步封裝,使 PopupWindow 的調(diào)用更加靈活、簡潔。

在封裝過程中遇到的問題是不能正確獲取到 PopupWindow 的寬高,正確獲取寬高的方法是先對(duì) PopupWindow 進(jìn)行測(cè)量,然后再獲取其寬高,具體如下:

//獲取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();

對(duì) PopupWindow 的封裝使用了建造者設(shè)計(jì)模式,下面看一下 PopupWindow 的默認(rèn)配置,具體如下:

public Builder(Context context) {
   this.context = context;
   this.popupWindow = new PopupWindow(context);
   //默認(rèn)PopupWindow響應(yīng)觸摸事件
   this.outsideTouchable = true;
   //默認(rèn)響應(yīng)觸摸事件
   this.touchable = true;
   //默認(rèn)背景透明
   this.backgroundDrawable = new ColorDrawable(Color.TRANSPARENT);
   //默認(rèn)寬高為WRAP_CONTENT
   this.width  = WindowManager.LayoutParams.WRAP_CONTENT;
   this.height = WindowManager.LayoutParams.WRAP_CONTENT;
   //默認(rèn)Gravity為Gravity.CENTER
   this.gravity = Gravity.CENTER;
   this.layoutId = -1;
   //默認(rèn)偏移量為0
   this.offsetX = 0;
   this.offsetY = 0;
   //...
}

由于寬高、背景、是否可點(diǎn)擊等相關(guān)屬性已經(jīng)設(shè)置了默認(rèn)值,使用時(shí)根據(jù)自己的需求設(shè)置相關(guān)屬性,如 PopupWindow 的動(dòng)畫等,所以這些設(shè)置肯定是非必須的,那么那些事創(chuàng)建時(shí)必須的呢。

下面是對(duì) 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 是必須需要設(shè)置的,如果沒有設(shè)置相應(yīng)的會(huì)有錯(cuò)誤提示,當(dāng)然在封裝中也對(duì) contentView 和 layoutId 不能同時(shí)使用做了限制和如果使用了兩者的錯(cuò)誤提示。

下面是對(duì)外提供的顯示 PopupWindow 的方法,根據(jù)不同的枚舉類型將 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);
   //獲取目標(biāo)View的坐標(biāo)
   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,只需四行代碼就可以顯示一個(gè)默認(rèn)的 PopupWindow 了,具體如下:

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

由于默認(rèn) PopupWindow 背景是透明的,建議測(cè)試時(shí)設(shè)置背景。

顯示效果:

下面是 PopupWindow 在各個(gè)位置的顯示,具體如下:

怎么封裝PopupWindow

到此,相信大家對(duì)“怎么封裝PopupWindow”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI