Android从屏幕底部弹出PopupWin窗口

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也就是相对于坐标原点的位置了。

完!!!

发布了106 篇原创文章 · 获赞 65 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/xialong_927/article/details/90243891
今日推荐