ソースを参照

Merge pull request #356 from Matcha-xiaobin/master

尝试修正 padding属性设置错误的bug.
Kongzue 1 年間 前
コミット
4501cf54a1

+ 3 - 1
DialogX/src/main/java/com/kongzue/dialogx/interfaces/BaseDialog.java

@@ -886,7 +886,9 @@ public abstract class BaseDialog implements LifecycleOwner {
         return windowInsets;
     }
 
-    public static void publicWindowInsets(WindowInsets windowInsets) {
+    public static void publicWindowInsets(WindowInsets windowInsets) {}
+
+    public static void publicWindowInsetsOld(WindowInsets windowInsets) {
         if (windowInsets == null) {
             return;
         }

+ 121 - 55
DialogX/src/main/java/com/kongzue/dialogx/util/views/DialogXBaseRelativeLayout.java

@@ -39,8 +39,6 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * @author: Kongzue
@@ -103,30 +101,88 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
             setClipChildren(false);
             setClipToPadding(false);
         }
-    }
+        //新增的 设置监听 OnApplyWindowInsetsListener
+        FitSystemBarUtils.attachView(this, new FitSystemBarUtils.CallBack() {
+            @Override
+            public boolean isEnable(FitSystemBarUtils.Orientation orientation) {
+                return true;
+            }
 
-    @Override
-    protected boolean fitSystemWindows(Rect insets) {
-        if (!useWindowInsetsAnimation && (DialogX.useActivityLayoutTranslationNavigationBar || (getParentDialog() != null && getParentDialog().getDialogImplMode() != DialogX.IMPL_MODE.VIEW))) {
-            log("#fitSystemWindows paddingView: b=" + insets.bottom);
-            paddingView(insets.left, insets.top, insets.right, insets.bottom);
-        }
-        return super.fitSystemWindows(insets);
-    }
+            @Override
+            public void unsafeRect(int start, int top, int end, int bottom) {
+                if (unsafePlace == null) {
+                    unsafePlace = new Rect();
+                }
+                unsafePlace.left = start;
+                unsafePlace.top = top;
+                unsafePlace.right = end;
+                unsafePlace.bottom = bottom;
+
+                //做下判断,如果是底部对话框,则把paddingBottom设为0,改为推起子控件
+                MaxRelativeLayout bkgView = findViewById(R.id.bkg);
+                if (bkgView != null && bkgView.getLayoutParams() instanceof LayoutParams) {
+                    LayoutParams bkgLp = (LayoutParams) bkgView.getLayoutParams();
+                    if (bkgLp.getRules()[ALIGN_PARENT_BOTTOM] == RelativeLayout.TRUE && isAutoUnsafePlacePadding()) {
+                        setPadding(extraPadding[0] + unsafePlace.left,
+                                extraPadding[1] + unsafePlace.top,
+                                extraPadding[2] + unsafePlace.right,
+                                extraPadding[3]
+                        );
+                        bkgView.setNavBarHeight(bottom);
+                        if (getParentDialog() instanceof DialogXBaseBottomDialog) {
+                            if (((DialogXBaseBottomDialog) getParentDialog()).isBottomNonSafetyAreaBySelf()) {
+                                bkgView.setPadding(0, 0, 0, 0);
+                                return;
+                            }
+                        }
+                        unsafePlace.bottom = 0;
+                        bkgView.setPadding(0, 0, 0, bottom);
+                    }
+                }
+            }
 
-    @Override
-    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            if (!useWindowInsetsAnimation && (DialogX.useActivityLayoutTranslationNavigationBar || (getParentDialog() != null && getParentDialog().getDialogImplMode() != DialogX.IMPL_MODE.VIEW))) {
-                paddingView(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
-                log("#dispatchApplyWindowInsets paddingView: b=" + insets.getSystemWindowInsetBottom());
+            @Override
+            public int initialPadding(FitSystemBarUtils.Orientation orientation) {
+                switch (orientation) {
+                    case Start:
+                        return extraPadding[0];
+                    case Top:
+                        return extraPadding[1];
+                    case End:
+                        return extraPadding[2];
+                    case Bottom:
+                        return extraPadding[3];
+                }
+                return 0;
             }
-        }
-        return super.dispatchApplyWindowInsets(insets);
+        });
+    }
+
+//    @Override
+//    protected boolean fitSystemWindows(Rect insets) {
+//        if (!useWindowInsetsAnimation && (DialogX.useActivityLayoutTranslationNavigationBar || (getParentDialog() != null && getParentDialog().getDialogImplMode() != DialogX.IMPL_MODE.VIEW))) {
+//            log("#fitSystemWindows paddingView: b=" + insets.bottom);
+//            paddingView(insets.left, insets.top, insets.right, insets.bottom);
+//        }
+//        return super.fitSystemWindows(insets);
+//    }
+
+//    @Override
+//    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+//            if (!useWindowInsetsAnimation && (DialogX.useActivityLayoutTranslationNavigationBar || (getParentDialog() != null && getParentDialog().getDialogImplMode() != DialogX.IMPL_MODE.VIEW))) {
+//                paddingView(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
+//                log("#dispatchApplyWindowInsets paddingView: b=" + insets.getSystemWindowInsetBottom());
+//            }
+//        }
+//        return super.dispatchApplyWindowInsets(insets);
+//    }
+
+    public void paddingView(Insets insets) {
     }
 
     @RequiresApi(api = Build.VERSION_CODES.Q)
-    public void paddingView(Insets insets) {
+    public void paddingViewOld(Insets insets) {
         if (insets != null) {
             paddingView(insets.left, insets.top, insets.right, insets.bottom);
             log("#paddingView(insets) paddingView: b=" + insets.bottom);
@@ -134,6 +190,9 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
     }
 
     public void paddingView(WindowInsets insets) {
+    }
+
+    public void paddingViewOld(WindowInsets insets) {
         if (!isAttachedToWindow()) {
             getDynamicWindowInsetsAnimationListener(parentKey).remove(dynamicWindowInsetsAnimationListener);
             return;
@@ -182,36 +241,36 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         if (!isInEditMode()) {
-            final ViewParent parent = getParent();
-            if (parent instanceof View) {
-                ViewCompat.setFitsSystemWindows(this, ViewCompat.getFitsSystemWindows((View) parent));
-            }
-            ViewCompat.requestApplyInsets(this);
+//            final ViewParent parent = getParent();
+//            if (parent instanceof View) {
+//                ViewCompat.setFitsSystemWindows(this, ViewCompat.getFitsSystemWindows((View) parent));
+//            }
+//            ViewCompat.requestApplyInsets(this);
 
             if (getParentDialog() == null || getParentDialog().getOwnActivity() == null) return;
 
-            View decorView = (View) getParent();
-            if (decorView != null) {
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
-                    parentKey = Integer.toHexString(decorView.hashCode());
-                    getDynamicWindowInsetsAnimationListener(parentKey).add(dynamicWindowInsetsAnimationListener = new DynamicWindowInsetsAnimationListener() {
-                        @Override
-                        public void onChange(WindowInsets windowInsets) {
-                            paddingView(windowInsets);
-                        }
-                    });
-                    paddingWindowInsetsByDefault();
-                    initDynamicSafeAreaListener();
-                } else {
-                    decorView.getViewTreeObserver().addOnGlobalLayoutListener(decorViewLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
-                        @Override
-                        public void onGlobalLayout() {
-                            paddingWindowInsetsByDefault();
-                        }
-                    });
-                    decorViewLayoutListener.onGlobalLayout();
-                }
-            }
+//            View decorView = (View) getParent();
+//            if (decorView != null) {
+//                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+//                    parentKey = Integer.toHexString(decorView.hashCode());
+//                    getDynamicWindowInsetsAnimationListener(parentKey).add(dynamicWindowInsetsAnimationListener = new DynamicWindowInsetsAnimationListener() {
+//                        @Override
+//                        public void onChange(WindowInsets windowInsets) {
+//                            paddingView(windowInsets);
+//                        }
+//                    });
+//                    paddingWindowInsetsByDefault();
+//                    initDynamicSafeAreaListener();
+//                } else {
+//                    decorView.getViewTreeObserver().addOnGlobalLayoutListener(decorViewLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
+//                        @Override
+//                        public void onGlobalLayout() {
+//                            paddingWindowInsetsByDefault();
+//                        }
+//                    });
+//                    decorViewLayoutListener.onGlobalLayout();
+//                }
+//            }
 
             if (onLifecycleCallBack != null) {
                 onLifecycleCallBack.onShow();
@@ -238,8 +297,11 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
 
     boolean useWindowInsetsAnimation = false;
 
+
+    private void initDynamicSafeAreaListener() {}
+
     @RequiresApi(api = Build.VERSION_CODES.KITKAT_WATCH)
-    private void initDynamicSafeAreaListener() {
+    private void initDynamicSafeAreaListenerOld() {
         View decorView = (View) getParent();
         if (decorView != null) {
             try {
@@ -269,13 +331,15 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
 
     private void paddingWindowInsetsByDefault() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            paddingView(getRootWindowInsets());
+//            paddingView(getRootWindowInsets());
         } else {
-            getWindowInsetsByDisplayMetrics();
+//            getWindowInsetsByDisplayMetrics();
         }
     }
 
-    private void getWindowInsetsByDisplayMetrics() {
+    private void getWindowInsetsByDisplayMetrics() {}
+
+    private void getWindowInsetsByDisplayMetricsOld() {
         if (getParentDialog() == null || getParentDialog().getOwnActivity() == null) return;
         DisplayMetrics displayMetrics = new DisplayMetrics();
         getParentDialog().getOwnActivity().getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
@@ -353,10 +417,10 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
     public void requestFocusOnResume() {
         log("#requestFocusOnResume");
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && getRootWindowInsets() != null && getRootWindowInsets().getStableInsets() != null) {
-            paddingView(getRootWindowInsets().getStableInsets());
+//            paddingView(getRootWindowInsets().getStableInsets());
         }
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
-            initDynamicSafeAreaListener();
+//            initDynamicSafeAreaListener();
         }
         View findFocusView = findFocus();
         if (findFocusView != null && findFocusView != this) {
@@ -375,7 +439,9 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
 
     protected Rect unsafePlace = new Rect();
 
-    private void paddingView(int left, int top, int right, int bottom) {
+    private void paddingView(int left, int top, int right, int bottom) {}
+
+    private void paddingViewOld(int left, int top, int right, int bottom) {
         unsafePlace = new Rect(left, top, right, bottom);
         if (onSafeInsetsChangeListener != null) onSafeInsetsChangeListener.onChange(unsafePlace);
         MaxRelativeLayout bkgView = findViewById(R.id.bkg);
@@ -423,7 +489,7 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
     public DialogXBaseRelativeLayout setAutoUnsafePlacePadding(boolean autoUnsafePlacePadding) {
         this.autoUnsafePlacePadding = autoUnsafePlacePadding;
         if (!autoUnsafePlacePadding) {
-            setPadding(extraPadding[0], extraPadding[1], extraPadding[2], extraPadding[3]);
+//            setPadding(extraPadding[0], extraPadding[1], extraPadding[2], extraPadding[3]);
         }
         return this;
     }

+ 315 - 0
DialogX/src/main/java/com/kongzue/dialogx/util/views/FitSystemBarUtils.java

@@ -0,0 +1,315 @@
+package com.kongzue.dialogx.util.views;
+
+
+import static androidx.core.view.WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE;
+
+import android.graphics.Rect;
+import android.os.Build;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.core.graphics.Insets;
+import androidx.core.view.DisplayCutoutCompat;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsAnimationCompat;
+import androidx.core.view.WindowInsetsCompat;
+
+import java.util.List;
+
+public class FitSystemBarUtils {
+
+    //当前是否正在平滑填充中
+    private boolean inSmoothingPadding = false;
+
+    public boolean isInSmoothingPadding() {
+        return inSmoothingPadding;
+    }
+
+    //是否需要处理挖孔屏,刘海屏
+    public boolean safeCutOutPadding = true;
+
+    //是否需要平滑填充,仅在android R及以上生效,默认开启
+    public boolean smoothPadding = true;
+
+    private View contentView;
+
+    private CallBack callBack;
+
+    /**
+     * 绑定到View
+     *
+     * @param view 指定View
+     */
+    public static FitSystemBarUtils attachView(View view) {
+        return attachView(view, new CallBack() {
+            @Override
+            public boolean isEnable(Orientation orientation) {
+                return true;
+            }
+
+            @Override
+            public void unsafeRect(int start, int top, int end, int bottom) {
+
+            }
+
+            @Override
+            public int initialPadding(Orientation orientation) {
+                return 0;
+            }
+        });
+    }
+
+    /**
+     * 绑定到View
+     *
+     * @param view     指定View
+     * @param callBack 用于判断是否需要某条边的padding,会非常频繁的调用,所以不要在里面做需要耗时的操作,以免卡UI线程
+     */
+    public static FitSystemBarUtils attachView(View view, CallBack callBack) {
+        return new FitSystemBarUtils(view, callBack);
+    }
+
+
+    /**
+     * 绑定到View
+     *
+     * @param view   指定View
+     * @param start  是否需要paddingStart
+     * @param top    是否需要paddingTop
+     * @param end    是否需要paddingEnd
+     * @param bottom 是否需要paddingBottom
+     */
+    public static FitSystemBarUtils attachView(
+            View view,
+            boolean start,
+            boolean top,
+            boolean end,
+            boolean bottom
+    ) {
+        return attachView(view, new CallBack() {
+            @Override
+            public boolean isEnable(Orientation orientation) {
+                switch (orientation) {
+                    case Start:
+                        return start;
+                    case Top:
+                        return top;
+                    case End:
+                        return end;
+                    case Bottom:
+                        return bottom;
+                }
+                return false;
+            }
+
+            @Override
+            public void unsafeRect(int start, int top, int end, int bottom) {
+
+            }
+
+            @Override
+            public int initialPadding(Orientation orientation) {
+                return 0;
+            }
+        });
+    }
+
+    private FitSystemBarUtils() {
+    }
+
+    public FitSystemBarUtils(View view, CallBack callBack) {
+//        view.setFitsSystemWindows(true);
+        contentView = view;
+        this.callBack = callBack;
+        applyWindowInsets();
+    }
+
+    public void applyWindowInsets() {
+//        view.fitsSystemWindows = true
+        //创建原始padding的快照
+        RelativePadding initialPadding = new RelativePadding(
+                ViewCompat.getPaddingStart(contentView),
+                contentView.getPaddingTop(),
+                ViewCompat.getPaddingEnd(contentView),
+                contentView.getPaddingBottom()
+        );
+        //不带平滑变化的
+        ViewCompat.setOnApplyWindowInsetsListener(contentView, (view, insets) -> {
+            if (inSmoothingPadding) return insets;
+            formatInsets(insets, new RelativePadding(initialPadding));
+            return insets;
+        });
+        //带平滑变化的,但是支支持android R及以上
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            ViewCompat.setWindowInsetsAnimationCallback(contentView,
+                    new WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
+
+                        @NonNull
+                        @Override
+                        public WindowInsetsCompat onProgress(
+                                @NonNull WindowInsetsCompat insets,
+                                @NonNull List<WindowInsetsAnimationCompat> runningAnimations
+                        ) {
+                            if (smoothPadding) {
+                                formatInsets(insets, new RelativePadding(initialPadding));
+                            }
+                            return insets;
+                        }
+
+                        @Override
+                        public void onEnd(@NonNull WindowInsetsAnimationCompat animation) {
+                            inSmoothingPadding = false;
+                            super.onEnd(animation);
+                        }
+
+                        @Override
+                        public void onPrepare(@NonNull WindowInsetsAnimationCompat animation) {
+                            inSmoothingPadding = smoothPadding;
+                            super.onPrepare(animation);
+                        }
+                    });
+        }
+
+        if (ViewCompat.isAttachedToWindow(contentView)) {
+            ViewCompat.requestApplyInsets(contentView);
+        } else {
+            contentView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+                @Override
+                public void onViewAttachedToWindow(View view) {
+                    view.removeOnAttachStateChangeListener(this);
+                    ViewCompat.requestApplyInsets(view);
+                }
+
+                @Override
+                public void onViewDetachedFromWindow(View view) {
+
+                }
+
+            });
+        }
+    }
+
+    /**
+     * 针对不同版本处理Insets
+     */
+    private void formatInsets(WindowInsetsCompat insetsCompat, RelativePadding initialPadding) {
+        int cutoutPaddingLeft = 0;
+        int cutoutPaddingTop = 0;
+        int cutoutPaddingRight = 0;
+        int cutoutPaddingBottom = 0;
+
+        int systemWindowInsetLeft;
+        int systemWindowInsetTop;
+        int systemWindowInsetRight;
+        int systemWindowInsetBottom;
+
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
+            if (safeCutOutPadding) {
+                DisplayCutoutCompat displayCutout = insetsCompat.getDisplayCutout();
+                if (null != displayCutout) {
+                    cutoutPaddingTop = displayCutout.getSafeInsetTop();
+                    cutoutPaddingLeft = displayCutout.getSafeInsetLeft();
+                    cutoutPaddingRight = displayCutout.getSafeInsetRight();
+                    cutoutPaddingBottom = displayCutout.getSafeInsetRight();
+                }
+            }
+        }
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
+            Insets systemBars = insetsCompat.getInsets(WindowInsetsCompat.Type.systemBars());
+            Insets ime = insetsCompat.getInsets(WindowInsetsCompat.Type.ime());
+            Insets maxInsets = androidx.core.graphics.Insets.max(ime, systemBars);
+            systemWindowInsetLeft = systemBars.left;
+            systemWindowInsetRight = systemBars.right;
+            systemWindowInsetTop = systemBars.top;
+            systemWindowInsetBottom = maxInsets.bottom;
+        } else {
+            systemWindowInsetLeft = insetsCompat.getSystemWindowInsetLeft();
+            systemWindowInsetRight = insetsCompat.getSystemWindowInsetRight();
+            systemWindowInsetTop = insetsCompat.getSystemWindowInsetTop();
+            systemWindowInsetBottom = insetsCompat.getSystemWindowInsetBottom();
+        }
+
+        if (callBack.isEnable(Orientation.Top)) {
+            initialPadding.top += Math.max(systemWindowInsetTop, cutoutPaddingTop);
+        }
+        if (callBack.isEnable(Orientation.Bottom)) {
+            initialPadding.bottom += Math.max(systemWindowInsetBottom, cutoutPaddingBottom);
+        }
+
+        boolean isRtl =
+                ViewCompat.getLayoutDirection(contentView) == ViewCompat.LAYOUT_DIRECTION_RTL;
+        if (callBack.isEnable(Orientation.Start)) {
+            if (isRtl) {
+                initialPadding.start += Math.max(systemWindowInsetRight, cutoutPaddingRight);
+            } else {
+                initialPadding.start += Math.max(systemWindowInsetLeft, cutoutPaddingLeft);
+            }
+        }
+        if (callBack.isEnable(Orientation.End)) {
+            if (isRtl) {
+                initialPadding.end += Math.max(systemWindowInsetLeft, cutoutPaddingLeft);
+            } else {
+                initialPadding.end += Math.max(systemWindowInsetRight, cutoutPaddingRight);
+            }
+        }
+        //加上用户自定义的
+        initialPadding.start += callBack.initialPadding(Orientation.Start);
+        initialPadding.top += callBack.initialPadding(Orientation.Top);
+        initialPadding.end += callBack.initialPadding(Orientation.End);
+        initialPadding.bottom += callBack.initialPadding(Orientation.Bottom);
+
+        initialPadding.applyToView(contentView);
+        //四边 非安全区 传递回去
+        callBack.unsafeRect(
+                initialPadding.start,
+                initialPadding.top,
+                initialPadding.end,
+                initialPadding.bottom
+        );
+
+    }
+
+    public interface CallBack {
+
+        //是否启用指定边的insets
+        boolean isEnable(Orientation orientation);
+
+        //非安全区
+        void unsafeRect(int start, int top, int end, int bottom);
+
+        //用户自定义的padding
+        int initialPadding(Orientation orientation);
+    }
+
+    public static class RelativePadding {
+        int start;
+        int top;
+        int end;
+        int bottom;
+
+        public RelativePadding(int start, int top, int end, int bottom) {
+            this.start = start;
+            this.top = top;
+            this.end = end;
+            this.bottom = bottom;
+        }
+
+        public RelativePadding(RelativePadding other) {
+            start = other.start;
+            top = other.top;
+            end = other.end;
+            bottom = other.bottom;
+        }
+
+        /**
+         * Applies this relative padding to the view.
+         */
+        public void applyToView(View view) {
+            ViewCompat.setPaddingRelative(view, start, top, end, bottom);
+        }
+    }
+
+    enum Orientation {
+        Start, Top, End, Bottom
+    }
+}