Android 封装一个通用的PopupWindow
*本篇文章已授權(quán)微信公眾號(hào) guolin_blog (郭霖)獨(dú)家發(fā)布
先上效果圖:
完整代碼地址已上傳Github:CommonPopupWindow
PopupWindow這個(gè)類用來(lái)實(shí)現(xiàn)一個(gè)彈出框,可以使用任意布局的View作為其內(nèi)容,這個(gè)彈出框是懸浮在當(dāng)前activity之上的。
一般PopupWindow的使用:
//準(zhǔn)備PopupWindow的布局View View popupView = LayoutInflater.from(this).inflate(R.layout.popup, null); //初始化一個(gè)PopupWindow,width和height都是WRAP_CONTENT PopupWindow popupWindow = new PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); //設(shè)置PopupWindow的視圖內(nèi)容 popupWindow.setContentView(popupView); //點(diǎn)擊空白區(qū)域PopupWindow消失,這里必須先設(shè)置setBackgroundDrawable,否則點(diǎn)擊無(wú)反應(yīng) popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000)); popupWindow.setOutsideTouchable(true); //設(shè)置PopupWindow動(dòng)畫 popupWindow.setAnimationStyle(R.style.AnimDown); //設(shè)置是否允許PopupWindow的范圍超過(guò)屏幕范圍 popupWindow.setClippingEnabled(true); //設(shè)置PopupWindow消失監(jiān)聽 popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {@Overridepublic void onDismiss() {}}); //PopupWindow在targetView下方彈出 popupWindow.showAsDropDown(targetView); 復(fù)制代碼上面就是PopupWindow通常需要設(shè)置的各個(gè)方法,不難,但是稍微有點(diǎn)繁瑣,有些是可以復(fù)用的,所以封裝了一個(gè)通用的CommonPopupWindow:
CommonPopupWindow繼承自PopupWindow,擁有PopupWindow的各個(gè)屬性方法,使用類似建造者模式,和AlertDialog的使用方式差不多,CommonPopupWindow使用舉例:
CommonPopupWindow popupWindow = new CommonPopupWindow.Builder(this)//設(shè)置PopupWindow布局.setView(R.layout.popup_down) //設(shè)置寬高.setWidthAndHeight(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)//設(shè)置動(dòng)畫.setAnimationStyle(R.style.AnimDown)//設(shè)置背景顏色,取值范圍0.0f-1.0f 值越小越暗 1.0f為透明.setBackGroundLevel(0.5f)//設(shè)置PopupWindow里的子View及點(diǎn)擊事件 .setViewOnclickListener(new CommonPopupWindow.ViewInterface() {@Overridepublic void getChildView(View view, int layoutResId) {TextView tv_child = (TextView) view.findViewById(R.id.tv_child);tv_child.setText("我是子View");}})//設(shè)置外部是否可點(diǎn)擊 默認(rèn)是true.setOutsideTouchable(true)//開始構(gòu)建.create(); //彈出PopupWindow popupWindow.showAsDropDown(view); 復(fù)制代碼- CommonPopupWindow 設(shè)置背景:
這里使用的是WindowManager.LayoutParams.alpha屬性,看下官網(wǎng)解釋:**An alpha value to apply to this entire window. An alpha of 1.0 means fully opaque and 0.0 means fully transparent .**alpha 值適用于整個(gè)Window,α為1.0時(shí)表示完全不透明而0.0表示完全透明,默認(rèn)是1.0,當(dāng)PopupWindow彈出時(shí)通過(guò)設(shè)置alpha在(0.0,1.0)之間設(shè)置灰色背景,當(dāng)PopupWindow消失時(shí)恢復(fù)默認(rèn)值。
private void setBackGroundLevel(float level) {mWindow = ((Activity) context).getWindow();WindowManager.LayoutParams params = mWindow.getAttributes();params.alpha = level;mWindow.setAttributes(params);} 復(fù)制代碼- 計(jì)算CommonPopupWindow 寬高:
注:在測(cè)量寬高時(shí)遇到一種情況,如圖所示:
如果設(shè)置TextView 的 android:layout_width="wrap_content",那么測(cè)量不出TextView 準(zhǔn)確的height,當(dāng)設(shè)置width為某個(gè)確定值時(shí),也能得到準(zhǔn)確的height了。
- CommonPopupWindow 設(shè)置動(dòng)畫:
如設(shè)置向右動(dòng)畫:
.setAnimationStyle(R.style.AnimHorizontal); 復(fù)制代碼在style.xml文件中設(shè)置:
<style name="AnimHorizontal" parent="@android:style/Animation"><item name="android:windowEnterAnimation">@anim/push_scale_left_in</item><item name="android:windowExitAnimation">@anim/push_scale_left_out</item></style> 復(fù)制代碼android:windowEnterAnimation、android:windowExitAnimation分別為Popupwindow彈出和消失動(dòng)畫
進(jìn)入動(dòng)畫為anim目錄下的 push_scale_left_in.xml:
<scale xmlns:android="http://schemas.android.com/apk/res/android"android:duration="200"android:fromXScale="0.0"android:fromYScale="1.0"android:interpolator="@android:anim/accelerate_decelerate_interpolator"android:toXScale="1.0"android:toYScale="1.0" /> 復(fù)制代碼消失動(dòng)畫為 push_scale_left_out.xml:
<scale xmlns:android="http://schemas.android.com/apk/res/android"android:duration="200"android:fromXScale="1.0"android:fromYScale="1.0"android:interpolator="@android:anim/accelerate_decelerate_interpolator"android:toXScale="0.0"android:toYScale="1.0" /> 復(fù)制代碼- CommonPopupWindow 彈出:
因?yàn)镃ommonPopupWindow繼承自PopupWindow,所以可以直接使用PopupWindow中的彈出方法,常用的下面三種:
public void showAsDropDown(View anchor)public void showAsDropDown(View anchor, int xoff, int yoff)public void showAtLocation(View parent, int gravity, int x, int y) 復(fù)制代碼其中,showAsDropDown是顯示在參照物anchor的周圍,xoff、yoff分別是X軸、Y軸的偏移量,如果不設(shè)置xoff、yoff,默認(rèn)是顯示在anchor的下方;showAtLocation是設(shè)置在父控件的位置,如設(shè)置Gravity.BOTTOM表示在父控件底部彈出,xoff、yoff也是X軸、Y軸的偏移量。
如上面向右彈出例子,分別使用showAsDropDown和showAtLocation來(lái)實(shí)現(xiàn):
showAsDropDown:
popupWindow.showAsDropDown(view, view.getWidth(), -view.getHeight()); 復(fù)制代碼showAsDropDown默認(rèn)展示在button的下面,通過(guò)改變X軸和Y軸的偏移量(X軸向右偏移button的寬度,Y軸向上偏移button的高度),實(shí)現(xiàn)在Button右邊彈出。
showAtLocation:
int[] positions = new int[2]; view.getLocationOnScreen(positions); popupWindow.showAtLocation(findViewById(android.R.id.content), Gravity.START| Gravity.TOP , positions[0] + view.getWidth(), positions[1]); 復(fù)制代碼使用了View的getLocationOnScreen方法來(lái)獲得View在屏幕中的坐標(biāo)位置,傳入的參數(shù)必須是一個(gè)有2個(gè)整數(shù)的數(shù)組,分別代表View的X、Y坐標(biāo),即是View的左上角的坐標(biāo),這里的View是Button,知道了Button左上角的坐標(biāo),就可以得到要展示的PopupWindow的左上角的坐標(biāo)為(positions[0] + view.getWidth(), positions[1]),從而實(shí)現(xiàn)在Button右邊彈出。
最后貼一下代碼 CommonPopupWindow.java:
public class CommonPopupWindow extends PopupWindow {final PopupController controller;@Overridepublic int getWidth() {return controller.mPopupView.getMeasuredWidth();}@Overridepublic int getHeight() {return controller.mPopupView.getMeasuredHeight();}public interface ViewInterface {void getChildView(View view, int layoutResId);}private CommonPopupWindow(Context context) {controller = new PopupController(context, this);}@Overridepublic void dismiss() {super.dismiss();controller.setBackGroundLevel(1.0f);}public static class Builder {private final PopupController.PopupParams params;private ViewInterface listener;public Builder(Context context) {params = new PopupController.PopupParams(context);}/*** @param layoutResId 設(shè)置PopupWindow 布局ID* @return Builder*/public Builder setView(int layoutResId) {params.mView = null;params.layoutResId = layoutResId;return this;}/*** @param view 設(shè)置PopupWindow布局* @return Builder*/public Builder setView(View view) {params.mView = view;params.layoutResId = 0;return this;}/*** 設(shè)置子View** @param listener ViewInterface* @return Builder*/public Builder setViewOnclickListener(ViewInterface listener) {this.listener = listener;return this;}/*** 設(shè)置寬度和高度 如果不設(shè)置 默認(rèn)是wrap_content** @param width 寬* @return Builder*/public Builder setWidthAndHeight(int width, int height) {params.mWidth = width;params.mHeight = height;return this;}/*** 設(shè)置背景灰色程度** @param level 0.0f-1.0f* @return Builder*/public Builder setBackGroundLevel(float level) {params.isShowBg = true;params.bg_level = level;return this;}/*** 是否可點(diǎn)擊Outside消失** @param touchable 是否可點(diǎn)擊* @return Builder*/public Builder setOutsideTouchable(boolean touchable) {params.isTouchable = touchable;return this;}/*** 設(shè)置動(dòng)畫** @return Builder*/public Builder setAnimationStyle(int animationStyle) {params.isShowAnim = true;params.animationStyle = animationStyle;return this;}public CommonPopupWindow create() {final CommonPopupWindow popupWindow = new CommonPopupWindow(params.mContext);params.apply(popupWindow.controller);if (listener != null && params.layoutResId != 0) {listener.getChildView(popupWindow.controller.mPopupView, params.layoutResId);}CommonUtil.measureWidthAndHeight(popupWindow.controller.mPopupView);return popupWindow;}} } 復(fù)制代碼PopupController.java:
class PopupController {private int layoutResId;//布局idprivate Context context;private PopupWindow popupWindow;View mPopupView;//彈窗布局Viewprivate View mView;private Window mWindow;PopupController(Context context, PopupWindow popupWindow) {this.context = context;this.popupWindow = popupWindow;}public void setView(int layoutResId) {mView = null;this.layoutResId = layoutResId;installContent();}public void setView(View view) {mView = view;this.layoutResId = 0;installContent();}private void installContent() {if (layoutResId != 0) {mPopupView = LayoutInflater.from(context).inflate(layoutResId, null);} else if (mView != null) {mPopupView = mView;}popupWindow.setContentView(mPopupView);}/*** 設(shè)置寬度** @param width 寬* @param height 高*/private void setWidthAndHeight(int width, int height) {if (width == 0 || height == 0) {//如果沒設(shè)置寬高,默認(rèn)是WRAP_CONTENTpopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);} else {popupWindow.setWidth(width);popupWindow.setHeight(height);}}/*** 設(shè)置背景灰色程度** @param level 0.0f-1.0f*/void setBackGroundLevel(float level) {mWindow = ((Activity) context).getWindow();WindowManager.LayoutParams params = mWindow.getAttributes();params.alpha = level;mWindow.setAttributes(params);}/*** 設(shè)置動(dòng)畫*/private void setAnimationStyle(int animationStyle) {popupWindow.setAnimationStyle(animationStyle);}/*** 設(shè)置Outside是否可點(diǎn)擊** @param touchable 是否可點(diǎn)擊*/private void setOutsideTouchable(boolean touchable) {popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));//設(shè)置透明背景popupWindow.setOutsideTouchable(touchable);//設(shè)置outside可點(diǎn)擊popupWindow.setFocusable(touchable);}static class PopupParams {public int layoutResId;//布局idpublic Context mContext;public int mWidth, mHeight;//彈窗的寬和高public boolean isShowBg, isShowAnim;public float bg_level;//屏幕背景灰色程度public int animationStyle;//動(dòng)畫Idpublic View mView;public boolean isTouchable = true;public PopupParams(Context mContext) {this.mContext = mContext;}public void apply(PopupController controller) {if (mView != null) {controller.setView(mView);} else if (layoutResId != 0) {controller.setView(layoutResId);} else {throw new IllegalArgumentException("PopupView's contentView is null");}controller.setWidthAndHeight(mWidth, mHeight);controller.setOutsideTouchable(isTouchable);//設(shè)置outside可點(diǎn)擊if (isShowBg) {//設(shè)置背景controller.setBackGroundLevel(bg_level);}if (isShowAnim) {controller.setAnimationStyle(animationStyle);}}} } 復(fù)制代碼轉(zhuǎn)載于:https://juejin.im/post/5a33e7b85188256584545746
總結(jié)
以上是生活随笔為你收集整理的Android 封装一个通用的PopupWindow的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ubuntu安装amd/ati显卡驱动
- 下一篇: 为确保Bard能给出高质量答案 谷歌员工