No Description

SafeAreaView.java 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package com.th3rdwave.safeareacontext;
  2. import android.content.Context;
  3. import android.graphics.Rect;
  4. import android.os.Build;
  5. import android.view.Surface;
  6. import android.view.View;
  7. import android.view.ViewTreeObserver;
  8. import android.view.WindowInsets;
  9. import android.view.WindowManager;
  10. import com.facebook.infer.annotation.Assertions;
  11. import com.facebook.react.views.view.ReactViewGroup;
  12. import androidx.annotation.Nullable;
  13. public class SafeAreaView extends ReactViewGroup implements ViewTreeObserver.OnGlobalLayoutListener {
  14. public interface OnInsetsChangeListener {
  15. void onInsetsChange(SafeAreaView view, EdgeInsets insets);
  16. }
  17. private @Nullable OnInsetsChangeListener mInsetsChangeListener;
  18. private WindowManager mWindowManager;
  19. private @Nullable EdgeInsets mLastInsets;
  20. public SafeAreaView(Context context) {
  21. super(context);
  22. mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  23. }
  24. private EdgeInsets getSafeAreaInsets() {
  25. // Window insets are parts of the window that are covered by system views (status bar,
  26. // navigation bar, notches). There are no apis the get these values for android < M so we
  27. // do a best effort polyfill.
  28. EdgeInsets windowInsets;
  29. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  30. WindowInsets insets = getRootWindowInsets();
  31. windowInsets = new EdgeInsets(
  32. insets.getSystemWindowInsetTop(),
  33. insets.getSystemWindowInsetRight(),
  34. insets.getSystemWindowInsetBottom(),
  35. insets.getSystemWindowInsetLeft());
  36. } else {
  37. int rotation = mWindowManager.getDefaultDisplay().getRotation();
  38. int statusBarHeight = 0;
  39. int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
  40. if (resourceId > 0) {
  41. statusBarHeight = getResources().getDimensionPixelSize(resourceId);
  42. }
  43. int navbarHeight = 0;
  44. resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
  45. if (resourceId > 0) {
  46. navbarHeight = getResources().getDimensionPixelSize(resourceId);
  47. }
  48. windowInsets = new EdgeInsets(
  49. statusBarHeight,
  50. rotation == Surface.ROTATION_90 ? navbarHeight : 0,
  51. rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? navbarHeight : 0,
  52. rotation == Surface.ROTATION_270 ? navbarHeight : 0);
  53. }
  54. // Calculate the part of the root view that overlaps with window insets.
  55. View rootView = getRootView();
  56. View contentView = rootView.findViewById(android.R.id.content);
  57. float windowWidth = rootView.getWidth();
  58. float windowHeight = rootView.getHeight();
  59. Rect visibleRect = new Rect();
  60. contentView.getGlobalVisibleRect(visibleRect);
  61. windowInsets.top = Math.max(windowInsets.top - visibleRect.top, 0);
  62. windowInsets.left = Math.max(windowInsets.left - visibleRect.left, 0);
  63. windowInsets.bottom = Math.max(visibleRect.top + contentView.getHeight() + windowInsets.bottom - windowHeight, 0);
  64. windowInsets.right = Math.max(visibleRect.left + contentView.getWidth() + windowInsets.right - windowWidth, 0);
  65. return windowInsets;
  66. }
  67. private void maybeUpdateInsets() {
  68. if (!isAttachedToWindow()) {
  69. return;
  70. }
  71. EdgeInsets edgeInsets = getSafeAreaInsets();
  72. if (mLastInsets == null || !mLastInsets.equalsToEdgeInsets(edgeInsets)) {
  73. Assertions.assertNotNull(mInsetsChangeListener).onInsetsChange(this, edgeInsets);
  74. mLastInsets = edgeInsets;
  75. }
  76. }
  77. @Override
  78. protected void onAttachedToWindow() {
  79. super.onAttachedToWindow();
  80. getViewTreeObserver().addOnGlobalLayoutListener(this);
  81. maybeUpdateInsets();
  82. }
  83. @Override
  84. protected void onDetachedFromWindow() {
  85. super.onDetachedFromWindow();
  86. getViewTreeObserver().removeOnGlobalLayoutListener(this);
  87. }
  88. @Override
  89. public void onGlobalLayout() {
  90. maybeUpdateInsets();
  91. }
  92. public void setOnInsetsChangeListener(OnInsetsChangeListener listener) {
  93. mInsetsChangeListener = listener;
  94. }
  95. }