diff --git a/README.md b/README.md index 8ae2277..58d333c 100644 --- a/README.md +++ b/README.md @@ -1,211 +1,26 @@ # PopupWindowCompat -兼容android 7.x , 8.0 etc的Popwindow +[![Build Status](https://travis-ci.com/wang0826jj/PopupWindowCompat.svg?branch=master)](https://travis-ci.com/wang0826jj/PopupWindowCompat) [![Bintray](https://api.bintray.com/packages/wang0826jj/maven/PopupWindowCompat/images/download.svg)](https://bintray.com/wang0826jj/maven/PopupWindowCompat/_latestVersion) [![GitHub license](https://img.shields.io/github/license/wang0826jj/PopupWindowCompat.svg)](https://github.com/wang0826jj/PopupWindowCompat/blob/master/LICENSE) -### 问题描述 -前段时间发现Popupwindow在8.0的手机上显示成全屏了,搜了下发现7.0以上就有这个问题了,好久没写Popwindow了,才知道(尴尬)。于是总结了在以下情况可能出问题: +## [English](README_EN.md) | 中文 -1. 当设置PopupWindow 的高度为 MATCH_PARENT,调用 showAsDropDown(View anchor) 时,在 7.0 之前,会在 anchor 下边缘到屏幕底部之间显示 PopupWindow;而在 7.0系统上(包括7.1, 8.0)的 PopupWindow 会占据整个屏幕(除状态栏之外)。 -2. 当设置PopupWindow 的高度为 WRAP_CONTENT,调用 showAsDropDown(View anchor) 时,没有兼容性问题。 -3. 当设置PopupWindow 的高度为自定义的值height,调用 showAsDropDown(View anchor)时, 如果 height > anchor 下边缘与屏幕底部的距离, 则还是会出现7.0以上显示异常的问题;否则,不会出现该问题。 +一个兼容android 7.x , 8.x etc系统的Popwindow,主要适配当设置高度为match_parent时,调用`popupWindow.showAsDropDown()`后的高度全屏问题,同时适配了是否有虚拟按键,虚拟按键是否显示的情况。 -### 问题解决 -好了,现在我们知道问题出现的情况了,上网搜了很多解决方案,发现都不能完美解决问题,如以下代码: +## 添加到项目 -```java -if (Build.VERSION.SDK_INT >= 24) { - int[] location = new int[2]; - anchor.getLocationOnScreen(location); - // 7.1 版本处理 - if (Build.VERSION.SDK_INT == 25) { - WindowManager windowManager = (WindowManager) pw.getContentView().getContext().getSystemService(Context.WINDOW_SERVICE); - if (windowManager != null) { - int screenHeight = windowManager.getDefaultDisplay().getHeight(); - // PopupWindow height for match_parent, will occupy the entire screen, it needs to do special treatment in Android 7.1 - pw.setHeight(screenHeight - location[1] - anchor.getHeight() - yoff); - } - } - pw.showAtLocation(anchor, Gravity.NO_GRAVITY, xoff, location[1] + anchor.getHeight() + yoff); - - } else { - pw.showAsDropDown(anchor, xoff, yoff); - } -``` -或者这种代码: - -```java -public static void showAsDropDown(final PopupWindow pw, final View anchor, final int xoff, final int yoff) { - if (Build.VERSION.SDK_INT >= 24) { - Rect visibleFrame = new Rect(); - anchor.getGlobalVisibleRect(visibleFrame); - int height = anchor.getResources().getDisplayMetrics().heightPixels - visibleFrame.bottom; - pw.setHeight(height); - pw.showAsDropDown(anchor, xoff, yoff); - } else { - pw.showAsDropDown(anchor, xoff, yoff); - } -} -``` -这两段代码的主要问题是,没有考虑虚拟按键的情况,屏幕的高度算的不一定对,或者有虚拟按键,虚拟按键是否显示都会影响屏幕的可用高度。所以问题的关键是算出屏幕真实的可用高度。 - -为了方便以后复用,我们重新定义一个PopupWindowCompat继承自PopupWindow,具体代码如下,主要是综合考虑以上三种情况,和算出屏幕的真实可用高度,注释已经写的很清楚了吧,我就省点字了(偷懒)。 - -获取屏幕真实总高度: - -```java -public static int getScreenHeight(Activity activity) { - if (activity == null) { - return 0; - } - Display display = activity.getWindowManager().getDefaultDisplay(); - int realHeight = 0; - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - final DisplayMetrics metrics = new DisplayMetrics(); - display.getRealMetrics(metrics); - realHeight = metrics.heightPixels; - } else { - try { - Method mGetRawH = Display.class.getMethod("getRawHeight"); - realHeight = (Integer) mGetRawH.invoke(display); - } catch (Exception e) { - e.printStackTrace(); - } - } - return realHeight; - } -``` - -检测是否具有底部导航栏 - -```java - private static boolean checkDeviceHasNavigationBar(Activity activity) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - WindowManager windowManager = activity.getWindowManager(); - Display display = windowManager.getDefaultDisplay(); - DisplayMetrics realDisplayMetrics = new DisplayMetrics(); - display.getRealMetrics(realDisplayMetrics); - int realHeight = realDisplayMetrics.heightPixels; - int realWidth = realDisplayMetrics.widthPixels; - DisplayMetrics displayMetrics = new DisplayMetrics(); - display.getMetrics(displayMetrics); - int displayHeight = displayMetrics.heightPixels; - int displayWidth = displayMetrics.widthPixels; - return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0; - } else { - boolean hasNavigationBar = false; - Resources resources = activity.getResources(); - int id = resources.getIdentifier("config_showNavigationBar", "bool", "android"); - if (id > 0) { - hasNavigationBar = resources.getBoolean(id); - } - try { - Class systemPropertiesClass = Class.forName("android.os.SystemProperties"); - Method m = systemPropertiesClass.getMethod("get", String.class); - String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys"); - if ("1".equals(navBarOverride)) { - hasNavigationBar = false; - } else if ("0".equals(navBarOverride)) { - hasNavigationBar = true; - } - } catch (Exception e) { - } - return hasNavigationBar; - } - } +```groovy +implementation 'com.jankin.popupwindowcompat:lib:1.0.1' ``` -有底部导航栏时,底部导航栏是否可见: +## 使用 -```java -private static boolean isNavigationBarVisible(Activity activity) { - boolean show = false; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - Display display = activity.getWindow().getWindowManager().getDefaultDisplay(); - Point point = new Point(); - display.getRealSize(point); - View decorView = activity.getWindow().getDecorView(); - Configuration conf = activity.getResources().getConfiguration(); - if (Configuration.ORIENTATION_LANDSCAPE == conf.orientation) { - View contentView = decorView.findViewById(android.R.id.content); - show = (point.x != contentView.getWidth()); - } else { - Rect rect = new Rect(); - decorView.getWindowVisibleDisplayFrame(rect); - show = (rect.bottom != point.y); - } - } - return show; - } -``` - - -获取底部导航栏真实高度: - -```java - /** - * 获取当前底部导航栏高度(隐藏后高度为0) - * - * @param activity - * @return - */ - public static int getCurrentNavigationBarHeight(Activity activity) { - int navigationBarHeight = 0; - Resources resources = activity.getResources(); - int resourceId = resources.getIdentifier(isPortrait(activity) ? "navigation_bar_height" : "navigation_bar_height_landscape", "dimen", "android"); - if (resourceId > 0 && checkDeviceHasNavigationBar(activity) && isNavigationBarVisible(activity)) { - navigationBarHeight = resources.getDimensionPixelSize(resourceId); - } - return navigationBarHeight; - } -``` +使用PopupWindowCompat替代PopupWindow,用法和PopupWindow一样。 -获取屏幕可用高度: +## 效果图 -```java - /** - * 获取可用屏幕高度,排除虚拟键 - * - * @param context 上下文 - * @return 返回高度 - */ - public static int getContentHeight(Activity context) { - int contentHeight = getScreenHeight(context) - getCurrentNavigationBarHeight(context); - return contentHeight; - } +![screenshot](screenshot.gif) -``` - -自定义的PopupWindowCompat的主要代码如下: - -```java - @Override - public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) { - // 7.0 以下或者高度为WRAP_CONTENT, 默认显示 - if (Build.VERSION.SDK_INT < 24 || getHeight() == ViewGroup.LayoutParams.WRAP_CONTENT) { - super.showAsDropDown(anchor, xoff, yoff, gravity); - } else { - if (getContentView().getContext() instanceof Activity) { - Activity activity = (Activity) getContentView().getContext(); - int screenHeight; - // 获取屏幕真实高度, 减掉虚拟按键的高度 - screenHeight = OsUtils.getContentHeight(activity); - int[] location = new int[2]; - // 获取控件在屏幕的位置 - anchor.getLocationOnScreen(location); - // 算出popwindow最大高度 - int maxHeight = screenHeight - location[1] - anchor.getHeight(); - // popupwindow 有具体的高度值,但是小于anchor下边缘与屏幕底部的距离, 正常显示 - if(getHeight() > 0 && getHeight() < maxHeight){ - super.showAsDropDown(anchor, xoff, yoff, gravity); - }else { - // match_parent 或者 popwinddow的具体高度值大于anchor下边缘与屏幕底部的距离, 都设置为最大可用高度 - setHeight(maxHeight); - super.showAsDropDown(anchor, xoff, yoff, gravity); - } - } - } +## 传送门 - - } -``` +- [博客文章](https://blog.csdn.net/Kelaker/article/details/81274417) \ No newline at end of file diff --git a/README_EN.md b/README_EN.md new file mode 100644 index 0000000..c83daaa --- /dev/null +++ b/README_EN.md @@ -0,0 +1,26 @@ +# PopupWindowCompat +[![Build Status](https://travis-ci.com/wang0826jj/PopupWindowCompat.svg?branch=master)](https://travis-ci.com/wang0826jj/PopupWindowCompat) [![Bintray](https://api.bintray.com/packages/wang0826jj/maven/PopupWindowCompat/images/download.svg)](https://bintray.com/wang0826jj/maven/PopupWindowCompat/_latestVersion) [![GitHub license](https://img.shields.io/github/license/wang0826jj/PopupWindowCompat.svg)](https://github.com/wang0826jj/PopupWindowCompat/blob/master/LICENSE) + +## English | [中文](README.md) + +A compatible Popwindow adapt android 7.x , 8.x etc, Mainly adapts to the height of the full-screen problem after calling `popupWindow.showAsDropDown()` when setting the height to match_parent, and adapting whether there is a virtual button and whether the virtual button is displayed. + +## Adding to your project + +```groovy +implementation 'com.jankin.popupwindowcompat:lib:1.0.1' +``` + +## Simple Usage + +Use PopupWindowCompat instead of PopupWindow, the same as PopupWindow. + +## Screenshots + +![screenshot](screenshot.gif) + + + +## Gateway + +- [Blog posts](https://blog.csdn.net/Kelaker/article/details/81274417) \ No newline at end of file diff --git a/screenshot.gif b/screenshot.gif new file mode 100644 index 0000000..21f178f Binary files /dev/null and b/screenshot.gif differ