日常android开发中经常会用到popWindow。因此封装一个可自定义view,可设置弹出动画,可设置大小的通用popWindow显得尤为重要。
效果图如下:
通用PopWindow分为如下3部分:
1.自定义popWindow
2.popWindow的辅助类
3.popWindow的弹出动画
4.popWindow的使用
1.自定义popWindow
/*
* 通用的popWindow
*/
public class CommonPopupWindow extends PopupWindow {
private PopupController controller;
@Override
public int getWidth() {
return controller.mPopupView.getMeasuredWidth();
}
@Override
public int getHeight() {
return controller.mPopupView.getMeasuredHeight();
}
public interface ViewInterface {
void getChildView(View view, int layoutResId);
}
private CommonPopupWindow(Context context) {
controller = new PopupController(context, this);
}
@Override
public 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 设置PopupWindow 布局ID
* @return Builder
*/
public Builder setView(int layoutResId) {
params.mView = null;
params.layoutResId = layoutResId;
return this;
}
/**
* @param view 设置PopupWindow布局
* @return Builder
*/
public Builder setView(View view) {
params.mView = view;
params.layoutResId = 0;
return this;
}
/**
* 设置子View
*
* @param listener ViewInterface
* @return Builder
*/
public Builder setViewOnclickListener(ViewInterface listener) {
this.listener = listener;
return this;
}
/**
* 设置宽度和高度 如果不设置 默认是wrap_content
*
* @param width 宽
* @return Builder
*/
public Builder setWidthAndHeight(int width, int height) {
params.mWidth = width;
params.mHeight = height;
return this;
}
/**
* 设置背景灰色程度
*
* @param level 0.0f-1.0f
* @return Builder
*/
public Builder setBackGroundLevel(float level) {
params.isShowBg = true;
params.bg_level = level;
return this;
}
/**
* 是否可点击Outside消失
*
* @param touchable 是否可点击
* @return Builder
*/
public Builder setOutsideTouchable(boolean touchable) {
params.isTouchable = touchable;
return this;
}
/**
* 设置动画
*
* @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);
}
//测量View的宽高
int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
popupWindow.controller.mPopupView.measure(w, h);
return popupWindow;
}
}
}
2.popWindow的辅助类
/*
*用pop辅助类(只会在CommonPopupWindow中被用到)
*/
public class PopupController {
private int layoutResId; //布局id
private Context context;
private PopupWindow popupWindow;
public View mPopupView; //弹窗布局View
private View mView;
private Window mWindow;
public 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);
}
/**
* 设置宽度
*
* @param width 宽
* @param height 高
*/
private void setWidthAndHeight(int width, int height) {
if (width == 0 || height == 0) {
//如果没设置宽高,默认是WRAP_CONTENT
popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
} else {
popupWindow.setWidth(width);
popupWindow.setHeight(height);
}
}
/**
* 设置背景灰色程度
*
* @param level 0.0f-1.0f
*/
public void setBackGroundLevel(float level) {
mWindow = ((Activity) context).getWindow();
WindowManager.LayoutParams params = mWindow.getAttributes();
params.alpha = level;
mWindow.setAttributes(params);
}
/**
* 设置动画
*/
private void setAnimationStyle(int animationStyle) {
popupWindow.setAnimationStyle(animationStyle);
}
/**
* 设置Outside是否可点击
*
* @param touchable 是否可点击
*/
private void setOutsideTouchable(boolean touchable) {
popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));//设置透明背景
popupWindow.setOutsideTouchable(touchable);//设置outside可点击
popupWindow.setFocusable(touchable);
}
public static class PopupParams {
public int layoutResId;//布局id
public Context mContext;
public int mWidth, mHeight;//弹窗的宽和高
public boolean isShowBg, isShowAnim;
public float bg_level;//屏幕背景灰色程度
public int animationStyle;//动画Id
public 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);//设置outside可点击
if (isShowBg) {
//设置背景
controller.setBackGroundLevel(bg_level);
}
if (isShowAnim) {
controller.setAnimationStyle(animationStyle);
}
}
}
}
3.popWindow的弹出动画
淡入:pop_fade_in_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha
android:duration="200"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>
淡出:pop_fade_out_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha
android:duration="200"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>
style.xml
<style name="pop_anim" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/pop_fade_in_anim</item>
<item name="android:windowExitAnimation">@anim/pop_fade_out_anim</item>
</style>
4.popWindow的使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
ImageView addMore = findViewById(R.id.add_more_iv);
addMore.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CommonPopupWindow popupWindow = new CommonPopupWindow.Builder(MainActivity.this)
.setView(R.layout.popwindow_add_more)
.setWidthAndHeight(DensityUtils.dp2px(MainActivity.this, 140),
DensityUtils.dp2px(MainActivity.this, 140))
.setAnimationStyle(R.style.pop_anim)
.setViewOnclickListener(new CommonPopupWindow.ViewInterface() {
@Override
public void getChildView(View view, int layoutResId) {
TextView addFriends = view.findViewById(R.id.add_friends);
TextView startWeChat = view.findViewById(R.id.start_we_chat);
TextView scan = view.findViewById(R.id.scan);
addFriends.setOnClickListener(itemsOnClick);
startWeChat.setOnClickListener(itemsOnClick);
scan.setOnClickListener(itemsOnClick);
}
})
.setOutsideTouchable(true)
.create();
popupWindow.showAsDropDown(v);
}
});
}
private View.OnClickListener itemsOnClick = new View.OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.add_friends:
Toast.makeText(MainActivity.this,"添加朋友",Toast.LENGTH_SHORT).show();
break;
case R.id.start_we_chat:
Toast.makeText(MainActivity.this,"发起群聊",Toast.LENGTH_SHORT).show();
break;
case R.id.scan:
Toast.makeText(MainActivity.this,"扫一扫",Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
};
}
至于上面调整popWindow大小用到的dp转换工具类DensityUtils.java,我就不贴出来了,网上一大堆。popWindow的背景用到的点9图,大家需要的话,可点击下载 带箭头的点9图。
补充一点,关于popWindow的弹出位置可使用
popupWindow.showAsDropDown(v);
//或者
mPopwindow.showAtLocation(v,Gravity.xxx, 0, 0);
写完之后发现一个好像挺不错的博文,贴出来吧。
拒绝无用功,封装一个通用的 PopupWindow
好了,完了。有问题,请留言。