Skip to content

Commit

Permalink
update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Jankin6 committed Nov 22, 2018
1 parent f002092 commit d1258f7
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 197 deletions.
209 changes: 12 additions & 197 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)
26 changes: 26 additions & 0 deletions README_EN.md
Original file line number Diff line number Diff line change
@@ -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)
Binary file added screenshot.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit d1258f7

Please sign in to comment.