Просмотр исходного кода

fix bugs and add FullScreenDialog

kongzue 4 лет назад
Родитель
Сommit
e0b6e4a1f3

+ 314 - 0
DialogX/src/main/java/com/kongzue/dialogx/dialogs/FullScreenDialog.java

@@ -0,0 +1,314 @@
+package com.kongzue.dialogx.dialogs;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.ColorInt;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.R;
+import com.kongzue.dialogx.impl.AnimatorListenerEndCallBack;
+import com.kongzue.dialogx.interfaces.BaseDialog;
+import com.kongzue.dialogx.interfaces.DialogConvertViewInterface;
+import com.kongzue.dialogx.interfaces.DialogLifecycleCallback;
+import com.kongzue.dialogx.interfaces.DialogXStyle;
+import com.kongzue.dialogx.interfaces.OnBackPressedListener;
+import com.kongzue.dialogx.interfaces.OnBindView;
+import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener;
+import com.kongzue.dialogx.interfaces.OnSafeInsetsChangeListener;
+import com.kongzue.dialogx.util.BottomDialogTouchEventInterceptor;
+import com.kongzue.dialogx.util.FullScreenDialogTouchEventInterceptor;
+import com.kongzue.dialogx.util.TextInfo;
+import com.kongzue.dialogx.util.views.ActivityScreenShotImageView;
+import com.kongzue.dialogx.util.views.BlurView;
+import com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout;
+import com.kongzue.dialogx.util.views.MaxRelativeLayout;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/6 15:17
+ */
+public class FullScreenDialog extends BaseDialog {
+    
+    protected OnBindView<FullScreenDialog> onBindView;
+    
+    protected DialogLifecycleCallback<FullScreenDialog> dialogLifecycleCallback;
+    
+    protected FullScreenDialog me = this;
+    
+    protected FullScreenDialog() {
+        super();
+    }
+    
+    private View dialogView;
+    
+    public static FullScreenDialog build() {
+        return new FullScreenDialog();
+    }
+    
+    public FullScreenDialog(OnBindView<FullScreenDialog> onBindView) {
+        this.onBindView = onBindView;
+    }
+    
+    public static FullScreenDialog show(OnBindView<FullScreenDialog> onBindView) {
+        FullScreenDialog fullScreenDialog = new FullScreenDialog(onBindView);
+        fullScreenDialog.show();
+        return fullScreenDialog;
+    }
+    
+    public void show() {
+        dialogView = createView(R.layout.layout_dialogx_fullscreen);
+        dialogImpl = new DialogImpl(dialogView);
+        show(dialogView);
+    }
+    
+    protected DialogImpl dialogImpl;
+    
+    public class DialogImpl implements DialogConvertViewInterface {
+        
+        private FullScreenDialogTouchEventInterceptor fullScreenDialogTouchEventInterceptor;
+    
+        public ActivityScreenShotImageView imgZoomActivity;
+        public DialogXBaseRelativeLayout boxRoot;
+        public RelativeLayout boxBkg;
+        public MaxRelativeLayout bkg;
+        public RelativeLayout boxCustom;
+        
+        public DialogImpl(View convertView) {
+            imgZoomActivity = convertView.findViewById(R.id.img_zoom_activity);
+            boxRoot = convertView.findViewById(R.id.box_root);
+            boxBkg = convertView.findViewById(R.id.box_bkg);
+            bkg = convertView.findViewById(R.id.bkg);
+            boxCustom = convertView.findViewById(R.id.box_custom);
+            init();
+            refreshView();
+        }
+        
+        public float bkgEnterAimY = -1;
+        
+        @Override
+        public void init() {
+            boxRoot.setOnLifecycleCallBack(new DialogXBaseRelativeLayout.OnLifecycleCallBack() {
+                @Override
+                public void onShow() {
+                    isShow = true;
+                    boxRoot.setAlpha(0f);
+                    
+                    getDialogLifecycleCallback().onShow(me);
+                    
+                    if (onBindView != null) onBindView.onBind(me, onBindView.getCustomView());
+                }
+                
+                @Override
+                public void onDismiss() {
+                    isShow = false;
+                    getDialogLifecycleCallback().onDismiss(me);
+                }
+            });
+            
+            boxRoot.setOnBackPressedListener(new OnBackPressedListener() {
+                @Override
+                public boolean onBackPressed() {
+                    if (onBackPressedListener != null && onBackPressedListener.onBackPressed()) {
+                        dismiss();
+                        return false;
+                    }
+                    if (cancelable) {
+                        dismiss();
+                    }
+                    return false;
+                }
+            });
+            
+            fullScreenDialogTouchEventInterceptor = new FullScreenDialogTouchEventInterceptor(me, dialogImpl);
+            
+            boxRoot.post(new Runnable() {
+                @Override
+                public void run() {
+                    bkgEnterAimY = boxRoot.getSafeHeight() - boxCustom.getHeight();
+                    
+                    boxRoot.animate().setDuration(300).alpha(1f).setInterpolator(new DecelerateInterpolator()).setDuration(100).setListener(null);
+    
+                    ObjectAnimator exitAnim = ObjectAnimator.ofFloat(bkg, "y", boxRoot.getHeight(), bkgEnterAimY);
+                    exitAnim.setDuration(300);
+                    exitAnim.start();
+                }
+            });
+    
+            bkg.setOnYChanged(new MaxRelativeLayout.OnYChanged() {
+                @Override
+                public void y(float y) {
+                    float zoomScale = 1 - (boxRoot.getHeight() - y) * 0.00002f;
+                    if (zoomScale > 1) zoomScale = 1;
+                    imgZoomActivity.setScaleX(zoomScale);
+                    imgZoomActivity.setScaleY(zoomScale);
+    
+                    imgZoomActivity.setRadius(dip2px(15) * ((boxRoot.getHeight() - y) / boxRoot.getHeight()));
+                }
+            });
+    
+            boxRoot.setOnSafeInsetsChangeListener(new OnSafeInsetsChangeListener() {
+                @Override
+                public void onChange(Rect unsafeRect) {
+                    if (unsafeRect.bottom>dip2px(100)){
+                        ObjectAnimator enterAnim = ObjectAnimator.ofFloat(bkg, "y", bkg.getY(), 0);
+                        enterAnim.setDuration(300);
+                        enterAnim.start();
+                    }
+                }
+            });
+        }
+        
+        @Override
+        public void refreshView() {
+            if (backgroundColor != -1) {
+                tintColor(bkg, backgroundColor);
+            }
+            
+            if (cancelable) {
+                boxRoot.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        doDismiss(v);
+                    }
+                });
+            } else {
+                boxRoot.setOnClickListener(null);
+            }
+            
+            if (onBindView != null) {
+                if (onBindView.getCustomView() != null) {
+                    if (onBindView.getCustomView().isAttachedToWindow()) {
+                        boxCustom.removeView(onBindView.getCustomView());
+                    }
+                    ViewGroup.LayoutParams lp = onBindView.getCustomView().getLayoutParams();
+                    if (lp == null) {
+                        lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+                    }
+                    boxCustom.addView(onBindView.getCustomView(), lp);
+                }
+            }
+            
+            fullScreenDialogTouchEventInterceptor.refresh(me,this);
+        }
+        
+        @Override
+        public void doDismiss(View v) {
+            if (v != null) v.setEnabled(false);
+            
+            ObjectAnimator exitAnim = ObjectAnimator.ofFloat(bkg, "y", bkg.getY(), boxBkg.getHeight());
+            exitAnim.setDuration(300);
+            exitAnim.start();
+            
+            boxRoot.animate().setDuration(300).alpha(0f).setInterpolator(new AccelerateInterpolator()).setDuration(exitAnim.getDuration()).setListener(new AnimatorListenerEndCallBack() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    dismiss(dialogView);
+                }
+            });
+        }
+        
+        public void preDismiss() {
+            if (cancelable) {
+                doDismiss(boxRoot);
+            } else {
+                ObjectAnimator enterAnim = ObjectAnimator.ofFloat(bkg, "y", bkg.getY(), bkgEnterAimY);
+                enterAnim.setDuration(300);
+                enterAnim.start();
+            }
+        }
+    }
+    
+    public void refreshUI() {
+        if (dialogImpl == null) return;
+        dialogImpl.refreshView();
+    }
+    
+    public void dismiss() {
+        if (dialogImpl == null) return;
+        dialogImpl.doDismiss(null);
+    }
+    
+    public DialogLifecycleCallback<FullScreenDialog> getDialogLifecycleCallback() {
+        return dialogLifecycleCallback == null ? new DialogLifecycleCallback<FullScreenDialog>() {
+        } : dialogLifecycleCallback;
+    }
+    
+    public FullScreenDialog setDialogLifecycleCallback(DialogLifecycleCallback<FullScreenDialog> dialogLifecycleCallback) {
+        this.dialogLifecycleCallback = dialogLifecycleCallback;
+        return this;
+    }
+    
+    public OnBackPressedListener getOnBackPressedListener() {
+        return onBackPressedListener;
+    }
+    
+    public FullScreenDialog setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
+        this.onBackPressedListener = onBackPressedListener;
+        refreshUI();
+        return this;
+    }
+    
+    public FullScreenDialog setStyle(DialogXStyle style) {
+        this.style = style;
+        return this;
+    }
+    
+    public FullScreenDialog setTheme(DialogX.THEME theme) {
+        this.theme = theme;
+        return this;
+    }
+    
+    public boolean isCancelable() {
+        return cancelable;
+    }
+    
+    public FullScreenDialog setCancelable(boolean cancelable) {
+        this.cancelable = cancelable;
+        refreshUI();
+        return this;
+    }
+    
+    public DialogImpl getDialogImpl() {
+        return dialogImpl;
+    }
+    
+    public FullScreenDialog setCustomView(OnBindView<FullScreenDialog> onBindView) {
+        this.onBindView = onBindView;
+        refreshUI();
+        return this;
+    }
+    
+    public View getCustomView() {
+        if (onBindView == null) return null;
+        return onBindView.getCustomView();
+    }
+    
+    public FullScreenDialog removeCustomView() {
+        this.onBindView.clean();
+        refreshUI();
+        return this;
+    }
+    
+    public int getBackgroundColor() {
+        return backgroundColor;
+    }
+    
+    public FullScreenDialog setBackgroundColor(@ColorInt int backgroundColor) {
+        this.backgroundColor = backgroundColor;
+        refreshUI();
+        return this;
+    }
+}

+ 2 - 1
DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnBindView.java

@@ -2,6 +2,7 @@ package com.kongzue.dialogx.interfaces;
 
 import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.RelativeLayout;
 
 /**
  * @author: Kongzue
@@ -16,7 +17,7 @@ public abstract class OnBindView<D> {
     
     public OnBindView(int layoutResId) {
         this.layoutResId = layoutResId;
-        customView = LayoutInflater.from(BaseDialog.getContext()).inflate(layoutResId, null);
+        customView = LayoutInflater.from(BaseDialog.getContext()).inflate(layoutResId, new RelativeLayout(BaseDialog.getContext()),false);
     }
     
     public OnBindView(View customView) {

+ 15 - 0
DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnSafeInsetsChangeListener.java

@@ -0,0 +1,15 @@
+package com.kongzue.dialogx.interfaces;
+
+import android.graphics.Rect;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/19 16:06
+ */
+public interface OnSafeInsetsChangeListener {
+    
+    void onChange(Rect unsafeRect);
+}

+ 96 - 0
DialogX/src/main/java/com/kongzue/dialogx/util/FullScreenDialogTouchEventInterceptor.java

@@ -0,0 +1,96 @@
+package com.kongzue.dialogx.util;
+
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.kongzue.dialogx.dialogs.FullScreenDialog;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/19 13:54
+ */
+public class FullScreenDialogTouchEventInterceptor {
+    
+    /**
+     * 下边三个值用于判断触控过程,
+     * isBkgTouched:标记是否已按下
+     * bkgTouchDownY:记录起始触控位置
+     * scrolledY:记录 ScrollView 已滚动过的距离,下次触控事件将接着上次的位置继续滑动
+     * bkgOldY:记录按下时 bkg 的位置,用于区分松开手指时,bkg 移动的方向。
+     */
+    private boolean isBkgTouched = false;
+    private float bkgTouchDownY;
+    private float bkgOldY;
+    
+    public FullScreenDialogTouchEventInterceptor(FullScreenDialog me, FullScreenDialog.DialogImpl impl) {
+        refresh(me, impl);
+    }
+    
+    public void refresh(final FullScreenDialog me, final FullScreenDialog.DialogImpl impl) {
+        if (me == null || impl == null || impl.bkg == null) {
+            return;
+        }
+        
+        impl.boxCustom.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                switch (event.getAction()) {
+                    case MotionEvent.ACTION_DOWN:
+                        bkgTouchDownY = event.getY();
+                        isBkgTouched = true;
+                        bkgOldY = impl.bkg.getY();
+                        break;
+                    case MotionEvent.ACTION_MOVE:
+                        if (isBkgTouched) {
+                            float aimY = impl.bkg.getY() + event.getY() - bkgTouchDownY;
+                            if (aimY < 0) {
+                                aimY = 0;
+                            }
+                            impl.bkg.setY(aimY);
+                        }
+                        break;
+                    case MotionEvent.ACTION_UP:
+                    case MotionEvent.ACTION_CANCEL:
+                        isBkgTouched = false;
+                        if (bkgOldY == 0) {
+                            if (impl.bkg.getY() < dip2px(35)) {
+                                ObjectAnimator enterAnim = ObjectAnimator.ofFloat(impl.bkg, "y", impl.bkg.getY(), 0);
+                                enterAnim.setDuration(300);
+                                enterAnim.start();
+                            } else if (impl.bkg.getY() > impl.bkgEnterAimY + dip2px(35)) {
+                                impl.preDismiss();
+                            } else {
+                                ObjectAnimator enterAnim = ObjectAnimator.ofFloat(impl.bkg, "y", impl.bkg.getY(), impl.bkgEnterAimY);
+                                enterAnim.setDuration(300);
+                                enterAnim.start();
+                            }
+                        } else {
+                            if (impl.bkg.getY() < bkgOldY - dip2px(35)) {
+                                ObjectAnimator enterAnim = ObjectAnimator.ofFloat(impl.bkg, "y", impl.bkg.getY(), 0);
+                                enterAnim.setDuration(300);
+                                enterAnim.start();
+                            } else if (impl.bkg.getY() > bkgOldY + dip2px(35)) {
+                                impl.preDismiss();
+                            } else {
+                                ObjectAnimator enterAnim = ObjectAnimator.ofFloat(impl.bkg, "y", impl.bkg.getY(), impl.bkgEnterAimY);
+                                enterAnim.setDuration(300);
+                                enterAnim.start();
+                            }
+                        }
+                        break;
+                }
+                return true;
+            }
+        });
+    }
+    
+    private int dip2px(float dpValue) {
+        final float scale = Resources.getSystem().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+}

+ 124 - 0
DialogX/src/main/java/com/kongzue/dialogx/util/views/ActivityScreenShotImageView.java

@@ -0,0 +1,124 @@
+package com.kongzue.dialogx.util.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+
+import androidx.appcompat.widget.AppCompatImageView;
+
+import com.kongzue.dialogx.interfaces.BaseDialog;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2019/11/17 23:53
+ */
+public class ActivityScreenShotImageView extends AppCompatImageView {
+    
+    float width, height, mRadius;
+    
+    public ActivityScreenShotImageView(Context context) {
+        super(context);
+        init(null);
+    }
+    
+    public ActivityScreenShotImageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(attrs);
+    }
+    
+    public ActivityScreenShotImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(attrs);
+    }
+    
+    private void init(AttributeSet attrs) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            setLayerType(LAYER_TYPE_HARDWARE, null);
+        }
+    }
+    
+    public void setRadius(float mRadius) {
+        this.mRadius = mRadius;
+        invalidate();
+    }
+    
+    
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        width = getWidth();
+        height = getHeight();
+    }
+    
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (width >= mRadius && height > mRadius) {
+            Path path = new Path();
+            path.moveTo(mRadius, 0);
+            path.lineTo(width - mRadius, 0);
+            path.quadTo(width, 0, width, mRadius);
+            path.lineTo(width, height - mRadius);
+            path.quadTo(width, height, width - mRadius, height);
+            path.lineTo(mRadius, height);
+            path.quadTo(0, height, 0, height - mRadius);
+            path.lineTo(0, mRadius);
+            path.quadTo(0, 0, mRadius, 0);
+            
+            canvas.clipPath(path);
+        }
+        try {
+            super.onDraw(canvas);
+        } catch (Exception e) {
+        }
+    }
+    
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        
+        refreshImage();
+    }
+    
+    private int screenWidth, screenHeight;
+    
+    private void refreshImage() {
+        if (screenWidth != getMeasuredWidth() || screenHeight != getMeasuredHeight()) {
+            screenWidth = getMeasuredWidth();
+            screenHeight = getMeasuredHeight();
+            doScreenshotActivityAndZoom();
+        }
+    }
+    
+    private void doScreenshotActivityAndZoom() {
+        if (BaseDialog.getRootFrameLayout() == null) return;
+        final View view = BaseDialog.getRootFrameLayout().getChildAt(0);
+        //先执行一次绘制,防止出现闪屏问题
+        drawViewImage(view);
+        view.post(new Runnable() {
+            @Override
+            public void run() {
+                //当view渲染完成后再次通知刷新一下界面(当旋转屏幕执行时,很可能出现渲染延迟的问题)
+                drawViewImage(view);
+            }
+        });
+    }
+    
+    private void drawViewImage(View view) {
+        view.destroyDrawingCache();
+        view.setDrawingCacheEnabled(true);
+        view.buildDrawingCache();
+        Bitmap bmp = view.getDrawingCache();
+        setImageBitmap(bmp);
+    }
+}

+ 0 - 6
DialogX/src/main/java/com/kongzue/dialogx/util/views/BlurView.java

@@ -1,20 +1,14 @@
 package com.kongzue.dialogx.util.views;
 
-import android.app.Activity;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.Xfermode;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.TypedValue;

+ 21 - 0
DialogX/src/main/java/com/kongzue/dialogx/util/views/DialogXBaseRelativeLayout.java

@@ -5,6 +5,7 @@ import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.Build;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -22,6 +23,7 @@ import androidx.core.view.ViewCompat;
 import com.kongzue.dialogx.R;
 import com.kongzue.dialogx.interfaces.BaseDialog;
 import com.kongzue.dialogx.interfaces.OnBackPressedListener;
+import com.kongzue.dialogx.interfaces.OnSafeInsetsChangeListener;
 
 import java.util.Arrays;
 import java.util.List;
@@ -35,6 +37,8 @@ import java.util.List;
  */
 public class DialogXBaseRelativeLayout extends RelativeLayout {
     
+    private OnSafeInsetsChangeListener onSafeInsetsChangeListener;
+    
     private OnLifecycleCallBack onLifecycleCallBack;
     private OnBackPressedListener onBackPressedListener;
     
@@ -153,6 +157,10 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
         return this;
     }
     
+    public float getSafeHeight() {
+        return getMeasuredHeight() - unsafePlace.bottom - unsafePlace.top;
+    }
+    
     public abstract static class OnLifecycleCallBack {
         public void onShow() {
         }
@@ -160,7 +168,11 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
         public abstract void onDismiss();
     }
     
+    protected Rect unsafePlace;
+    
     private void paddingView(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);
         if (bkgView != null && bkgView.getLayoutParams() instanceof LayoutParams) {
             LayoutParams bkgLp = (LayoutParams) bkgView.getLayoutParams();
@@ -177,4 +189,13 @@ public class DialogXBaseRelativeLayout extends RelativeLayout {
         this.onBackPressedListener = onBackPressedListener;
         return this;
     }
+    
+    public OnSafeInsetsChangeListener getOnSafeInsetsChangeListener() {
+        return onSafeInsetsChangeListener;
+    }
+    
+    public DialogXBaseRelativeLayout setOnSafeInsetsChangeListener(OnSafeInsetsChangeListener onSafeInsetsChangeListener) {
+        this.onSafeInsetsChangeListener = onSafeInsetsChangeListener;
+        return this;
+    }
 }

+ 49 - 0
DialogX/src/main/java/com/kongzue/dialogx/util/views/MaxRelativeLayout.java

@@ -1,8 +1,11 @@
 package com.kongzue.dialogx.util.views;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewParent;
@@ -23,6 +26,7 @@ public class MaxRelativeLayout extends RelativeLayout {
     private int maxWidth;
     private int maxHeight;
     private boolean lockWidth;
+    private boolean interceptTouch = true;
     
     public MaxRelativeLayout(Context context) {
         super(context);
@@ -39,15 +43,31 @@ public class MaxRelativeLayout extends RelativeLayout {
         init(context, attrs);
     }
     
+    private float startAnimValue = 0, endAnimValue = 0;
+    
     private void init(Context context, AttributeSet attrs) {
         if (attrs != null) {
             TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MaxRelativeLayout);
             maxWidth = a.getDimensionPixelSize(R.styleable.MaxRelativeLayout_maxLayoutWidth, 0);
             maxHeight = a.getDimensionPixelSize(R.styleable.MaxRelativeLayout_maxLayoutHeight, 0);
             lockWidth = a.getBoolean(R.styleable.MaxRelativeLayout_lockWidth, false);
+            interceptTouch = a.getBoolean(R.styleable.MaxRelativeLayout_interceptTouch, true);
             
             a.recycle();
         }
+        
+        if (!isInEditMode()) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                animate().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        float progress = (float) animation.getAnimatedValue();
+                        long value = (long) (startAnimValue + (endAnimValue - startAnimValue) * progress);
+                        if (onYChangedListener != null) onYChangedListener.y(value);
+                    }
+                });
+            }
+        }
     }
     
     private ScrollView childScrollView;
@@ -105,6 +125,9 @@ public class MaxRelativeLayout extends RelativeLayout {
     
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
+        if (!interceptTouch) {
+            return super.onInterceptTouchEvent(event);
+        }
         if (onTouchListener != null) {
             onTouchListener.onTouch(this, event);
             switch (event.getAction()) {
@@ -175,4 +198,30 @@ public class MaxRelativeLayout extends RelativeLayout {
         this.lockWidth = lockWidth;
         return this;
     }
+    
+    private OnYChanged onYChangedListener;
+    
+    public interface OnYChanged {
+        void y(float y);
+    }
+    
+    @Override
+    public void setY(float y) {
+        super.setY(y);
+    }
+    
+    public OnYChanged getOnYChanged() {
+        return onYChangedListener;
+    }
+    
+    public MaxRelativeLayout setOnYChanged(OnYChanged onYChanged) {
+        this.onYChangedListener = onYChanged;
+        return this;
+    }
+    
+    @Override
+    public void setTranslationY(float translationY) {
+        super.setTranslationY(translationY);
+        if (onYChangedListener != null) onYChangedListener.y(translationY);
+    }
 }

+ 47 - 0
DialogX/src/main/res/layout/layout_dialogx_fullscreen.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:background="@color/black">
+
+    <com.kongzue.dialogx.util.views.ActivityScreenShotImageView
+        android:id="@+id/img_zoom_activity"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_centerInParent="true" />
+
+    <com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout
+        android:id="@+id/box_root"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/black20"
+        android:orientation="vertical">
+
+        <RelativeLayout
+            android:id="@+id/box_bkg"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+            <com.kongzue.dialogx.util.views.MaxRelativeLayout
+                android:id="@+id/bkg"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_alignParentBottom="true"
+                android:background="@drawable/rect_dialogx_material_bottom_bkg_light"
+                android:focusableInTouchMode="true">
+
+                <RelativeLayout
+                    android:id="@+id/box_custom"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:clickable="true"
+                    android:orientation="vertical"/>
+
+            </com.kongzue.dialogx.util.views.MaxRelativeLayout>
+
+        </RelativeLayout>
+
+    </com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>
+
+</RelativeLayout>

+ 1 - 0
DialogX/src/main/res/values/attrs.xml

@@ -5,6 +5,7 @@
         <attr name="maxLayoutWidth" format="dimension"/>
         <attr name="maxLayoutHeight" format="dimension"/>
         <attr name="lockWidth" format="boolean"/>
+        <attr name="interceptTouch" format="boolean"/>
     </declare-styleable>
 
     <declare-styleable name="RealtimeBlurView">

+ 3 - 3
README.md

@@ -17,9 +17,9 @@ DialogX开发计划
     InputDialog(extends MessageDialog)      √
     WaitDialog                              √
     TipDialog(extends WaitDialog)           √
-    BottomDialog                            -
-    BottomMenu                              -
-    FullScreenDialog                        ×
+    BottomDialog                            
+    BottomMenu                              
+    FullScreenDialog                        
     CustomDialog                            ×
     PopTip                                  ×
 

+ 2 - 0
app/src/main/AndroidManifest.xml

@@ -2,6 +2,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.kongzue.dialogxdemo">
 
+    <uses-permission android:name="android.permission.INTERNET" />
+
     <application
         android:name=".App"
         android:allowBackup="true"

+ 157 - 0
app/src/main/java/com/kongzue/dialogxdemo/MainActivity.java

@@ -1,9 +1,15 @@
 package com.kongzue.dialogxdemo;
 
+import android.content.ActivityNotFoundException;
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.Color;
+import android.net.Uri;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
 import android.widget.EditText;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -22,6 +28,7 @@ import com.kongzue.baseframework.util.JumpParameter;
 import com.kongzue.dialogx.DialogX;
 import com.kongzue.dialogx.dialogs.BottomDialog;
 import com.kongzue.dialogx.dialogs.BottomMenu;
+import com.kongzue.dialogx.dialogs.FullScreenDialog;
 import com.kongzue.dialogx.dialogs.InputDialog;
 import com.kongzue.dialogx.dialogs.MessageDialog;
 import com.kongzue.dialogx.dialogs.TipDialog;
@@ -51,6 +58,7 @@ public class MainActivity extends BaseActivity {
     private LinearLayout boxTableChild;
     private LinearLayout btnBack;
     private ImageView btnShare;
+    private TextView txtTitle;
     private LinearLayout boxBody;
     private RadioGroup grpStyle;
     private RadioButton rdoIos;
@@ -86,6 +94,7 @@ public class MainActivity extends BaseActivity {
         boxTableChild = findViewById(R.id.box_table_child);
         btnBack = findViewById(R.id.btn_back);
         btnShare = findViewById(R.id.btn_share);
+        txtTitle = findViewById(R.id.txt_title);
         boxBody = findViewById(R.id.box_body);
         grpStyle = findViewById(R.id.grp_style);
         rdoIos = findViewById(R.id.rdo_ios);
@@ -122,6 +131,7 @@ public class MainActivity extends BaseActivity {
         
         boolean showBreak = parameter.getBoolean("showBreak");
         if (showBreak) {
+            txtTitle.setText("显示Dialog时关闭Activity演示");
             MessageDialog.show("提示", "接下来会直接运行一个 WaitDialog,2 秒后直接关闭 Activity,并回到原 Activity,保证程序不会出现 WindowLeaked 错误。\n\n" +
                     "Android 原生 AlertDialog 常出现因 Dialog 先于 Activity 关闭而导致此错误引发程序崩溃。\n\n" +
                     "而使用 DialogX 构建的对话框不仅仅不会出现此问题,还可避免因句柄持续持有导致的内存泄漏。", "开始测试", "取消")
@@ -156,6 +166,16 @@ public class MainActivity extends BaseActivity {
     private TextView btnReplyCommit;
     private EditText editReplyCommit;
     
+    private TextView btnCancel;
+    private TextView btnSubmit;
+    private RelativeLayout boxUserName;
+    private EditText editUserName;
+    private RelativeLayout boxPassword;
+    private EditText editPassword;
+    
+    private TextView btnClose;
+    private WebView webView;
+    
     @Override
     public void setEvents() {
         grpTheme.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@@ -483,6 +503,143 @@ public class MainActivity extends BaseActivity {
                 jump(MainActivity.class, new JumpParameter().put("showBreak", true));
             }
         });
+        
+        btnFullScreenDialogLogin.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                FullScreenDialog.show(new OnBindView<FullScreenDialog>(R.layout.layout_full_login) {
+                    @Override
+                    public void onBind(FullScreenDialog dialog, View v) {
+                        btnCancel = v.findViewById(R.id.btn_cancel);
+                        btnSubmit = v.findViewById(R.id.btn_submit);
+                        boxUserName = v.findViewById(R.id.box_userName);
+                        editUserName = v.findViewById(R.id.edit_userName);
+                        boxPassword = v.findViewById(R.id.box_password);
+                        editPassword = v.findViewById(R.id.edit_password);
+                        
+                        initFullScreenLoginDemo(dialog);
+                    }
+                });
+            }
+        });
+        
+        btnFullScreenDialogWebPage.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                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);
+    
+                        btnClose.setOnClickListener(new View.OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+                                dialog.dismiss();
+                            }
+                        });
+    
+                        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;
+                            }
+        
+                            @Override
+                            public void onPageFinished(WebView view, String url) {
+                                super.onPageFinished(view, url);
+                            }
+                        });
+    
+                        webView.loadUrl("https://github.com/kongzue/DialogV3/");
+                    }
+                });
+            }
+        });
+    }
+    
+    private void initFullScreenLoginDemo(final FullScreenDialog fullScreenDialog) {
+        btnCancel.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                fullScreenDialog.dismiss();
+            }
+        });
+        
+        btnCancel.setText("取消");
+        btnSubmit.setText("下一步");
+        btnSubmit.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (isNull(editUserName.getText().toString().trim())) {
+                    hideIME(null);
+                    TipDialog.show("请输入账号", TipDialog.TYPE.WARNING);
+                    return;
+                }
+                
+                boxUserName.animate().x(-getDisplayWidth()).setDuration(300);
+                boxPassword.setX(getDisplayWidth());
+                boxPassword.setVisibility(View.VISIBLE);
+                boxPassword.animate().x(0).setDuration(300);
+                
+                editPassword.setFocusable(true);
+                editPassword.requestFocus();
+                
+                btnCancel.setText("上一步");
+                btnCancel.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        boxUserName.animate().x(0).setDuration(300);
+                        boxPassword.animate().x(getDisplayWidth()).setDuration(300);
+                        
+                        editUserName.setFocusable(true);
+                        editUserName.requestFocus();
+                        
+                        initFullScreenLoginDemo(fullScreenDialog);
+                    }
+                });
+                
+                btnSubmit.setText("登录");
+                btnSubmit.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        hideIME(null);
+                        if (isNull(editPassword.getText().toString().trim())) {
+                            TipDialog.show("请输入密码", TipDialog.TYPE.WARNING);
+                            return;
+                        }
+                        WaitDialog.show("登录中...");
+                        runOnMainDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                TipDialog.show("登录成功", TipDialog.TYPE.SUCCESS).setDialogLifecycleCallback(new DialogLifecycleCallback<WaitDialog>() {
+                                    @Override
+                                    public void onDismiss(WaitDialog dialog) {
+                                        fullScreenDialog.dismiss();
+                                    }
+                                });
+                            }
+                        }, 2000);
+                    }
+                });
+            }
+        });
     }
     
     @Override

+ 9 - 0
app/src/main/res/drawable/ios_edit_box_bkg.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+    <selector>
+        <item
+            android:drawable="@drawable/rect_ios_edit_box_bkg_focus"
+            android:state_focused="true" />
+        <item android:drawable="@drawable/rect_ios_edit_box_bkg_normal" />
+    </selector>
+</inset>

+ 10 - 0
app/src/main/res/drawable/rect_ios_edit_box_bkg_focus.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <!-- 填充颜色 -->
+    <solid android:color="#E3E3E4"></solid>
+
+    <!-- 矩形的圆角半径 -->
+    <corners android:radius="17dp" />
+
+</shape>

+ 10 - 0
app/src/main/res/drawable/rect_ios_edit_box_bkg_normal.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <!-- 填充颜色 -->
+    <solid android:color="#F3F3F4"></solid>
+
+    <!-- 矩形的圆角半径 -->
+    <corners android:radius="17dp" />
+
+</shape>

+ 1 - 0
app/src/main/res/layout/activity_main.xml

@@ -81,6 +81,7 @@
                     android:background="#a6a8a9" />
 
                 <TextView
+                    android:id="@+id/txt_title"
                     android:layout_width="wrap_content"
                     android:layout_height="50dp"
                     android:layout_alignParentBottom="true"

+ 157 - 0
app/src/main/res/layout/layout_full_login.xml

@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="600dp"
+    android:gravity="center_horizontal"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="50dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/btn_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:paddingHorizontal="15dp"
+            android:text="取消"
+            android:textColor="@color/dialogxIOSBlue"
+            android:textSize="18dp" />
+
+        <Space
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1" />
+
+        <TextView
+            android:id="@+id/btn_submit"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:paddingHorizontal="15dp"
+            android:text="下一步"
+            android:textColor="@color/dialogxIOSBlue"
+            android:textSize="18dp" />
+
+    </LinearLayout>
+
+    <ImageView
+        android:layout_width="80dp"
+        android:layout_height="80dp"
+        android:layout_marginTop="30dp"
+        android:src="@mipmap/img_login" />
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="25dp">
+
+        <RelativeLayout
+            android:id="@+id/box_userName"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingLeft="25dp"
+            android:paddingRight="25dp">
+
+            <EditText
+                android:id="@+id/edit_userName"
+                android:layout_width="match_parent"
+                android:layout_height="50dp"
+                android:background="@drawable/ios_edit_box_bkg"
+                android:gravity="center"
+                android:hint="请输入账号"
+                android:inputType="textEmailAddress" />
+
+        </RelativeLayout>
+
+        <RelativeLayout
+            android:id="@+id/box_password"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingLeft="25dp"
+            android:paddingRight="25dp"
+            android:visibility="gone">
+
+            <EditText
+                android:id="@+id/edit_password"
+                android:layout_width="match_parent"
+                android:layout_height="50dp"
+                android:background="@drawable/ios_edit_box_bkg"
+                android:gravity="center"
+                android:hint="请输入密码"
+                android:inputType="textPassword" />
+
+        </RelativeLayout>
+
+    </FrameLayout>
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="25dp"
+        android:gravity="center"
+        android:text="登录后,您可以:"
+        android:textColor="@color/black"
+        android:textSize="13dp"
+        android:textStyle="bold" />
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="15dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="· 使用云同步备份您的存档文件"
+            android:textColor="@color/black75"
+            android:textSize="13dp" />
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="7dp"
+            android:text="· 享受随时随地的客户服务及7*24小时电话咨询服务"
+            android:textColor="@color/black75"
+            android:textSize="13dp" />
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="7dp"
+            android:text="· 免费的远程协助和更大的云端存储空间"
+            android:textColor="@color/black75"
+            android:textSize="13dp" />
+
+    </LinearLayout>
+
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="15dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="25dp"
+            android:gravity="center"
+            android:text="登录代表您同意"
+            android:textColor="@color/black"
+            android:textSize="13dp" />
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="25dp"
+            android:gravity="center"
+            android:text="《用户服务条款》"
+            android:textColor="@color/dialogxIOSBlue"
+            android:textSize="13dp" />
+
+    </LinearLayout>
+</LinearLayout>

+ 33 - 0
app/src/main/res/layout/layout_full_webview.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="50dp"
+        android:orientation="horizontal">
+
+        <Space
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1" />
+
+        <TextView
+            android:id="@+id/btn_close"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:paddingHorizontal="15dp"
+            android:text="关闭"
+            android:textColor="@color/dialogxIOSBlue"
+            android:textSize="18dp" />
+
+    </LinearLayout>
+
+    <WebView
+        android:id="@+id/webView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</LinearLayout>

BIN
app/src/main/res/mipmap-xxhdpi/img_login.png