Android Nougat PopupWindow showAsDropDown(...) 重力不起作用

Android Nougat PopupWindow showAsDropDown(...) Gravity not working

我有这个代码。

PopupWindow popUp = new PopupWindow();
popUp.setFocusable(true);
popUp.setOutsideTouchable(true);        
popUp.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
popUp.setHeight(600);

popUp.setContentView(anchorView);
popUp.showAsDropDown(anchorView);
popUp.update();

它完美适用于 Android 版本 < Android 牛轧糖。但在 Android Nougat 中,弹出窗口显示在屏幕顶部,而不是相对于锚点视图。

这似乎是 android 7.0 中的错误。但是你可以用一个解决它 兼容方式。

PopupWindow popUp = new PopupWindow();
popUp.setFocusable(true);
popUp.setOutsideTouchable(true);        
popUp.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
popUp.setHeight(600);

popUp.setContentView(anchorView);
  if (android.os.Build.VERSION.SDK_INT >=24) {
     int[] a = new int[2]; //getLocationInWindow required array of size 2
     anchorView.getLocationInWindow(a);
     popUp.showAtLocation(((Activity) mContext).getWindow().getDecorView(), Gravity.NO_GRAVITY, 0 , a[1]+anchorView.getHeight());
    } else{
     popUp.showAsDropDown(anchorView);
}

popUp.update();

Google 将在未来的版本中修复此错误。还有一个最终的解决方法。创建pop时需要给定高度。

PopupWindow popup = new PopupWindow(contentView, with, height);

init pop同上,只能用 popUp.showAsDropDown(anchorView) 显示此弹出窗口。这样就可以忽略AndroidAPI.

的版本了

您的代码中真的需要 popUp.update(); 吗?我有一个类似的问题,在我的情况下我不需要 popUp.update(); 并且删除它使弹出重力按预期运行。

此外,这很可能是一个相关问题,已报告 PopupWindow.showAtLocation()

https://code.google.com/p/android/issues/detail?id=221001

看起来这个问题只出现在 Android 7.0 (API 24) 中。在 7.1.1 (API 25) 中,在相同的设备上一切正常。经过一些研究确定由 popUp.update() 引起的问题,就像 已经提到的一样。但是如果你只是删除popUp.update(),弹出窗口不会出现在API 24之前的版本中。为了避免这种情况,现在唯一的方法是使用版本检查并且不要使用update() 方法仅适用于 API 24 的设备。这是对我有用的解决方案:

if (Build.VERSION.SDK_INT != 24) {
   popup.update(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
}

在不同的设备和 API 上对其进行了测试,从 API 18 到 API 25,它在任何地方都运行良好。

7.0和7.1实现不同,所以要分开处理。

以下方法我在虚拟机(7.0和7.1)中测试过,没问题。

public void showFilterWindow(Context context, PopupWindow popupWindow,View showView, int xoff, int yoff) {
        if (Build.VERSION.SDK_INT < 24) {
            //7.0 The following system is used normally
            popupWindow.showAsDropDown(showView, xoff, yoff);
        } else {
            int[] location = new int[2];
            showView.getLocationOnScreen(location);
            int offsetY = location[1] + showView.getHeight() + yoff;
            if (Build.VERSION.SDK_INT == 25) {
                //【note!】Gets the screen height without the virtual key
                WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
                int screenHeight = wm.getDefaultDisplay().getHeight();
                /*
                 * PopupWindow height for match_parent,
                 * will occupy the entire screen, it needs to do special treatment in Android 7.1
                */
                popupWindow.setHeight(screenHeight - offsetY);
            }
            //Use showAtLocation to display pop-up windows
            popupWindow.showAtLocation(showView, Gravity.NO_GRAVITY, 0, offsetY);
        }
    }

这段代码对我有用。请试一试

    protected void showSortPopup(View anchorView) {


    if (Build.VERSION.SDK_INT >= 25) {
        Rect rectf = new Rect();
        anchorView.getGlobalVisibleRect(rectf);
        int offsetY = (rectf.top + anchorView.getHeight());
        WindowManager wm = (WindowManager) Manager.getInstance().getCurrentActivity().getSystemService(Context.WINDOW_SERVICE);
        int screenHeight = wm.getDefaultDisplay().getHeight();
        mPopup.setHeight(screenHeight - offsetY);
    }
    mPopup.showAsDropDown(anchorView);

}

在 Android API 29 中,我通过将弹出窗口的宽度和高度替换为 WRAP_CONTENT 进行了修复。正如我在 Kotlin.

中的代码
private fun createSpinnerLikePopUp() {
        val inflater = context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val vw = inflater.inflate(R.layout.dialog_window, null, false)
            popUp = PopupWindow(context).apply {
            isFocusable = true
            width = WindowManager.LayoutParams.WRAP_CONTENT
            height = WindowManager.LayoutParams.WRAP_CONTENT
            contentView = vw
            setBackgroundDrawable(null)
        }
        vw!!.recyclerView.apply {
            layoutManager = LinearLayoutManager(context)
            adapter = RecyclerAdapter(context, myArray)
        }
    }

点击按钮如下:

displayPopupBtn.setOnClickListener { view ->
            if (popUp != null) {
                if (popUp.isShowing) {
                    popUp.dismiss()
                } else {
                    popUp.showAsDropDown(view)
                }
            }
        }