Browse Source

0.0.48.beta22 ready
- BottomDialog 以及 BottomMenu 各主题全部提供 Ok、Cancel、Other 三个按钮,此前该设置受限于主题样式,仅在 Material、Material You 两个主题下提供三个按钮,在其他主题中只提供了取消按钮;
- AGT 版本升级;

⚠️ 以下非公开的内部组件或方法将在未来的版本废弃:
- BaseDialog.getContext()
- com.kongzue.dialogx.util.views.BlurView

Kongzue 2 years ago
parent
commit
2fe0f06833

+ 36 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -93,6 +93,42 @@
       <option name="IGNORE_POINT_TO_ITSELF" value="false" />
       <option name="myAdditionalJavadocTags" value="hide,date" />
     </inspection_tool>
+    <inspection_tool class="JavadocDeclaration" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="ADDITIONAL_TAGS" value="hide,date,Deprecated" />
+    </inspection_tool>
     <inspection_tool class="MapOrSetKeyShouldOverrideHashCodeEquals" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="MissingJavadoc" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="PACKAGE_SETTINGS">
+        <Options>
+          <option name="ENABLED" value="false" />
+        </Options>
+      </option>
+      <option name="MODULE_SETTINGS">
+        <Options>
+          <option name="ENABLED" value="false" />
+        </Options>
+      </option>
+      <option name="TOP_LEVEL_CLASS_SETTINGS">
+        <Options>
+          <option name="ENABLED" value="false" />
+        </Options>
+      </option>
+      <option name="INNER_CLASS_SETTINGS">
+        <Options>
+          <option name="ENABLED" value="false" />
+        </Options>
+      </option>
+      <option name="METHOD_SETTINGS">
+        <Options>
+          <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
+          <option name="ENABLED" value="false" />
+        </Options>
+      </option>
+      <option name="FIELD_SETTINGS">
+        <Options>
+          <option name="ENABLED" value="false" />
+        </Options>
+      </option>
+    </inspection_tool>
   </profile>
 </component>

+ 54 - 47
DialogX/src/main/java/com/kongzue/dialogx/dialogs/BottomDialog.java

@@ -28,6 +28,7 @@ import androidx.lifecycle.Lifecycle;
 import com.kongzue.dialogx.DialogX;
 import com.kongzue.dialogx.R;
 import com.kongzue.dialogx.interfaces.BaseDialog;
+import com.kongzue.dialogx.interfaces.BlurViewType;
 import com.kongzue.dialogx.interfaces.BottomDialogSlideEventLifecycleCallback;
 import com.kongzue.dialogx.interfaces.DialogConvertViewInterface;
 import com.kongzue.dialogx.interfaces.DialogLifecycleCallback;
@@ -47,6 +48,9 @@ import com.kongzue.dialogx.util.views.BottomDialogScrollView;
 import com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout;
 import com.kongzue.dialogx.util.views.MaxRelativeLayout;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * @author: Kongzue
  * @github: https://github.com/kongzue/
@@ -252,7 +256,6 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
         public DialogXBaseRelativeLayout boxRoot;
         public RelativeLayout boxBkg;
         public MaxRelativeLayout bkg;
-        public ViewGroup boxBody;
         public ImageView imgTab;
         public TextView txtDialogTitle;
         public ScrollController scrollView;
@@ -261,20 +264,22 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
         public View imgSplit;
         public RelativeLayout boxList;
         public RelativeLayout boxCustom;
-        public BlurView blurView;
         public ViewGroup boxCancel;
-        public TextView btnCancel;
-        public BlurView cancelBlurView;
+        public ImageView splitSelectPositive;
+        public ImageView splitSelectOther;
+
+        private LinearLayout boxButton;
+        private TextView btnSelectNegative;
+        private TextView btnSelectOther;
+        private TextView btnSelectPositive;
 
-        public TextView btnSelectOther;
-        public TextView btnSelectPositive;
+        private List<View> blurViews;
 
         public DialogImpl(View convertView) {
             if (convertView == null) return;
             boxRoot = convertView.findViewById(R.id.box_root);
             boxBkg = convertView.findViewById(R.id.box_bkg);
             bkg = convertView.findViewById(R.id.bkg);
-            boxBody = convertView.findViewWithTag("blurBody");
             imgTab = convertView.findViewById(R.id.img_tab);
             txtDialogTitle = convertView.findViewById(R.id.txt_dialog_title);
             scrollView = convertView.findViewById(R.id.scrollView);
@@ -283,12 +288,15 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
             imgSplit = convertView.findViewWithTag("split");
             boxList = convertView.findViewById(R.id.box_list);
             boxCustom = convertView.findViewById(R.id.box_custom);
-            blurView = convertView.findViewById(R.id.blurView);
+
             boxCancel = convertView.findViewWithTag("cancelBox");
-            btnCancel = convertView.findViewWithTag("cancel");
 
+            boxButton = convertView.findViewById(R.id.box_button);
+            btnSelectNegative = convertView.findViewById(R.id.btn_selectNegative);
             btnSelectOther = convertView.findViewById(R.id.btn_selectOther);
             btnSelectPositive = convertView.findViewById(R.id.btn_selectPositive);
+            splitSelectPositive = convertView.findViewWithTag("imgPositiveButtonSplit");
+            splitSelectOther = convertView.findViewWithTag("imgOtherButtonSplit");
 
             init();
             dialogImpl = this;
@@ -326,7 +334,7 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
             if (cancelText == null) cancelText = DialogX.cancelButtonText;
 
             txtDialogTitle.getPaint().setFakeBoldText(true);
-            if (btnCancel != null) btnCancel.getPaint().setFakeBoldText(true);
+            if (btnSelectNegative != null) btnSelectNegative.getPaint().setFakeBoldText(true);
             if (btnSelectPositive != null) btnSelectPositive.getPaint().setFakeBoldText(true);
             if (btnSelectOther != null) btnSelectOther.getPaint().setFakeBoldText(true);
 
@@ -351,31 +359,6 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
 
                     onDialogShow();
 
-                    boxRoot.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            if (style.messageDialogBlurSettings() != null && style.messageDialogBlurSettings().blurBackground() && boxBody != null && boxCancel != null) {
-                                int blurFrontColor = getResources().getColor(style.messageDialogBlurSettings().blurForwardColorRes(isLightTheme()));
-                                blurView = new BlurView(getOwnActivity(), null);
-                                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(bkg.getWidth(), bkg.getHeight());
-                                blurView.setOverlayColor(backgroundColor == -1 ? blurFrontColor : backgroundColor);
-                                blurView.setOverrideOverlayColor(backgroundColor != -1);
-                                blurView.setTag("blurView");
-                                blurView.setRadiusPx(style.messageDialogBlurSettings().blurBackgroundRoundRadiusPx());
-                                boxBody.addView(blurView, 0, params);
-
-                                cancelBlurView = new BlurView(getOwnActivity(), null);
-                                RelativeLayout.LayoutParams cancelButtonLp = new RelativeLayout.LayoutParams(boxCancel.getWidth(), boxCancel.getHeight());
-                                cancelBlurView.setOverlayColor(backgroundColor == -1 ? blurFrontColor : backgroundColor);
-                                cancelBlurView.setOverrideOverlayColor(backgroundColor != -1);
-                                cancelBlurView.setTag("blurView");
-                                cancelBlurView.setRadiusPx(style.messageDialogBlurSettings().blurBackgroundRoundRadiusPx());
-                                boxCancel.addView(cancelBlurView, 0, cancelButtonLp);
-                            }
-                            setLifecycleState(Lifecycle.State.RESUMED);
-                        }
-                    });
-
                     refreshUI();
                 }
 
@@ -392,8 +375,8 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
                 }
             });
 
-            if (btnCancel != null) {
-                btnCancel.setOnClickListener(new View.OnClickListener() {
+            if (btnSelectNegative != null) {
+                btnSelectNegative.setOnClickListener(new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
                         buttonSelectResult = BUTTON_SELECT_RESULT.BUTTON_CANCEL;
@@ -483,6 +466,18 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
             onDialogInit();
         }
 
+        private void findAllBlurView(View v) {
+            if (v instanceof BlurViewType) {
+                blurViews.add(v);
+            }
+            if (v instanceof ViewGroup) {
+                ViewGroup group = (ViewGroup) v;
+                for (int i = 0; i < group.getChildCount(); i++) {
+                    findAllBlurView(group.getChildAt(i));
+                }
+            }
+        }
+
         @Override
         public void refreshView() {
             if (boxRoot == null || getOwnActivity() == null) {
@@ -491,16 +486,22 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
             boxRoot.setRootPadding(screenPaddings[0], screenPaddings[1], screenPaddings[2], screenPaddings[3]);
             if (backgroundColor != -1) {
                 tintColor(bkg, backgroundColor);
-                if (blurView != null && cancelBlurView != null) {
-                    blurView.setOverlayColor(backgroundColor);
-                    blurView.setOverrideOverlayColor(true);
-                    cancelBlurView.setOverlayColor(backgroundColor);
-                    cancelBlurView.setOverrideOverlayColor(true);
-                }
-
                 tintColor(btnSelectOther, backgroundColor);
-                tintColor(btnCancel, backgroundColor);
+                tintColor(btnSelectNegative, backgroundColor);
                 tintColor(btnSelectPositive, backgroundColor);
+
+                if (style.messageDialogBlurSettings() != null && style.messageDialogBlurSettings().blurBackground()) {
+                    if (blurViews == null) {
+                        blurViews = new ArrayList<>();
+                        findAllBlurView(dialogView);
+                    }
+
+                    if (blurViews != null) {
+                        for (View blurView : blurViews) {
+                            ((BlurViewType) blurView).setOverlayColor(backgroundColor);
+                        }
+                    }
+                }
             }
 
             showText(txtDialogTitle, title);
@@ -508,7 +509,7 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
 
             useTextInfo(txtDialogTitle, titleTextInfo);
             useTextInfo(txtDialogTip, messageTextInfo);
-            useTextInfo(btnCancel, cancelTextInfo);
+            useTextInfo(btnSelectNegative, cancelTextInfo);
             useTextInfo(btnSelectOther, otherTextInfo);
             useTextInfo(btnSelectPositive, okTextInfo);
 
@@ -606,8 +607,14 @@ public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog
             }
 
             showText(btnSelectPositive, okText);
-            showText(btnCancel, cancelText);
+            showText(btnSelectNegative, cancelText);
             showText(btnSelectOther, otherText);
+            if (splitSelectPositive != null) {
+                splitSelectPositive.setVisibility(btnSelectPositive.getVisibility());
+            }
+            if (splitSelectOther != null) {
+                splitSelectOther.setVisibility(btnSelectOther.getVisibility());
+            }
 
             onDialogRefreshUI();
         }

+ 2 - 2
DialogX/src/main/java/com/kongzue/dialogx/dialogs/GuideDialog.java

@@ -538,7 +538,7 @@ public class GuideDialog extends CustomDialog {
             getDialogImpl().boxCustom.setOnClickListener(null);
             getDialogImpl().boxCustom.setClickable(false);
             
-            ImageView imageView = new ImageView(getContext());
+            ImageView imageView = new ImageView(getOwnActivity());
             imageView.setImageDrawable(tipImage);
             imageView.setAdjustViewBounds(true);
             imageView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
@@ -551,7 +551,7 @@ public class GuideDialog extends CustomDialog {
             onBindView.bindParent(getDialogImpl().boxCustom, me);
         }
         if (getOnStageLightPathClickListener() != null && baseView != null) {
-            stageLightPathStub = new View(getContext());
+            stageLightPathStub = new View(getOwnActivity());
             stageLightPathStub.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {

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

@@ -209,14 +209,14 @@ public abstract class BaseDialog implements LifecycleOwner {
                         dialogXFloatingWindowActivity.showDialogX(baseDialog.dialogKey());
                         return;
                     }
-                    Intent intent = new Intent(getContext(), DialogXFloatingWindowActivity.class);
+                    Intent intent = new Intent(getPrivateContext(), DialogXFloatingWindowActivity.class);
                     if (baseDialog.getOwnActivity() == null) {
                         intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
                     }
                     intent.putExtra("dialogXKey", baseDialog.dialogKey());
                     intent.putExtra("fromActivityUiStatus", baseDialog.getOwnActivity() == null ? 0 : (getDecorView(baseDialog.getOwnActivity()) == null ? 0 : getDecorView(baseDialog.getOwnActivity()).getSystemUiVisibility()));
-                    intent.putExtra("from", getContext().hashCode());
-                    getContext().startActivity(intent);
+                    intent.putExtra("from", getPrivateContext().hashCode());
+                    getPrivateContext().startActivity(intent);
                     int version = Integer.valueOf(Build.VERSION.SDK_INT);
                     if (version > 5 && baseDialog.getOwnActivity() != null) {
                         baseDialog.getOwnActivity().overridePendingTransition(0, 0);
@@ -441,7 +441,17 @@ public abstract class BaseDialog implements LifecycleOwner {
         return activityWeakReference.get();
     }
 
+    /**
+     * @Deprecated 已废弃,将在未来版本删除此方法,建议使用 {@link #getOwnActivity()} 替代此方法
+     *
+     * @return  获取上下文
+     */
+    @Deprecated
     public static Context getContext() {
+        return getPrivateContext();
+    }
+
+    private static Context getPrivateContext() {
         Activity activity = getTopActivity();
         if (activity == null) {
             Context applicationContext = getApplicationContext();

+ 5 - 0
DialogX/src/main/java/com/kongzue/dialogx/interfaces/BlurViewType.java

@@ -0,0 +1,5 @@
+package com.kongzue.dialogx.interfaces;
+
+public interface BlurViewType {
+    void setOverlayColor(int color);
+}

+ 3 - 11
DialogX/src/main/java/com/kongzue/dialogx/util/views/BlurView.java

@@ -35,15 +35,14 @@ import com.kongzue.dialogx.DialogX;
 import com.kongzue.dialogx.R;
 import com.kongzue.dialogx.interfaces.BaseDialog;
 
+@Deprecated
 public class BlurView extends View {
+
     private float mDownsampleFactor = 4;
     private int mOverlayColor = Color.WHITE;
     private float mBlurRadius = 35;
     private boolean overrideOverlayColor = false;
-    
     private float mRadius = 0;
-    private Path mBoundPath = null;
-    
     private boolean mDirty;
     private Bitmap mBitmapToBlur, mBlurredBitmap;
     private Canvas mBlurringCanvas;
@@ -52,19 +51,13 @@ public class BlurView extends View {
     private Allocation mBlurInput, mBlurOutput;
     private boolean mIsRendering;
     private final Rect mRectSrc = new Rect(), mRectDst = new Rect();
-    // mDecorView should be the root view of the activity (even if you are on a different window like a dialog)
     private View mDecorView;
-    // If the view is on different root view (usually means we are on a PopupWindow),
-    // we need to manually call invalidate() in onPreDraw(), otherwise we will not be able to see the changes
     private boolean mDifferentRoot;
     private static int RENDERING_COUNT;
     
     private Paint mPaint;
     private RectF mRectF;
     
-    private Bitmap mRoundBitmap;
-    private Canvas mTmpCanvas;
-    
     public BlurView(Context context, AttributeSet attrs) {
         super(context, attrs);
         init(context, attrs);
@@ -300,8 +293,7 @@ public class BlurView extends View {
                 getLocationOnScreen(locations);
                 x += locations[0];
                 y += locations[1];
-                
-                // just erase transparent
+
                 mBitmapToBlur.eraseColor(mOverlayColor & 0xffffff);
                 
                 int rc = mBlurringCanvas.save();

+ 1 - 0
DialogXIOSStyle/build.gradle

@@ -24,6 +24,7 @@ artifacts {
     archives sourcesJar
 }
 dependencies {
+    implementation 'androidx.appcompat:appcompat:1.3.0+'
     implementation fileTree(dir: "libs", include: ["*.jar"])
     implementation project(path: ':DialogX')
     compileOnly project(path: ':DialogXInterface')

+ 554 - 0
DialogXIOSStyle/src/main/java/com/kongzue/dialogx/style/views/BlurLinearLayout.java

@@ -0,0 +1,554 @@
+package com.kongzue.dialogx.style.views;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.os.Build;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.ScriptIntrinsicBlur;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.view.ViewTreeObserver;
+import android.widget.LinearLayout;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.interfaces.BaseDialog;
+import com.kongzue.dialogx.interfaces.BlurViewType;
+import com.kongzue.dialogx.iostheme.R;
+
+public class BlurLinearLayout extends LinearLayout implements BlurViewType {
+
+    private float mDownSampleFactor = 4;
+    private int mOverlayColor = Color.WHITE;
+    private float mBlurRadius = 35;
+    private boolean overrideOverlayColor = false;
+
+    private float mRadius = 0;
+
+    private boolean mDirty;
+    private Bitmap mBitmapToBlur, mBlurredBitmap;
+    private Canvas mBlurringCanvas;
+    private RenderScript mRenderScript;
+    private ScriptIntrinsicBlur mBlurScript;
+    private Allocation mBlurInput, mBlurOutput;
+    private boolean mIsRendering;
+    private final Rect mRectSrc = new Rect(), mRectDst = new Rect();
+    private View mDecorView;
+    private boolean mDifferentRoot;
+    private static int RENDERING_COUNT;
+
+    private Paint mPaint;
+    private RectF mRectF;
+
+    public BlurLinearLayout(Context context) {
+        super(context);
+        init(context, null);
+    }
+
+    public BlurLinearLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context, attrs);
+    }
+
+    public BlurLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context, attrs);
+    }
+
+    private boolean isInit = false;
+
+    Paint cutPaint;
+    Paint overlayPaint;
+
+    private void init(Context context, AttributeSet attrs) {
+        if (!isInit) {
+            TypedArray a = context.obtainStyledAttributes(attrs, com.kongzue.dialogx.R.styleable.RealtimeBlurView);
+            mBlurRadius = a.getDimension(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeBlurRadius, dip2px(35));
+            mDownSampleFactor = a.getFloat(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeDownsampleFactor, 4);
+            mOverlayColor = a.getColor(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeOverlayColor, getResources().getColor(R.color.dialogxIOSBkgLight));
+            mRadius = a.getDimension(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeRadius, dip2px(15));
+            a.recycle();
+
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
+                setOutlineProvider(new ViewOutlineProvider() {
+                    @Override
+                    public void getOutline(View view, Outline outline) {
+                        outline.setRoundRect(0, 0, view.getWidth(),view.getHeight(), mRadius);
+                    }
+                });
+                setClipToOutline(true);
+            }
+
+            mPaint = new Paint();
+            mPaint.setAntiAlias(true);
+            mRectF = new RectF();
+
+            cutPaint = new Paint();
+            cutPaint.setAntiAlias(true);
+            cutPaint.setColor(mOverlayColor);
+
+            overlayPaint = new Paint();
+            overlayPaint.setAntiAlias(true);
+
+            isInit = true;
+            if (!isCompatMode()) {
+                setOutlineProvider(new ViewOutlineProvider() {
+                    @Override
+                    public void getOutline(View view, Outline outline) {
+                        outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mRadius);
+                    }
+                });
+                setClipToOutline(true);
+            }
+        }
+    }
+
+    private boolean isCompatMode() {
+        return Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;
+    }
+
+    public void setBlurRadius(float radius) {
+        if (mBlurRadius != radius) {
+            mBlurRadius = radius;
+            mDirty = true;
+            invalidate();
+        }
+    }
+
+    public void setRadiusPx(float r) {
+        if (mRadius != r) {
+            mRadius = r;
+            mDirty = true;
+            invalidate();
+        }
+    }
+
+    public void setDownsampleFactor(float factor) {
+        if (factor <= 0) {
+            throw new IllegalArgumentException("Downsample factor must be greater than 0.");
+        }
+
+        if (mDownSampleFactor != factor) {
+            mDownSampleFactor = factor;
+            mDirty = true; // may also change blur radius
+            releaseBitmap();
+            invalidate();
+        }
+    }
+
+    public void setOverlayColor(int color) {
+        if (mOverlayColor != color) {
+            mOverlayColor = color;
+            invalidate();
+        }
+    }
+
+    private void releaseBitmap() {
+        if (mBlurInput != null) {
+            mBlurInput.destroy();
+            mBlurInput = null;
+        }
+        if (mBlurOutput != null) {
+            mBlurOutput.destroy();
+            mBlurOutput = null;
+        }
+        if (mBitmapToBlur != null) {
+            mBitmapToBlur.recycle();
+            mBitmapToBlur = null;
+        }
+        if (mBlurredBitmap != null) {
+            mBlurredBitmap.recycle();
+            mBlurredBitmap = null;
+        }
+    }
+
+    private void releaseScript() {
+        if (mRenderScript != null) {
+            mRenderScript.destroy();
+            mRenderScript = null;
+        }
+        if (mBlurScript != null) {
+            mBlurScript.destroy();
+            mBlurScript = null;
+        }
+    }
+
+    protected void release() {
+        releaseBitmap();
+        releaseScript();
+    }
+
+    protected boolean prepare() {
+        if (mBlurRadius == 0) {
+            release();
+            return false;
+        }
+
+        float downsampleFactor = mDownSampleFactor;
+
+        if (mDirty || mRenderScript == null) {
+            if (supportRenderScript && useBlur) {
+                if (mRenderScript == null) {
+                    try {
+                        mRenderScript = RenderScript.create(getContext());
+                        mBlurScript = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript));
+
+                    } catch (Exception e) {
+                        supportRenderScript = false;
+                        if (isDebug()) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+
+                mDirty = false;
+                float radius = mBlurRadius / downsampleFactor;
+                if (radius > 25) {
+                    downsampleFactor = downsampleFactor * radius / 25;
+                    radius = 25;
+                }
+                if (mBlurScript != null) mBlurScript.setRadius(radius);
+            }
+        }
+
+        final int width = getWidth();
+        final int height = getHeight();
+
+        int scaledWidth = Math.max(1, (int) (width / downsampleFactor));
+        int scaledHeight = Math.max(1, (int) (height / downsampleFactor));
+
+        if (mBlurringCanvas == null || mBlurredBitmap == null || mBlurredBitmap.getWidth() != scaledWidth || mBlurredBitmap.getHeight() != scaledHeight) {
+            releaseBitmap();
+
+            boolean r = false;
+            try {
+                mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
+                if (mBitmapToBlur == null) {
+                    return false;
+                }
+                mBlurringCanvas = new Canvas(mBitmapToBlur);
+
+                if (!supportRenderScript || !useBlur) {
+                    return true;
+                }
+
+                mBlurInput = Allocation.createFromBitmap(mRenderScript, mBitmapToBlur,
+                        Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT
+                );
+                mBlurOutput = Allocation.createTyped(mRenderScript, mBlurInput.getType());
+
+                mBlurredBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
+                if (mBlurredBitmap == null) {
+                    return false;
+                }
+
+                r = true;
+            } catch (Exception e) {
+                if (isDebug()) e.printStackTrace();
+            } finally {
+                if (!r) {
+                    releaseBitmap();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    protected void blur(Bitmap bitmapToBlur, Bitmap blurredBitmap) {
+        mBlurInput.copyFrom(bitmapToBlur);
+        mBlurScript.setInput(mBlurInput);
+        mBlurScript.forEach(mBlurOutput);
+        mBlurOutput.copyTo(blurredBitmap);
+    }
+
+    private final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            final int[] locations = new int[2];
+            Bitmap oldBmp = mBlurredBitmap;
+            View decor = mDecorView;
+            if (decor != null && isShown() && prepare()) {
+                boolean redrawBitmap = mBlurredBitmap != oldBmp;
+                decor.getLocationOnScreen(locations);
+                int x = -locations[0];
+                int y = -locations[1];
+
+                getLocationOnScreen(locations);
+                x += locations[0];
+                y += locations[1];
+
+                // just erase transparent
+                mBitmapToBlur.eraseColor(mOverlayColor & 0xffffff);
+
+                int rc = mBlurringCanvas.save();
+                mIsRendering = true;
+                RENDERING_COUNT++;
+                try {
+                    mBlurringCanvas.scale(1.f * mBitmapToBlur.getWidth() / getWidth(), 1.f * mBitmapToBlur.getHeight() / getHeight());
+                    mBlurringCanvas.translate(-x, -y);
+                    if (decor.getBackground() != null) {
+                        decor.getBackground().draw(mBlurringCanvas);
+                    }
+                    decor.draw(mBlurringCanvas);
+                } catch (Exception e) {
+                    if (isDebug()) e.printStackTrace();
+                } finally {
+                    mIsRendering = false;
+                    RENDERING_COUNT--;
+                    mBlurringCanvas.restoreToCount(rc);
+                }
+
+                blur(mBitmapToBlur, mBlurredBitmap);
+
+                if (redrawBitmap || mDifferentRoot) {
+                    invalidate();
+                }
+            }
+
+            return true;
+        }
+    };
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        Activity activity;
+        if (getContext() instanceof Activity) {
+            activity = (Activity) getContext();
+        } else {
+            activity = BaseDialog.getTopActivity();
+        }
+        ViewGroup decorView = ((ViewGroup) activity.getWindow().getDecorView());
+        if (decorView.getChildCount() >= 1) {
+            mDecorView = decorView.getChildAt(0);
+        }
+        if (mDecorView != null) {
+            log("mDecorView is ok.");
+            mDecorView.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
+            mDifferentRoot = mDecorView.getRootView() != getRootView();
+            if (mDifferentRoot) {
+                mDecorView.postInvalidate();
+            }
+        } else {
+            log("mDecorView is NULL.");
+            mDifferentRoot = false;
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if (mDecorView != null) {
+            mDecorView.getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
+        }
+        release();
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        if (isCompatMode()) {
+            drawBlurredBitmapCompat(canvas);
+        } else {
+            drawBlurredBitmap(canvas, mBlurredBitmap);
+        }
+        super.dispatchDraw(canvas);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        log("#draw");
+        if (!useBlur || !supportRenderScript) {
+            mRectF.right = getWidth();
+            mRectF.bottom = getHeight();
+            overlayPaint.setColor(needRemoveAlphaColor() ? removeAlphaColor(mOverlayColor) : mOverlayColor);
+            canvas.drawRoundRect(mRectF, mRadius, mRadius, overlayPaint);
+        } else {
+            if (!mIsRendering && RENDERING_COUNT <= 0) {
+                log("draw: ok");
+                super.draw(canvas);
+            }
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (isCompatMode()) {
+            drawBlurredBitmapCompat(canvas);
+        } else {
+            drawBlurredBitmap(canvas, mBlurredBitmap);
+        }
+        super.onDraw(canvas);
+    }
+
+    private void drawBlurredBitmapCompat(Canvas canvas) {
+        if (mBlurredBitmap != null) {
+            mRectDst.right = getWidth();
+            mRectDst.bottom = getHeight();
+            if (getWidth() > 0 && getHeight() > 0) {
+                Bitmap readyDrawBitmap = getRoundedCornerBitmap(resizeImage(mBlurredBitmap, getWidth(), getHeight()), mRectDst);
+                if (readyDrawBitmap != null) {
+                    canvas.drawBitmap(readyDrawBitmap, 0, 0, null);
+                } else {
+                    Bitmap overlyBitmap = drawOverlyColor(Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888));
+                    if (overlyBitmap != null) canvas.drawBitmap(overlyBitmap, 0, 0, null);
+                }
+            }
+        } else {
+            Bitmap overlyBitmap = drawOverlyColor(Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888));
+            if (overlyBitmap != null) canvas.drawBitmap(overlyBitmap, 0, 0, null);
+        }
+    }
+
+    protected void drawBlurredBitmap(Canvas canvas, Bitmap blurredBitmap) {
+        if (blurredBitmap != null) {
+            mRectSrc.right = blurredBitmap.getWidth();
+            mRectSrc.bottom = blurredBitmap.getHeight();
+            mRectDst.right = getWidth();
+            mRectDst.bottom = getHeight();
+            canvas.drawBitmap(blurredBitmap, mRectSrc, mRectDst, null);
+            canvas.drawColor(mOverlayColor);
+        } else {
+            Bitmap overlyBitmap = drawOverlyColor(Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888));
+            if (overlyBitmap != null) canvas.drawBitmap(overlyBitmap, 0, 0, null);
+        }
+    }
+
+    private Bitmap getRoundedCornerBitmap(Bitmap bitmap, Rect mRectDst) {
+        bitmap = drawOverlyColor(resizeImage(bitmap, mRectDst.width(), mRectDst.height()));
+        if (bitmap == null) return null;
+        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(output);
+        BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+        Paint paint = new Paint();
+        paint.setAntiAlias(true);
+        paint.setShader(bitmapShader);
+        canvas.drawRoundRect(new RectF(mRectDst), mRadius, mRadius, paint);
+        return output;
+    }
+
+    private Bitmap drawOverlyColor(Bitmap bitmap) {
+        if (bitmap != null) {
+            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(output);
+            Rect originRect = new Rect();
+            originRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
+            canvas.drawBitmap(bitmap, originRect, originRect, overlayPaint);
+            canvas.drawColor(needRemoveAlphaColor() ? removeAlphaColor(mOverlayColor) : mOverlayColor);
+            return output;
+        } else {
+            return null;
+        }
+    }
+
+    private Bitmap resizeImage(Bitmap bitmap, int newWidth, int newHeight) {
+        if (bitmap != null) {
+            int width = bitmap.getWidth();
+            int height = bitmap.getHeight();
+            float scaleWidth = ((float) newWidth) / width;
+            float scaleHeight = ((float) newHeight) / height;
+            Matrix matrix = new Matrix();
+            matrix.postScale(scaleWidth, scaleHeight);
+            return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
+        } else {
+            return null;
+        }
+    }
+
+    private static boolean supportRenderScript = false;
+    private boolean useBlur = true;
+
+    public boolean isUseBlur() {
+        return useBlur;
+    }
+
+    public BlurLinearLayout setUseBlur(boolean useBlur) {
+        this.useBlur = useBlur;
+        invalidate();
+        return this;
+    }
+
+    private boolean needRemoveAlphaColor() {
+        if (overrideOverlayColor) {
+            return false;
+        } else {
+            return !(supportRenderScript && useBlur);
+        }
+    }
+
+    private static int removeAlphaColor(int color) {
+        int alpha = 255;
+        int red = Color.red(color);
+        int green = Color.green(color);
+        int blue = Color.blue(color);
+        return Color.argb(alpha, red, green, blue);
+    }
+
+    private static int replaceAlphaColor(int color, int alpha) {
+        int red = Color.red(color);
+        int green = Color.green(color);
+        int blue = Color.blue(color);
+        return Color.argb(alpha, red, green, blue);
+    }
+
+    static {
+        /**
+         * 之所以需要启动一个新线程检测RenderScript是否可用的原因是不清楚Android什么时候对loadClass做了变更,
+         * 会直接抛出NoClassDefFoundError无法拦截,在主线程检测会导致程序直接闪退,因此改为异步检测。
+         * 检测后会给定(boolean)supportRenderScript用于判断时光支持
+         */
+        new Thread() {
+            @Override
+            public void run() {
+                try {
+                    BlurLinearLayout.class.getClassLoader().loadClass(RenderScript.class.getCanonicalName());
+                    supportRenderScript = true;
+                } catch (Throwable e) {
+                    if (isDebug()) {
+                        e.printStackTrace();
+                    }
+                    supportRenderScript = false;
+                }
+            }
+        }.start();
+    }
+
+    public static boolean DEBUGMODE = false;
+
+    static boolean isDebug() {
+        return DEBUGMODE && DialogX.DEBUGMODE;
+    }
+
+    private static void log(Object o) {
+        if (isDebug()) Log.i(">>>", "DialogX.BlurView: " + o.toString());
+    }
+
+    public static void error(Object o) {
+        if (isDebug()) Log.e(">>>", o.toString());
+    }
+
+    public BlurLinearLayout setOverrideOverlayColor(boolean overrideOverlayColor) {
+        log("setOverrideOverlayColor: " + overrideOverlayColor);
+        this.overrideOverlayColor = overrideOverlayColor;
+        return this;
+    }
+    private int dip2px(float dpValue) {
+        final float scale = getResources().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+}

+ 554 - 0
DialogXIOSStyle/src/main/java/com/kongzue/dialogx/style/views/BlurRelativeLayout.java

@@ -0,0 +1,554 @@
+package com.kongzue.dialogx.style.views;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.os.Build;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.ScriptIntrinsicBlur;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.view.ViewTreeObserver;
+import android.widget.RelativeLayout;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.interfaces.BaseDialog;
+import com.kongzue.dialogx.interfaces.BlurViewType;
+import com.kongzue.dialogx.iostheme.R;
+
+public class BlurRelativeLayout extends RelativeLayout implements BlurViewType {
+
+    private float mDownSampleFactor = 4;
+    private int mOverlayColor = Color.WHITE;
+    private float mBlurRadius = 35;
+    private boolean overrideOverlayColor = false;
+
+    private float mRadius = 0;
+
+    private boolean mDirty;
+    private Bitmap mBitmapToBlur, mBlurredBitmap;
+    private Canvas mBlurringCanvas;
+    private RenderScript mRenderScript;
+    private ScriptIntrinsicBlur mBlurScript;
+    private Allocation mBlurInput, mBlurOutput;
+    private boolean mIsRendering;
+    private final Rect mRectSrc = new Rect(), mRectDst = new Rect();
+    private View mDecorView;
+    private boolean mDifferentRoot;
+    private static int RENDERING_COUNT;
+
+    private Paint mPaint;
+    private RectF mRectF;
+
+    public BlurRelativeLayout(Context context) {
+        super(context);
+        init(context, null);
+    }
+
+    public BlurRelativeLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context, attrs);
+    }
+
+    public BlurRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context, attrs);
+    }
+
+    private boolean isInit = false;
+
+    Paint cutPaint;
+    Paint overlayPaint;
+
+    private void init(Context context, AttributeSet attrs) {
+        if (!isInit) {
+            TypedArray a = context.obtainStyledAttributes(attrs, com.kongzue.dialogx.R.styleable.RealtimeBlurView);
+            mBlurRadius = a.getDimension(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeBlurRadius, dip2px(35));
+            mDownSampleFactor = a.getFloat(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeDownsampleFactor, 4);
+            mOverlayColor = a.getColor(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeOverlayColor, getResources().getColor(R.color.dialogxIOSBkgLight));
+            mRadius = a.getDimension(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeRadius, dip2px(15));
+            a.recycle();
+
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
+                setOutlineProvider(new ViewOutlineProvider() {
+                    @Override
+                    public void getOutline(View view, Outline outline) {
+                        outline.setRoundRect(0, 0, view.getWidth(),view.getHeight(), mRadius);
+                    }
+                });
+                setClipToOutline(true);
+            }
+
+            mPaint = new Paint();
+            mPaint.setAntiAlias(true);
+            mRectF = new RectF();
+
+            cutPaint = new Paint();
+            cutPaint.setAntiAlias(true);
+            cutPaint.setColor(mOverlayColor);
+
+            overlayPaint = new Paint();
+            overlayPaint.setAntiAlias(true);
+
+            isInit = true;
+            if (!isCompatMode()) {
+                setOutlineProvider(new ViewOutlineProvider() {
+                    @Override
+                    public void getOutline(View view, Outline outline) {
+                        outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mRadius);
+                    }
+                });
+                setClipToOutline(true);
+            }
+        }
+    }
+
+    private boolean isCompatMode() {
+        return Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;
+    }
+
+    public void setBlurRadius(float radius) {
+        if (mBlurRadius != radius) {
+            mBlurRadius = radius;
+            mDirty = true;
+            invalidate();
+        }
+    }
+
+    public void setRadiusPx(float r) {
+        if (mRadius != r) {
+            mRadius = r;
+            mDirty = true;
+            invalidate();
+        }
+    }
+
+    public void setDownsampleFactor(float factor) {
+        if (factor <= 0) {
+            throw new IllegalArgumentException("Downsample factor must be greater than 0.");
+        }
+
+        if (mDownSampleFactor != factor) {
+            mDownSampleFactor = factor;
+            mDirty = true; // may also change blur radius
+            releaseBitmap();
+            invalidate();
+        }
+    }
+
+    public void setOverlayColor(int color) {
+        if (mOverlayColor != color) {
+            mOverlayColor = color;
+            invalidate();
+        }
+    }
+
+    private void releaseBitmap() {
+        if (mBlurInput != null) {
+            mBlurInput.destroy();
+            mBlurInput = null;
+        }
+        if (mBlurOutput != null) {
+            mBlurOutput.destroy();
+            mBlurOutput = null;
+        }
+        if (mBitmapToBlur != null) {
+            mBitmapToBlur.recycle();
+            mBitmapToBlur = null;
+        }
+        if (mBlurredBitmap != null) {
+            mBlurredBitmap.recycle();
+            mBlurredBitmap = null;
+        }
+    }
+
+    private void releaseScript() {
+        if (mRenderScript != null) {
+            mRenderScript.destroy();
+            mRenderScript = null;
+        }
+        if (mBlurScript != null) {
+            mBlurScript.destroy();
+            mBlurScript = null;
+        }
+    }
+
+    protected void release() {
+        releaseBitmap();
+        releaseScript();
+    }
+
+    protected boolean prepare() {
+        if (mBlurRadius == 0) {
+            release();
+            return false;
+        }
+
+        float downsampleFactor = mDownSampleFactor;
+
+        if (mDirty || mRenderScript == null) {
+            if (supportRenderScript && useBlur) {
+                if (mRenderScript == null) {
+                    try {
+                        mRenderScript = RenderScript.create(getContext());
+                        mBlurScript = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript));
+
+                    } catch (Exception e) {
+                        supportRenderScript = false;
+                        if (isDebug()) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+
+                mDirty = false;
+                float radius = mBlurRadius / downsampleFactor;
+                if (radius > 25) {
+                    downsampleFactor = downsampleFactor * radius / 25;
+                    radius = 25;
+                }
+                if (mBlurScript != null) mBlurScript.setRadius(radius);
+            }
+        }
+
+        final int width = getWidth();
+        final int height = getHeight();
+
+        int scaledWidth = Math.max(1, (int) (width / downsampleFactor));
+        int scaledHeight = Math.max(1, (int) (height / downsampleFactor));
+
+        if (mBlurringCanvas == null || mBlurredBitmap == null || mBlurredBitmap.getWidth() != scaledWidth || mBlurredBitmap.getHeight() != scaledHeight) {
+            releaseBitmap();
+
+            boolean r = false;
+            try {
+                mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
+                if (mBitmapToBlur == null) {
+                    return false;
+                }
+                mBlurringCanvas = new Canvas(mBitmapToBlur);
+
+                if (!supportRenderScript || !useBlur) {
+                    return true;
+                }
+
+                mBlurInput = Allocation.createFromBitmap(mRenderScript, mBitmapToBlur,
+                        Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT
+                );
+                mBlurOutput = Allocation.createTyped(mRenderScript, mBlurInput.getType());
+
+                mBlurredBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
+                if (mBlurredBitmap == null) {
+                    return false;
+                }
+
+                r = true;
+            } catch (Exception e) {
+                if (isDebug()) e.printStackTrace();
+            } finally {
+                if (!r) {
+                    releaseBitmap();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    protected void blur(Bitmap bitmapToBlur, Bitmap blurredBitmap) {
+        mBlurInput.copyFrom(bitmapToBlur);
+        mBlurScript.setInput(mBlurInput);
+        mBlurScript.forEach(mBlurOutput);
+        mBlurOutput.copyTo(blurredBitmap);
+    }
+
+    private final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            final int[] locations = new int[2];
+            Bitmap oldBmp = mBlurredBitmap;
+            View decor = mDecorView;
+            if (decor != null && isShown() && prepare()) {
+                boolean redrawBitmap = mBlurredBitmap != oldBmp;
+                decor.getLocationOnScreen(locations);
+                int x = -locations[0];
+                int y = -locations[1];
+
+                getLocationOnScreen(locations);
+                x += locations[0];
+                y += locations[1];
+
+                // just erase transparent
+                mBitmapToBlur.eraseColor(mOverlayColor & 0xffffff);
+
+                int rc = mBlurringCanvas.save();
+                mIsRendering = true;
+                RENDERING_COUNT++;
+                try {
+                    mBlurringCanvas.scale(1.f * mBitmapToBlur.getWidth() / getWidth(), 1.f * mBitmapToBlur.getHeight() / getHeight());
+                    mBlurringCanvas.translate(-x, -y);
+                    if (decor.getBackground() != null) {
+                        decor.getBackground().draw(mBlurringCanvas);
+                    }
+                    decor.draw(mBlurringCanvas);
+                } catch (Exception e) {
+                    if (isDebug()) e.printStackTrace();
+                } finally {
+                    mIsRendering = false;
+                    RENDERING_COUNT--;
+                    mBlurringCanvas.restoreToCount(rc);
+                }
+
+                blur(mBitmapToBlur, mBlurredBitmap);
+
+                if (redrawBitmap || mDifferentRoot) {
+                    invalidate();
+                }
+            }
+
+            return true;
+        }
+    };
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        Activity activity;
+        if (getContext() instanceof Activity) {
+            activity = (Activity) getContext();
+        } else {
+            activity = BaseDialog.getTopActivity();
+        }
+        ViewGroup decorView = ((ViewGroup) activity.getWindow().getDecorView());
+        if (decorView.getChildCount() >= 1) {
+            mDecorView = decorView.getChildAt(0);
+        }
+        if (mDecorView != null) {
+            log("mDecorView is ok.");
+            mDecorView.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
+            mDifferentRoot = mDecorView.getRootView() != getRootView();
+            if (mDifferentRoot) {
+                mDecorView.postInvalidate();
+            }
+        } else {
+            log("mDecorView is NULL.");
+            mDifferentRoot = false;
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if (mDecorView != null) {
+            mDecorView.getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
+        }
+        release();
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        if (isCompatMode()) {
+            drawBlurredBitmapCompat(canvas);
+        } else {
+            drawBlurredBitmap(canvas, mBlurredBitmap);
+        }
+        super.dispatchDraw(canvas);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        log("#draw");
+        if (!useBlur || !supportRenderScript) {
+            mRectF.right = getWidth();
+            mRectF.bottom = getHeight();
+            overlayPaint.setColor(needRemoveAlphaColor() ? removeAlphaColor(mOverlayColor) : mOverlayColor);
+            canvas.drawRoundRect(mRectF, mRadius, mRadius, overlayPaint);
+        } else {
+            if (!mIsRendering && RENDERING_COUNT <= 0) {
+                log("draw: ok");
+                super.draw(canvas);
+            }
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        if (isCompatMode()) {
+            drawBlurredBitmapCompat(canvas);
+        } else {
+            drawBlurredBitmap(canvas, mBlurredBitmap);
+        }
+    }
+
+    private void drawBlurredBitmapCompat(Canvas canvas) {
+        if (mBlurredBitmap != null) {
+            mRectDst.right = getWidth();
+            mRectDst.bottom = getHeight();
+            if (getWidth() > 0 && getHeight() > 0) {
+                Bitmap readyDrawBitmap = getRoundedCornerBitmap(resizeImage(mBlurredBitmap, getWidth(), getHeight()), mRectDst);
+                if (readyDrawBitmap != null) {
+                    canvas.drawBitmap(readyDrawBitmap, 0, 0, null);
+                } else {
+                    Bitmap overlyBitmap = drawOverlyColor(Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888));
+                    if (overlyBitmap != null) canvas.drawBitmap(overlyBitmap, 0, 0, null);
+                }
+            }
+        } else {
+            Bitmap overlyBitmap = drawOverlyColor(Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888));
+            if (overlyBitmap != null) canvas.drawBitmap(overlyBitmap, 0, 0, null);
+        }
+    }
+
+    protected void drawBlurredBitmap(Canvas canvas, Bitmap blurredBitmap) {
+        if (blurredBitmap != null) {
+            mRectSrc.right = blurredBitmap.getWidth();
+            mRectSrc.bottom = blurredBitmap.getHeight();
+            mRectDst.right = getWidth();
+            mRectDst.bottom = getHeight();
+            canvas.drawBitmap(blurredBitmap, mRectSrc, mRectDst, null);
+            canvas.drawColor(mOverlayColor);
+        } else {
+            Bitmap overlyBitmap = drawOverlyColor(Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888));
+            if (overlyBitmap != null) canvas.drawBitmap(overlyBitmap, 0, 0, null);
+        }
+    }
+
+    private Bitmap getRoundedCornerBitmap(Bitmap bitmap, Rect mRectDst) {
+        bitmap = drawOverlyColor(resizeImage(bitmap, mRectDst.width(), mRectDst.height()));
+        if (bitmap == null) return null;
+        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(output);
+        BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+        Paint paint = new Paint();
+        paint.setAntiAlias(true);
+        paint.setShader(bitmapShader);
+        canvas.drawRoundRect(new RectF(mRectDst), mRadius, mRadius, paint);
+        return output;
+    }
+
+    private Bitmap drawOverlyColor(Bitmap bitmap) {
+        if (bitmap != null) {
+            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(output);
+            Rect originRect = new Rect();
+            originRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
+            canvas.drawBitmap(bitmap, originRect, originRect, overlayPaint);
+            canvas.drawColor(needRemoveAlphaColor() ? removeAlphaColor(mOverlayColor) : mOverlayColor);
+            return output;
+        } else {
+            return null;
+        }
+    }
+
+    private Bitmap resizeImage(Bitmap bitmap, int newWidth, int newHeight) {
+        if (bitmap != null) {
+            int width = bitmap.getWidth();
+            int height = bitmap.getHeight();
+            float scaleWidth = ((float) newWidth) / width;
+            float scaleHeight = ((float) newHeight) / height;
+            Matrix matrix = new Matrix();
+            matrix.postScale(scaleWidth, scaleHeight);
+            return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
+        } else {
+            return null;
+        }
+    }
+
+    private static boolean supportRenderScript = false;
+    private boolean useBlur = true;
+
+    public boolean isUseBlur() {
+        return useBlur;
+    }
+
+    public BlurRelativeLayout setUseBlur(boolean useBlur) {
+        this.useBlur = useBlur;
+        invalidate();
+        return this;
+    }
+
+    private boolean needRemoveAlphaColor() {
+        if (overrideOverlayColor) {
+            return false;
+        } else {
+            return !(supportRenderScript && useBlur);
+        }
+    }
+
+    private static int removeAlphaColor(int color) {
+        int alpha = 255;
+        int red = Color.red(color);
+        int green = Color.green(color);
+        int blue = Color.blue(color);
+        return Color.argb(alpha, red, green, blue);
+    }
+
+    private static int replaceAlphaColor(int color, int alpha) {
+        int red = Color.red(color);
+        int green = Color.green(color);
+        int blue = Color.blue(color);
+        return Color.argb(alpha, red, green, blue);
+    }
+
+    static {
+        /**
+         * 之所以需要启动一个新线程检测RenderScript是否可用的原因是不清楚Android什么时候对loadClass做了变更,
+         * 会直接抛出NoClassDefFoundError无法拦截,在主线程检测会导致程序直接闪退,因此改为异步检测。
+         * 检测后会给定(boolean)supportRenderScript用于判断时光支持
+         */
+        new Thread() {
+            @Override
+            public void run() {
+                try {
+                    BlurRelativeLayout.class.getClassLoader().loadClass(RenderScript.class.getCanonicalName());
+                    supportRenderScript = true;
+                } catch (Throwable e) {
+                    if (isDebug()) {
+                        e.printStackTrace();
+                    }
+                    supportRenderScript = false;
+                }
+            }
+        }.start();
+    }
+
+    public static boolean DEBUGMODE = true;
+
+    static boolean isDebug() {
+        return DEBUGMODE && DialogX.DEBUGMODE;
+    }
+
+    private static void log(Object o) {
+        if (isDebug()) Log.i(">>>", "DialogX.BlurView: " + o.toString());
+    }
+
+    public static void error(Object o) {
+        if (isDebug()) Log.e(">>>", o.toString());
+    }
+
+    public BlurRelativeLayout setOverrideOverlayColor(boolean overrideOverlayColor) {
+        log("setOverrideOverlayColor: " + overrideOverlayColor);
+        this.overrideOverlayColor = overrideOverlayColor;
+        return this;
+    }
+    private int dip2px(float dpValue) {
+        final float scale = getResources().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+}

+ 53 - 11
DialogXIOSStyle/src/main/res/layout/layout_dialogx_bottom_ios.xml

@@ -33,10 +33,9 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
-                    android:minHeight="40dp"
-                    android:tag="blurBody">
+                    android:minHeight="40dp">
 
-                    <LinearLayout
+                    <com.kongzue.dialogx.style.views.BlurLinearLayout
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
                         android:clickable="true"
@@ -105,32 +104,75 @@
 
                         </com.kongzue.dialogx.util.views.BottomDialogScrollView>
 
-                    </LinearLayout>
+                    </com.kongzue.dialogx.style.views.BlurLinearLayout>
 
                 </com.kongzue.dialogx.util.views.MaxRelativeLayout>
 
-                <com.kongzue.dialogx.util.views.MaxRelativeLayout
+                <com.kongzue.dialogx.style.views.BlurLinearLayout
                     android:layout_width="match_parent"
-                    android:layout_height="53dp"
+                    android:layout_height="wrap_content"
                     android:layout_marginTop="7dp"
                     android:layout_marginBottom="10dp"
-                    android:tag="cancelBox">
+                    android:divider="@color/dialogxIOSSplitLight"
+                    android:orientation="vertical"
+                    android:showDividers="middle">
+
+                    <TextView
+                        android:id="@+id/btn_selectPositive"
+                        android:layout_width="match_parent"
+                        android:layout_height="53dp"
+                        android:background="@drawable/button_dialogx_ios_center_light"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:paddingLeft="15dp"
+                        android:paddingRight="15dp"
+                        android:singleLine="true"
+                        android:text="确定"
+                        android:textColor="@color/dialogxIOSBlue"
+                        android:textSize="19dp" />
+
+                    <ImageView
+                        android:layout_width="match_parent"
+                        android:layout_height="1px"
+                        android:tag="imgPositiveButtonSplit"
+                        android:background="@color/dialogxIOSSplitLight"/>
 
                     <TextView
+                        android:id="@+id/btn_selectOther"
                         android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        android:background="@drawable/button_dialogx_ios_light"
+                        android:layout_height="53dp"
+                        android:background="@drawable/button_dialogx_ios_center_light"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:paddingLeft="15dp"
+                        android:paddingRight="15dp"
+                        android:singleLine="true"
+                        android:text="其他"
+                        android:textColor="@color/dialogxIOSBlue"
+                        android:textSize="19dp" />
+
+                    <ImageView
+                        android:id="@+id/split_selectOther"
+                        android:layout_width="match_parent"
+                        android:tag="imgOtherButtonSplit"
+                        android:layout_height="1px"
+                        android:background="@color/dialogxIOSSplitLight"/>
+
+                    <TextView
+                        android:id="@+id/btn_selectNegative"
+                        android:layout_width="match_parent"
+                        android:layout_height="53dp"
+                        android:background="@drawable/button_dialogx_ios_center_light"
                         android:clickable="true"
                         android:gravity="center"
                         android:paddingLeft="15dp"
                         android:paddingRight="15dp"
                         android:singleLine="true"
-                        android:tag="cancel"
                         android:text="取消"
                         android:textColor="@color/dialogxIOSBlue"
                         android:textSize="19dp" />
 
-                </com.kongzue.dialogx.util.views.MaxRelativeLayout>
+                </com.kongzue.dialogx.style.views.BlurLinearLayout>
 
             </LinearLayout>
 

+ 51 - 10
DialogXIOSStyle/src/main/res/layout/layout_dialogx_bottom_ios_dark.xml

@@ -33,10 +33,9 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
-                    android:minHeight="40dp"
-                    android:tag="blurBody">
+                    android:minHeight="40dp">
 
-                    <LinearLayout
+                    <com.kongzue.dialogx.style.views.BlurLinearLayout
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
                         android:clickable="true"
@@ -105,32 +104,74 @@
 
                         </com.kongzue.dialogx.util.views.BottomDialogScrollView>
 
-                    </LinearLayout>
+                    </com.kongzue.dialogx.style.views.BlurLinearLayout>
 
                 </com.kongzue.dialogx.util.views.MaxRelativeLayout>
 
-                <com.kongzue.dialogx.util.views.MaxRelativeLayout
+                <com.kongzue.dialogx.style.views.BlurLinearLayout
                     android:layout_width="match_parent"
-                    android:layout_height="53dp"
+                    android:layout_height="wrap_content"
                     android:layout_marginTop="7dp"
                     android:layout_marginBottom="10dp"
-                    android:tag="cancelBox">
+                    android:divider="@drawable/rect_dialogx_ios_menu_split_divider"
+                    android:orientation="vertical"
+                    android:showDividers="middle">
+
+                    <TextView
+                        android:id="@+id/btn_selectPositive"
+                        android:layout_width="match_parent"
+                        android:layout_height="53dp"
+                        android:background="@drawable/button_dialogx_ios_night"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:paddingLeft="15dp"
+                        android:paddingRight="15dp"
+                        android:singleLine="true"
+                        android:text="确定"
+                        android:textColor="@color/dialogxIOSBlueDark"
+                        android:textSize="19dp" />
+
+                    <ImageView
+                        android:layout_width="match_parent"
+                        android:layout_height="1px"
+                        android:background="@color/dialogxIOSSplitDark"
+                        android:tag="imgPositiveButtonSplit" />
 
                     <TextView
+                        android:id="@+id/btn_selectOther"
                         android:layout_width="match_parent"
-                        android:layout_height="match_parent"
+                        android:layout_height="53dp"
+                        android:background="@drawable/button_dialogx_ios_night"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:paddingLeft="15dp"
+                        android:paddingRight="15dp"
+                        android:singleLine="true"
+                        android:text="其他"
+                        android:textColor="@color/dialogxIOSBlueDark"
+                        android:textSize="19dp" />
+
+                    <ImageView
+                        android:layout_width="match_parent"
+                        android:layout_height="1px"
+                        android:background="@color/dialogxIOSSplitDark"
+                        android:tag="imgOtherButtonSplit" />
+
+                    <TextView
+                        android:id="@+id/btn_selectNegative"
+                        android:layout_width="match_parent"
+                        android:layout_height="53dp"
                         android:background="@drawable/button_dialogx_ios_night"
                         android:clickable="true"
                         android:gravity="center"
                         android:paddingLeft="15dp"
                         android:paddingRight="15dp"
                         android:singleLine="true"
-                        android:tag="cancel"
                         android:text="取消"
                         android:textColor="@color/dialogxIOSBlueDark"
                         android:textSize="19dp" />
 
-                </com.kongzue.dialogx.util.views.MaxRelativeLayout>
+                </com.kongzue.dialogx.style.views.BlurLinearLayout>
 
             </LinearLayout>
 

+ 27 - 9
DialogXKongzueStyle/src/main/res/layout/layout_dialogx_bottom_kongzue.xml

@@ -92,24 +92,43 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:orientation="vertical"
+                    android:showDividers="middle"
+                    android:divider="@color/dialogxKongzueButtonSplitLineColor"
                     android:tag="cancelBox">
 
-                    <ImageView
-                        android:layout_width="match_parent"
-                        android:layout_height="1px"
-                        android:background="@color/dialogxKongzueButtonSplitLineColor" />
-
                     <ImageView
                         android:layout_width="match_parent"
                         android:layout_height="8dp"
                         android:background="@color/dialogxKongzueButtonSplitSpaceColor" />
 
-                    <ImageView
+                    <TextView
+                        android:id="@+id/btn_selectPositive"
+                        android:layout_width="match_parent"
+                        android:layout_height="50dp"
+                        android:background="@drawable/button_dialogx_kongzue_menu_light"
+                        android:gravity="center"
+                        android:paddingLeft="15dp"
+                        android:paddingRight="15dp"
+                        android:singleLine="true"
+                        android:text="确定"
+                        android:textColor="@color/black90"
+                        android:textSize="16dp" />
+
+                    <TextView
+                        android:id="@+id/btn_selectOther"
                         android:layout_width="match_parent"
-                        android:layout_height="1px"
-                        android:background="@color/dialogxKongzueButtonSplitLineColor" />
+                        android:layout_height="50dp"
+                        android:background="@drawable/button_dialogx_kongzue_menu_light"
+                        android:gravity="center"
+                        android:paddingLeft="15dp"
+                        android:paddingRight="15dp"
+                        android:singleLine="true"
+                        android:text="其他"
+                        android:textColor="@color/black90"
+                        android:textSize="16dp" />
 
                     <TextView
+                        android:id="@+id/btn_selectNegative"
                         android:layout_width="match_parent"
                         android:layout_height="50dp"
                         android:background="@drawable/button_dialogx_kongzue_menu_light"
@@ -117,7 +136,6 @@
                         android:paddingLeft="15dp"
                         android:paddingRight="15dp"
                         android:singleLine="true"
-                        android:tag="cancel"
                         android:text="取消"
                         android:textColor="@color/black90"
                         android:textSize="16dp" />

+ 30 - 2
DialogXKongzueStyle/src/main/res/layout/layout_dialogx_bottom_kongzue_dark.xml

@@ -92,7 +92,9 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:orientation="vertical"
-                    android:tag="cancelBox">
+                    android:divider="@color/dialogxKongzueDarkButtonSplitLineColor"
+                    android:showDividers="middle"
+                    android:tag="buttonBox">
 
                     <ImageView
                         android:layout_width="match_parent"
@@ -100,6 +102,33 @@
                         android:background="@color/dialogxKongzueDarkButtonSplitSpaceColor" />
 
                     <TextView
+                        android:id="@+id/btn_selectPositive"
+                        android:layout_width="match_parent"
+                        android:layout_height="50dp"
+                        android:background="@drawable/button_dialogx_kongzue_menu_night"
+                        android:gravity="center"
+                        android:paddingLeft="15dp"
+                        android:paddingRight="15dp"
+                        android:singleLine="true"
+                        android:text="确定"
+                        android:textColor="@color/white90"
+                        android:textSize="16dp" />
+
+                    <TextView
+                        android:id="@+id/btn_selectOther"
+                        android:layout_width="match_parent"
+                        android:layout_height="50dp"
+                        android:background="@drawable/button_dialogx_kongzue_menu_night"
+                        android:gravity="center"
+                        android:paddingLeft="15dp"
+                        android:paddingRight="15dp"
+                        android:singleLine="true"
+                        android:text="其他"
+                        android:textColor="@color/white90"
+                        android:textSize="16dp" />
+
+                    <TextView
+                        android:id="@+id/btn_selectNegative"
                         android:layout_width="match_parent"
                         android:layout_height="50dp"
                         android:background="@drawable/button_dialogx_kongzue_menu_night"
@@ -107,7 +136,6 @@
                         android:paddingLeft="15dp"
                         android:paddingRight="15dp"
                         android:singleLine="true"
-                        android:tag="cancel"
                         android:text="取消"
                         android:textColor="@color/white90"
                         android:textSize="16dp" />

+ 58 - 10
DialogXMIUIStyle/src/main/res/layout/layout_dialogx_bottom_miui.xml

@@ -60,8 +60,8 @@
                             android:layout_height="wrap_content"
                             android:layout_gravity="center_horizontal"
                             android:layout_marginLeft="26dp"
-                            android:layout_marginRight="26dp"
                             android:layout_marginTop="10dp"
+                            android:layout_marginRight="26dp"
                             android:gravity="left"
                             android:paddingBottom="5dp"
                             android:text="This is content text."
@@ -85,20 +85,68 @@
 
                 </com.kongzue.dialogx.util.views.BottomDialogScrollView>
 
-                <TextView
+                <LinearLayout
+                    android:id="@+id/box_button"
                     android:layout_width="match_parent"
-                    android:layout_height="50dp"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_horizontal"
                     android:layout_marginLeft="26dp"
                     android:layout_marginTop="10dp"
                     android:layout_marginRight="26dp"
                     android:layout_marginBottom="20dp"
-                    android:background="@drawable/button_dialogx_miui_gray"
-                    android:clickable="true"
-                    android:gravity="center"
-                    android:tag="cancel"
-                    android:text="取消"
-                    android:textColor="@color/black80"
-                    android:textSize="16dp" />
+                    android:gravity="right|center_vertical"
+                    android:orientation="horizontal">
+
+                    <TextView
+                        android:id="@+id/btn_selectNegative"
+                        android:layout_width="match_parent"
+                        android:layout_height="50dp"
+                        android:layout_marginLeft="6dp"
+                        android:layout_marginTop="5dp"
+                        android:layout_marginRight="6dp"
+                        android:layout_marginBottom="5dp"
+                        android:layout_weight="1"
+                        android:background="@drawable/button_dialogx_miui_gray"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:text="Cancel"
+                        android:textColor="@color/black80"
+                        android:textSize="16dp" />
+
+                    <TextView
+                        android:id="@+id/btn_selectOther"
+                        android:layout_width="match_parent"
+                        android:layout_height="50dp"
+                        android:layout_marginLeft="6dp"
+                        android:layout_marginTop="5dp"
+                        android:layout_marginRight="6dp"
+                        android:layout_marginBottom="5dp"
+                        android:layout_weight="1"
+                        android:background="@drawable/button_dialogx_miui_gray"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:text="Other"
+                        android:textColor="@color/dialogxMIUIButtonText"
+                        android:textSize="16dp"
+                        android:visibility="gone" />
+
+                    <TextView
+                        android:id="@+id/btn_selectPositive"
+                        android:layout_width="match_parent"
+                        android:layout_height="50dp"
+                        android:layout_marginLeft="6dp"
+                        android:layout_marginTop="5dp"
+                        android:layout_marginRight="6dp"
+                        android:layout_marginBottom="5dp"
+                        android:layout_weight="1"
+                        android:background="@drawable/button_dialogx_miui_blue"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:text="OK"
+                        android:textColor="@color/white"
+                        android:textSize="16dp" />
+
+                </LinearLayout>
 
             </LinearLayout>
 

+ 58 - 10
DialogXMIUIStyle/src/main/res/layout/layout_dialogx_bottom_miui_dark.xml

@@ -59,8 +59,8 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:layout_gravity="center_horizontal"
-                            android:layout_marginTop="10dp"
                             android:layout_marginLeft="26dp"
+                            android:layout_marginTop="10dp"
                             android:layout_marginRight="26dp"
                             android:gravity="left"
                             android:paddingBottom="5dp"
@@ -85,20 +85,68 @@
 
                 </com.kongzue.dialogx.util.views.BottomDialogScrollView>
 
-                <TextView
+                <LinearLayout
+                    android:id="@+id/box_button"
                     android:layout_width="match_parent"
-                    android:layout_height="50dp"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_horizontal"
                     android:layout_marginLeft="26dp"
                     android:layout_marginTop="10dp"
                     android:layout_marginRight="26dp"
                     android:layout_marginBottom="20dp"
-                    android:background="@drawable/button_dialogx_miui_gray_night"
-                    android:clickable="true"
-                    android:gravity="center"
-                    android:tag="cancel"
-                    android:text="取消"
-                    android:textColor="@color/dialogxMIUITextDark"
-                    android:textSize="16dp" />
+                    android:gravity="right|center_vertical"
+                    android:orientation="horizontal">
+
+                    <TextView
+                        android:id="@+id/btn_selectNegative"
+                        android:layout_width="match_parent"
+                        android:layout_height="50dp"
+                        android:layout_marginLeft="6dp"
+                        android:layout_marginTop="5dp"
+                        android:layout_marginRight="6dp"
+                        android:layout_marginBottom="5dp"
+                        android:layout_weight="1"
+                        android:background="@drawable/button_dialogx_miui_gray_night"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:text="Cancel"
+                        android:textColor="@color/dialogxMIUITextDark"
+                        android:textSize="16dp" />
+
+                    <TextView
+                        android:id="@+id/btn_selectOther"
+                        android:layout_width="match_parent"
+                        android:layout_height="50dp"
+                        android:layout_marginLeft="6dp"
+                        android:layout_marginTop="5dp"
+                        android:layout_marginRight="6dp"
+                        android:layout_marginBottom="5dp"
+                        android:layout_weight="1"
+                        android:background="@drawable/button_dialogx_miui_gray_night"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:text="Other"
+                        android:textColor="@color/dialogxMIUITextDark"
+                        android:textSize="16dp"
+                        android:visibility="gone" />
+
+                    <TextView
+                        android:id="@+id/btn_selectPositive"
+                        android:layout_width="match_parent"
+                        android:layout_height="50dp"
+                        android:layout_marginLeft="6dp"
+                        android:layout_marginTop="5dp"
+                        android:layout_marginRight="6dp"
+                        android:layout_marginBottom="5dp"
+                        android:layout_weight="1"
+                        android:background="@drawable/button_dialogx_miui_blue_night"
+                        android:clickable="true"
+                        android:gravity="center"
+                        android:text="OK"
+                        android:textColor="@color/dialogxMIUITextDark"
+                        android:textSize="16dp" />
+
+                </LinearLayout>
 
             </LinearLayout>
 

+ 42 - 42
app/src/main/java/com/kongzue/dialogxdemo/activity/MainActivity.java

@@ -11,6 +11,7 @@ import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Handler;
@@ -83,6 +84,7 @@ import com.kongzue.dialogx.interfaces.OnIconChangeCallBack;
 import com.kongzue.dialogx.interfaces.OnInputDialogButtonClickListener;
 import com.kongzue.dialogx.interfaces.OnMenuItemClickListener;
 import com.kongzue.dialogx.interfaces.OnMenuItemSelectListener;
+import com.kongzue.dialogx.interfaces.OnSafeInsetsChangeListener;
 import com.kongzue.dialogx.style.IOSStyle;
 import com.kongzue.dialogx.style.KongzueStyle;
 import com.kongzue.dialogx.style.MIUIStyle;
@@ -972,52 +974,50 @@ public class MainActivity extends BaseActivity {
         btnFullScreenDialogWebPage.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                FullScreenDialog.build(new OnBindView<FullScreenDialog>(R.layout.layout_full_webview) {
-                            @Override
-                            public void onBind(final FullScreenDialog dialog, View v) {
-
-                                btnClose = v.findViewById(R.id.btn_close);
-                                webView = v.findViewById(R.id.webView);
-
-                                btnClose.setOnClickListener(new View.OnClickListener() {
-                                    @Override
-                                    public void onClick(View v) {
-                                        dialog.dismiss();
-                                    }
-                                });
+                FullScreenDialog.show(new OnBindView<FullScreenDialog>(R.layout.layout_full_webview) {
+                    @Override
+                    public void onBind(final FullScreenDialog dialog, View v) {
+                        btnClose = v.findViewById(R.id.btn_close);
+                        webView = v.findViewById(R.id.webView);
 
-                                WebSettings webSettings = webView.getSettings();
-                                webSettings.setJavaScriptEnabled(true);
-                                webSettings.setLoadWithOverviewMode(true);
-                                webSettings.setUseWideViewPort(true);
-                                webSettings.setSupportZoom(false);
-                                webSettings.setAllowFileAccess(true);
-                                webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
-                                webSettings.setLoadsImagesAutomatically(true);
-                                webSettings.setDefaultTextEncodingName("utf-8");
-
-                                webView.setWebViewClient(new WebViewClient() {
-                                    @Override
-                                    public boolean shouldOverrideUrlLoading(WebView view, String url) {
-                                        try {
-                                            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
-                                            startActivity(intent);
-                                        } catch (ActivityNotFoundException e) {
-                                            e.printStackTrace();
-                                        }
-                                        return true;
-                                    }
+                        btnClose.setOnClickListener(new View.OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+                                dialog.dismiss();
+                            }
+                        });
 
-                                    @Override
-                                    public void onPageFinished(WebView view, String url) {
-                                        super.onPageFinished(view, url);
-                                    }
-                                });
+                        WebSettings webSettings = webView.getSettings();
+                        webSettings.setJavaScriptEnabled(true);
+                        webSettings.setLoadWithOverviewMode(true);
+                        webSettings.setUseWideViewPort(true);
+                        webSettings.setSupportZoom(false);
+                        webSettings.setAllowFileAccess(true);
+                        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
+                        webSettings.setLoadsImagesAutomatically(true);
+                        webSettings.setDefaultTextEncodingName("utf-8");
+
+                        webView.setWebViewClient(new WebViewClient() {
+                            @Override
+                            public boolean shouldOverrideUrlLoading(WebView view, String url) {
+                                try {
+                                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+                                    startActivity(intent);
+                                } catch (ActivityNotFoundException e) {
+                                    e.printStackTrace();
+                                }
+                                return true;
+                            }
 
-                                webView.loadUrl("https://github.com/kongzue/DialogX");
+                            @Override
+                            public void onPageFinished(WebView view, String url) {
+                                super.onPageFinished(view, url);
                             }
-                        })
-                        .show();
+                        });
+
+                        webView.loadUrl("https://github.com/kongzue/DialogX");
+                    }
+                }).setBottomNonSafetyAreaBySelf(true);
             }
         });
 

+ 1 - 1
build.gradle

@@ -9,7 +9,7 @@ buildscript {
         }
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:7.0.4'
+        classpath 'com.android.tools.build:gradle:7.1.0'
         classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
 
         // NOTE: Do not place your application dependencies here; they belong

+ 1 - 1
gradle.properties

@@ -19,6 +19,6 @@ android.useAndroidX=true
 # Automatically convert third-party libraries to use AndroidX
 android.enableJetifier=true
 
-BUILD_VERSION=0.0.48.beta21
+BUILD_VERSION=0.0.48.beta22
 BUILD_VERSION_INT=47
 DIALOGX_STYLE_VERSION=5