1、布局文件
lay_menupopwin
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/dot_trans_white"
android:orientation="vertical">
<TextView
android:id="@+id/text2"
android:layout_width="match_parent"
android:layout_height="45dp"
android:text="@string/t_menu_logout"
android:textColor="@color/red"
android:gravity="center"
android:textSize="@dimen/textsize_h4"/>
<View
android:layout_width="match_parent"
android:layout_height="10dp"
android:background="@color/transparent"/>
<TextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="45dp"
android:text="@string/t_menu_cancel"
android:textColor="@color/black"
android:gravity="center"
android:textSize="@dimen/textsize_h4"/>
</LinearLayout>
2、anim
bottom_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromYDelta="100%p"
android:toYDelta="0"
android:duration="200" />
<alpha
android:fromAlpha="0.7"
android:toAlpha="1.0"
android:duration="200" />
</set>
bottom_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromYDelta="0"
android:toYDelta="100%p"
android:duration="200" />
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.5"
android:duration="200" />
</set>
3、样式style.xml
<!-- popupwin泡泡窗口,控制面板 -->
<style name="popWinAnimBot" parent="android:Animation">
<item name="@android:windowEnterAnimation">@anim/bottom_enter</item>
<item name="@android:windowExitAnimation">@anim/bottom_out</item>
</style>
4、java
/**
* 弹出菜单
* Created by xl on 2019/5/15.
*/
public class MenuPopupWin extends PopupWindow {
private Context m_context;
private TextView m_tvMenu1;
private TextView m_tvMenu2;
private View m_view;
private Window m_window;
public MenuPopupWin(Context context, final OnMenuItemClickListener listener) {
super(context);
this.m_context = context;
// 初始化view
m_view = LayoutInflater.from(context).inflate(R.layout.lay_menupopwin, null);
m_tvMenu1 = m_view.findViewById(R.id.text1);
m_tvMenu2 = m_view.findViewById(R.id.text2);
m_tvMenu1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
m_tvMenu2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onItemClick(view, 1);
}
dismiss();
}
});
// 设置自定义PopupWindow的View
this.setContentView(m_view);
// 设置自定义PopupWindow弹出窗体的宽
this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
// 设置自定义PopupWindow弹出窗体的高
this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
// 设置自定义PopupWindow弹出窗体可点击
this.setFocusable(true);
// 设置自定义PopupWindow弹出窗体动画效果
this.setAnimationStyle(R.style.popWinAnimBot);
// 实例化一个ColorDrawable颜色为半透明
ColorDrawable dw = new ColorDrawable(0xb0000000);
// 设置自定义PopupWindow弹出窗体的背景
this.setBackgroundDrawable(dw);
// popupwindow消失,恢复透明度
this.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
WindowManager.LayoutParams lp = m_window.getAttributes();
lp.alpha = 1f;
m_window.setAttributes(lp);
}
});
// mMenuView添加OnTouchListener监听判断获取触屏位置如果在选择框外面则销毁弹出框
m_view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int height = m_view.findViewById(R.id.lay_spinnerdlg).getTop();
int y = (int) event.getY();
if (event.getAction() == MotionEvent.ACTION_UP) {
if (y < height) {
dismiss();
}
}
// setOutsideTouchable(true)则点击PopupWindow之外的地方PopupWindow会消失
return true;
}
});
}
/**
* 显示dlg,window用来设置背景变暗
*
* @param parent
*/
public void show(View parent, Window window) {
showAtLocation(parent, Gravity.BOTTOM, 0, 0);
m_window = window;
// 设置背景变暗
WindowManager.LayoutParams lp = window.getAttributes();
lp.alpha = 0.5f;
window.setAttributes(lp);
}
/**
* 定义接口
*/
public interface OnMenuItemClickListener {
void onItemClick(View view, int position);
}
}
5、activity调用
showMenuPopup(view);
/**
* 弹出menu菜单
*/
private void showMenuPopup(View view){
MenuPopupWin menu = new MenuPopupWin(this, new MenuPopupWin.OnMenuItemClickListener() {
@Override
public void onItemClick(View view, int position) {
}
});
menu.show(view, getWindow());
}
补充:
showAtLocation与showAsDropDown问题
showAsDropDown(View anchor, int xoff, int yoff)方法
这个方法没有什么好说的,在锚点anchor的正下方弹出popup,参数xoff和yoff分别是x轴和y轴的偏移量,偏移量是相对锚点anchor来说的,以anchor的左下角为参考点;
但是,需要注意的是,Android 7.0版本之前,在指定位置弹出popupwindow用showAsDropDown(View anchor, int xoff, int yoff)毫无问题,但在android 7.0上,用showAsDropDown()就需要注意下面两点了:
-
如果指定 PopupWindow 的高度为 MATCH_PARENT,调用 showAsDropDown(View anchor) 时,在 7.0 之前,会在锚点 anchor 下边缘到屏幕底部之间显示 PopupWindow;而在 7.0、7.1 系统上的 PopupWindow 会占据整个屏幕(除状态栏之外)。
-
如果指定 PopupWindow 的高度为自定义的值height,调用 showAsDropDown(View anchor)时, 如果 height > 锚点 anchor 下边缘与屏幕底部的距离, 则还是会出现7.0、7.1上显示异常的问题;否则,不会出现该问题。
所以在无法避免上述的两个问题时,这时候就需要用showAtLocation()来处理可能出现的popup显示异常问题。
showAtLocation(View parent, int gravity, int x, int y)
对showAtLocation()方法的很多解释都是:“相对于父控件的位置,x和y为偏移量。”这种解释绝对是错的离谱,而且很可笑,如果是这样,那它和showAsDropDown()方法还有什么异同,瞪大眼睛看看这个方法的参数,x不再是xoff,y也不再是yoff,从字面上来看也不是什么所谓的偏移量吧,首先,这个方法是对于整个window的屏幕以坐标来定位置的,不存在相对于某一个view,有相对也是相对整个屏幕,参数x和y是坐标。
该方法的第一个参数是parent,类型是个View,这个参数名很让人误解,其实,并不是把PopupWindow放到这个parent里,并不要求这个parent是一个ViewGroup。官方文档对这个参数的解释是“a parent view to get the token from”,这个parent的作用应该是调用其getWindowToken()方法获取窗口的Token,所以,只要是该窗口上的控件就可以了。我个人开发中,一般是拿该parent在屏幕中的坐标拿来作为参考的,通过parent.getLocationInWindow(location)
获得parent在屏幕上的坐标,其中location是一个大小为2的int数组。
第二个参数很让人理解为对齐方式,当然不是,而是通过设置gravity来设置坐标原点:
- Gravity.TOP | Gravity.LEFT 以屏幕左上角为坐标原点
- Gravity.BOTTOM | Gravity.RIGHT 以屏幕右下角为坐标原点
- Gravity.LEFT 以屏幕左侧,屏幕高度 1/2 处为坐标原点
以此类推,可根据实际情况是设置坐标原点的位置。
设置了第二个参数,后面的参数x,y也就是相对于坐标原点的位置了。
完!!!