QMUIBasePopup.java 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Tencent is pleased to support the open source community by making QMUI_Android available.
  3. *
  4. * Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
  5. *
  6. * Licensed under the MIT License (the "License"); you may not use this file except in
  7. * compliance with the License. You may obtain a copy of the License at
  8. *
  9. * http://opensource.org/licenses/MIT
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  12. * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  13. * either express or implied. See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.qmuiteam.qmui.widget.popup;
  17. import android.content.Context;
  18. import android.graphics.Color;
  19. import android.graphics.drawable.ColorDrawable;
  20. import android.os.Build;
  21. import android.view.Gravity;
  22. import android.view.MotionEvent;
  23. import android.view.View;
  24. import android.view.WindowManager;
  25. import android.widget.PopupWindow;
  26. import androidx.annotation.NonNull;
  27. import androidx.core.view.ViewCompat;
  28. import com.adealink.frame.util.EdgeUtilKt;
  29. import java.lang.ref.WeakReference;
  30. public abstract class QMUIBasePopup<T extends QMUIBasePopup> {
  31. public static final float DIM_AMOUNT_NOT_EXIST = -1f;
  32. public static final int NOT_SET = -1;
  33. protected final PopupWindow mWindow;
  34. protected WindowManager mWindowManager;
  35. protected Context mContext;
  36. protected WeakReference<View> mAttachedViewRf;
  37. private float mDimAmount = DIM_AMOUNT_NOT_EXIST;
  38. private int mDimAmountAttr = 0;
  39. private PopupWindow.OnDismissListener mDismissListener;
  40. private final View.OnAttachStateChangeListener mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() {
  41. @Override
  42. public void onViewAttachedToWindow(View v) {
  43. }
  44. @Override
  45. public void onViewDetachedFromWindow(View v) {
  46. dismiss();
  47. }
  48. };
  49. private final View.OnTouchListener mOutsideTouchDismissListener = new View.OnTouchListener() {
  50. @Override
  51. public boolean onTouch(View v, MotionEvent event) {
  52. if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
  53. mWindow.dismiss();
  54. return true;
  55. }
  56. return false;
  57. }
  58. };
  59. public QMUIBasePopup(Context context) {
  60. mContext = context;
  61. mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  62. mWindow = new PopupWindow(context);
  63. mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
  64. mWindow.setFocusable(true);
  65. mWindow.setTouchable(true);
  66. mWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
  67. @Override
  68. public void onDismiss() {
  69. removeOldAttachStateChangeListener();
  70. mAttachedViewRf = null;
  71. QMUIBasePopup.this.onDismiss();
  72. if (mDismissListener != null) {
  73. mDismissListener.onDismiss();
  74. }
  75. }
  76. });
  77. dismissIfOutsideTouch(true);
  78. }
  79. protected void onSkinChange(int oldSkin, int newSkin){
  80. }
  81. public T dimAmount(float dimAmount) {
  82. mDimAmount = dimAmount;
  83. return (T) this;
  84. }
  85. public T dimAmountAttr(int dimAmountAttr) {
  86. mDimAmountAttr = dimAmountAttr;
  87. return (T) this;
  88. }
  89. public T setTouchable(boolean touchable){
  90. mWindow.setTouchable(true);
  91. return (T) this;
  92. }
  93. public T setFocusable(boolean focusable){
  94. mWindow.setFocusable(focusable);
  95. return (T) this;
  96. }
  97. public T dismissIfOutsideTouch(boolean dismissIfOutsideTouch) {
  98. mWindow.setOutsideTouchable(dismissIfOutsideTouch);
  99. if (dismissIfOutsideTouch) {
  100. mWindow.setTouchInterceptor(mOutsideTouchDismissListener);
  101. } else {
  102. mWindow.setTouchInterceptor(null);
  103. }
  104. return (T) this;
  105. }
  106. public T onDismiss(PopupWindow.OnDismissListener listener) {
  107. mDismissListener = listener;
  108. return (T) this;
  109. }
  110. private void removeOldAttachStateChangeListener() {
  111. if (mAttachedViewRf != null) {
  112. View oldAttachedView = mAttachedViewRf.get();
  113. if (oldAttachedView != null) {
  114. oldAttachedView.removeOnAttachStateChangeListener(mOnAttachStateChangeListener);
  115. }
  116. }
  117. }
  118. public View getDecorView() {
  119. View decorView = null;
  120. try {
  121. if (mWindow.getBackground() == null) {
  122. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  123. decorView = (View) mWindow.getContentView().getParent();
  124. } else {
  125. decorView = mWindow.getContentView();
  126. }
  127. } else {
  128. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  129. decorView = (View) mWindow.getContentView().getParent().getParent();
  130. } else {
  131. decorView = (View) mWindow.getContentView().getParent();
  132. }
  133. }
  134. } catch (Exception ignore) {
  135. }
  136. return decorView;
  137. }
  138. protected void showAtLocation(@NonNull View parent, int x, int y) {
  139. if (!ViewCompat.isAttachedToWindow(parent)) {
  140. return;
  141. }
  142. removeOldAttachStateChangeListener();
  143. parent.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
  144. mAttachedViewRf = new WeakReference<>(parent);
  145. mWindow.showAtLocation(parent, Gravity.NO_GRAVITY, x, y);
  146. if (mDimAmount != DIM_AMOUNT_NOT_EXIST) {
  147. updateDimAmount(mDimAmount);
  148. }
  149. try {
  150. EdgeUtilKt.fitPopupEdgeToEdge(mWindow);
  151. } catch (Exception e) {}
  152. }
  153. private void updateDimAmount(float dimAmount) {
  154. View decorView = getDecorView();
  155. if (decorView != null) {
  156. WindowManager.LayoutParams p = (WindowManager.LayoutParams) decorView.getLayoutParams();
  157. p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
  158. p.dimAmount = dimAmount;
  159. modifyWindowLayoutParams(p);
  160. mWindowManager.updateViewLayout(decorView, p);
  161. }
  162. }
  163. protected void modifyWindowLayoutParams(WindowManager.LayoutParams lp) {
  164. }
  165. protected void onDismiss() {
  166. }
  167. public final void dismiss() {
  168. mWindow.dismiss();
  169. }
  170. }