onBindView) {
+ BottomDialog bottomDialog = new BottomDialog(onBindView);
+ bottomDialog.show();
+ return bottomDialog;
+ }
+
+ public void show() {
+ super.beforeShow();
+ int layoutId = isLightTheme() ? R.layout.layout_dialogx_bottom_material : R.layout.layout_dialogx_bottom_material_dark;
+ if (style.overrideBottomDialogRes() != null) {
+ layoutId = style.overrideBottomDialogRes().overrideDialogLayout(isLightTheme());
+ }
+
+ dialogView = createView(layoutId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+
+ public void show(Activity activity) {
+ super.beforeShow();
+ int layoutId = isLightTheme() ? R.layout.layout_dialogx_bottom_material : R.layout.layout_dialogx_bottom_material_dark;
+ if (style.overrideBottomDialogRes() != null) {
+ layoutId = style.overrideBottomDialogRes().overrideDialogLayout(isLightTheme());
+ }
+
+ dialogView = createView(layoutId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(activity, dialogView);
+ }
+
+ protected DialogImpl dialogImpl;
+
+ public class DialogImpl implements DialogConvertViewInterface {
+
+ private BottomDialogTouchEventInterceptor bottomDialogTouchEventInterceptor;
+
+ public DialogXBaseRelativeLayout boxRoot;
+ public RelativeLayout boxBkg;
+ public MaxRelativeLayout bkg;
+ public ViewGroup boxBody;
+ public ImageView imgTab;
+ public TextView txtDialogTitle;
+ public ScrollView scrollView;
+ public LinearLayout boxContent;
+ public TextView txtDialogTip;
+ public View imgSplit;
+ public RelativeLayout boxList;
+ public RelativeLayout boxCustom;
+ public BlurView blurView;
+ public ViewGroup boxCancel;
+ public TextView btnCancel;
+ public BlurView cancelBlurView;
+
+ public TextView btnSelectOther;
+ public TextView btnSelectPositive;
+
+ public DialogImpl(View convertView) {
+ boxRoot = convertView.findViewById(R.id.box_root);
+ boxBkg = convertView.findViewById(R.id.box_bkg);
+ bkg = convertView.findViewById(R.id.bkg);
+ boxBody = convertView.findViewWithTag("body");
+ imgTab = convertView.findViewById(R.id.img_tab);
+ txtDialogTitle = convertView.findViewById(R.id.txt_dialog_title);
+ scrollView = convertView.findViewById(R.id.scrollView);
+ boxContent = convertView.findViewById(R.id.box_content);
+ txtDialogTip = convertView.findViewById(R.id.txt_dialog_tip);
+ 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");
+
+ btnSelectOther = convertView.findViewById(R.id.btn_selectOther);
+ btnSelectPositive = convertView.findViewById(R.id.btn_selectPositive);
+
+ init();
+ dialogImpl = this;
+ refreshView();
+ }
+
+ public void reBuild() {
+ init();
+ dialogImpl = this;
+ refreshView();
+ }
+
+ /**
+ * 此值记录了BottomDialog启动后的位置
+ * ·当内容高度大于屏幕安全区高度时,BottomDialog会以全屏方式启动,但一开始只会展开到 0.8×屏幕高度,
+ * 此时可以再次上划查看全部内容。
+ * ·当内容高度小于屏幕安全区高度时,BottomDialog会以内容高度启动。
+ *
+ * 记录这个值的目的是,当用户向下滑动时,判断情况该回到这个位置还是关闭对话框,
+ * 并阻止当内容高度已经完全显示时的继续向上滑动操作。
+ */
+ public float bkgEnterAimY = -1;
+
+ @Override
+ public void init() {
+ if (titleTextInfo == null) titleTextInfo = DialogX.menuTitleInfo;
+ if (titleTextInfo == null) titleTextInfo = DialogX.titleTextInfo;
+ if (messageTextInfo == null) messageTextInfo = DialogX.messageTextInfo;
+ if (okTextInfo == null) okTextInfo = DialogX.okButtonTextInfo;
+ if (okTextInfo == null) okTextInfo = DialogX.buttonTextInfo;
+ if (cancelTextInfo == null) cancelTextInfo = DialogX.buttonTextInfo;
+ if (otherTextInfo == null) otherTextInfo = DialogX.buttonTextInfo;
+ if (backgroundColor == -1) backgroundColor = DialogX.backgroundColor;
+ if (cancelText == null) cancelText = DialogX.cancelButtonText;
+
+ txtDialogTitle.getPaint().setFakeBoldText(true);
+ if (btnCancel != null) btnCancel.getPaint().setFakeBoldText(true);
+ if (btnSelectPositive != null) btnSelectPositive.getPaint().setFakeBoldText(true);
+ if (btnSelectOther != null) btnSelectOther.getPaint().setFakeBoldText(true);
+
+ boxRoot.setParentDialog(me);
+ boxRoot.setOnLifecycleCallBack(new DialogXBaseRelativeLayout.OnLifecycleCallBack() {
+ @Override
+ public void onShow() {
+ bkg.setY(getRootFrameLayout().getMeasuredHeight());
+
+ isShow = true;
+ boxRoot.setAlpha(0f);
+
+ boxContent.getViewTreeObserver().addOnGlobalLayoutListener(onContentViewLayoutChangeListener);
+
+ getDialogLifecycleCallback().onShow(me);
+
+ onDialogInit(dialogImpl);
+
+ 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(bkg.getContext(), null);
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(bkg.getWidth(), bkg.getHeight());
+ blurView.setOverlayColor(backgroundColor == -1 ? blurFrontColor : backgroundColor);
+ blurView.setTag("blurView");
+ blurView.setRadiusPx(style.messageDialogBlurSettings().blurBackgroundRoundRadiusPx());
+ boxBody.addView(blurView, 0, params);
+
+ cancelBlurView = new BlurView(boxCancel.getContext(), null);
+ RelativeLayout.LayoutParams cancelButtonLp = new RelativeLayout.LayoutParams(boxCancel.getWidth(), boxCancel.getHeight());
+ cancelBlurView.setOverlayColor(backgroundColor == -1 ? blurFrontColor : backgroundColor);
+ cancelBlurView.setTag("blurView");
+ cancelBlurView.setRadiusPx(style.messageDialogBlurSettings().blurBackgroundRoundRadiusPx());
+ boxCancel.addView(cancelBlurView, 0, cancelButtonLp);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onDismiss() {
+ isShow = false;
+ getDialogLifecycleCallback().onDismiss(me);
+ }
+ });
+
+ if (btnCancel != null) {
+ btnCancel.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (cancelButtonClickListener != null) {
+ if (!cancelButtonClickListener.onClick(me, v)) {
+ dismiss();
+ }
+ } else {
+ dismiss();
+ }
+ }
+ });
+ }
+ if (btnSelectOther != null) {
+ btnSelectOther.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (otherButtonClickListener != null) {
+ if (!otherButtonClickListener.onClick(me, v)) {
+ dismiss();
+ }
+ } else {
+ dismiss();
+ }
+ }
+ });
+ }
+ if (btnSelectPositive != null) {
+ btnSelectPositive.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (okButtonClickListener != null) {
+ if (!okButtonClickListener.onClick(me, v)) {
+ dismiss();
+ }
+ } else {
+ dismiss();
+ }
+ }
+ });
+ }
+
+ if (imgSplit != null) {
+ int dividerRes = style.overrideBottomDialogRes().overrideMenuDividerDrawableRes(isLightTheme());
+ int dividerHeight = style.overrideBottomDialogRes().overrideMenuDividerHeight(isLightTheme());
+ if (dividerRes != 0) imgSplit.setBackgroundResource(dividerRes);
+ if (dividerHeight != 0) {
+ ViewGroup.LayoutParams lp = imgSplit.getLayoutParams();
+ lp.height = dividerHeight;
+ imgSplit.setLayoutParams(lp);
+ }
+ }
+
+ boxRoot.setOnBackPressedListener(new OnBackPressedListener() {
+ @Override
+ public boolean onBackPressed() {
+ if (onBackPressedListener != null && onBackPressedListener.onBackPressed()) {
+ dismiss();
+ return false;
+ }
+ if (isCancelable()) {
+ dismiss();
+ }
+ return false;
+ }
+ });
+
+ bottomDialogTouchEventInterceptor = new BottomDialogTouchEventInterceptor(me, dialogImpl);
+
+ boxRoot.post(new Runnable() {
+ @Override
+ public void run() {
+ long enterAnimDurationTemp = 300;
+ /**
+ * 对于非支持滑动展开的对话框,直接使用从下往上的资源动画实现
+ * 其他情况不适用,请参考 onContentViewLayoutChangeListener 的代码实现。
+ */
+ if (style.overrideBottomDialogRes() == null || !style.overrideBottomDialogRes().touchSlide()) {
+ //bkg.setY(getRootFrameLayout().getMeasuredHeight());
+ Animation enterAnim = AnimationUtils.loadAnimation(getContext(), R.anim.anim_dialogx_bottom_enter);
+ enterAnimDurationTemp = enterAnim.getDuration();
+ if (overrideEnterDuration >= 0) {
+ enterAnimDurationTemp = overrideEnterDuration;
+ }
+ if (enterAnimDuration >= 0) {
+ enterAnimDurationTemp = enterAnimDuration;
+ }
+ enterAnim.setDuration(enterAnimDurationTemp);
+ enterAnim.setInterpolator(new DecelerateInterpolator(2f));
+
+ bkg.setY(bkgEnterAimY);
+ bkg.startAnimation(enterAnim);
+ }
+
+ boxRoot.animate()
+ .setDuration(enterAnimDurationTemp)
+ .alpha(1f)
+ .setInterpolator(new DecelerateInterpolator())
+ .setListener(null);
+ }
+ });
+ }
+
+ private boolean isEnterAnimFinished = false;
+
+ private ViewTreeObserver.OnGlobalLayoutListener onContentViewLayoutChangeListener = new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (boxContent != null) {
+ if (style.overrideBottomDialogRes() != null &&style.overrideBottomDialogRes().touchSlide()) {
+ //若内容布已经超出屏幕可用范围,且预设的对话框最大高度已知
+ if (bkg.isChildScrollViewCanScroll() && bottomDialogMaxHeight != 0) {
+ //先将内容布局放置到屏幕底部以外区域,然后执行上移动画
+ if (!isEnterAnimFinished)bkg.setY(getRootFrameLayout().getMeasuredHeight());
+ //执行上移动画
+ if (bottomDialogMaxHeight <= 1) {
+ //bottomDialogMaxHeight 值若为小于 1 的小数,视为比例
+ bkgEnterAimY = boxBkg.getHeight() - bkg.getHeight() * bottomDialogMaxHeight;
+ } else {
+ bkgEnterAimY = boxBkg.getHeight() - bottomDialogMaxHeight;
+ }
+ long enterAnimDurationTemp = 300;
+ if (overrideEnterDuration >= 0) {
+ enterAnimDurationTemp = overrideEnterDuration;
+ }
+ if (enterAnimDuration >= 0) {
+ enterAnimDurationTemp = enterAnimDuration;
+ }
+ ObjectAnimator keepBottomAnim = ObjectAnimator.ofFloat(bkg, "y", bkg.getY(), bkgEnterAimY);
+ keepBottomAnim.setDuration(enterAnimDurationTemp);
+ keepBottomAnim.setInterpolator(new DecelerateInterpolator(2f));
+ keepBottomAnim.start();
+ } else {
+ bkgEnterAimY = boxBkg.getHeight() - bkg.getHeight();
+ if (!isEnterAnimFinished)bkg.setY(boxRoot.getHeight());
+ bkg.post(new Runnable() {
+ @Override
+ public void run() {
+ ObjectAnimator enterAnim = ObjectAnimator.ofFloat(bkg, "y", bkg.getY(), bkgEnterAimY);
+ long enterAnimDurationTemp = 300;
+ if (overrideEnterDuration >= 0) {
+ enterAnimDurationTemp = overrideEnterDuration;
+ }
+ if (enterAnimDuration >= 0) {
+ enterAnimDurationTemp = enterAnimDuration;
+ }
+ enterAnim.setDuration(enterAnimDurationTemp);
+ enterAnim.setInterpolator(new DecelerateInterpolator(2f));
+ enterAnim.start();
+ }
+ });
+ }
+ }else{
+ bkgEnterAimY = boxBkg.getHeight() - bkg.getHeight();
+ }
+ }
+ isEnterAnimFinished = true;
+ }
+ };
+
+ @Override
+ public void refreshView() {
+ if (backgroundColor != -1) {
+ tintColor(bkg, backgroundColor);
+ if (blurView != null && cancelBlurView != null) {
+ blurView.setOverlayColor(backgroundColor);
+ cancelBlurView.setOverlayColor(backgroundColor);
+ }
+ }
+
+ showText(txtDialogTitle, title);
+ showText(txtDialogTip, message);
+
+ useTextInfo(txtDialogTitle, titleTextInfo);
+ useTextInfo(txtDialogTip, messageTextInfo);
+ useTextInfo(btnCancel, cancelTextInfo);
+ useTextInfo(btnSelectOther, otherTextInfo);
+ useTextInfo(btnSelectPositive, okTextInfo);
+
+ if (isCancelable()) {
+ boxRoot.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ doDismiss(v);
+ }
+ });
+ } else {
+ boxRoot.setOnClickListener(null);
+ }
+ boxBkg.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boxRoot.callOnClick();
+ }
+ });
+
+ if (maskColor != -1) boxRoot.setBackgroundColor(maskColor);
+
+ if (onBindView != null && onBindView.getCustomView() != null) {
+ onBindView.bindParent(boxCustom, me);
+ }
+
+ if (isAllowInterceptTouch() && isCancelable()) {
+ if (imgTab != null) imgTab.setVisibility(View.VISIBLE);
+ } else {
+ if (imgTab != null) imgTab.setVisibility(View.GONE);
+ }
+
+ bottomDialogTouchEventInterceptor.refresh(me, this);
+
+ if (imgSplit != null) {
+ if (txtDialogTitle.getVisibility() == View.VISIBLE || txtDialogTip.getVisibility() == View.VISIBLE) {
+ imgSplit.setVisibility(View.VISIBLE);
+ } else {
+ imgSplit.setVisibility(View.GONE);
+ }
+ }
+
+ if (boxCancel != null) {
+ if (isNull(cancelText)) {
+ boxCancel.setVisibility(View.GONE);
+ } else {
+ boxCancel.setVisibility(View.VISIBLE);
+ }
+ }
+
+ showText(btnSelectPositive, okText);
+ showText(btnCancel, cancelText);
+ showText(btnSelectOther, otherText);
+ }
+
+ @Override
+ public void doDismiss(View v) {
+ if (v != null) v.setEnabled(false);
+
+ if (boxContent != null)
+ boxContent.getViewTreeObserver().removeOnGlobalLayoutListener(onContentViewLayoutChangeListener);
+
+ ObjectAnimator exitAnim = ObjectAnimator.ofFloat(bkg, "y", bkg.getY(), boxBkg.getHeight());
+ long exitAnimDurationTemp = 300;
+ if (overrideExitDuration >= 0) {
+ exitAnimDurationTemp = overrideExitDuration;
+ }
+ if (exitAnimDuration >= 0) {
+ exitAnimDurationTemp = exitAnimDuration;
+ }
+ exitAnim.setDuration(exitAnimDurationTemp);
+ exitAnim.start();
+
+ boxRoot.animate()
+ .alpha(0f)
+ .setInterpolator(new AccelerateInterpolator())
+ .setDuration(exitAnimDurationTemp);
+
+ new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ dismiss(dialogView);
+ }
+ }, exitAnimDurationTemp);
+ }
+
+ public void preDismiss() {
+ if (isCancelable()) {
+ doDismiss(boxRoot);
+ } else {
+ long exitAnimDurationTemp = 300;
+ if (overrideExitDuration >= 0) {
+ exitAnimDurationTemp = overrideExitDuration;
+ }
+ if (exitAnimDuration >= 0) {
+ exitAnimDurationTemp = exitAnimDuration;
+ }
+ ObjectAnimator exitAnim = ObjectAnimator.ofFloat(bkg, "y", bkg.getY(), bkgEnterAimY);
+ exitAnim.setDuration(exitAnimDurationTemp);
+ exitAnim.start();
+ }
+ }
+ }
+
+ protected void onDialogInit(DialogImpl dialog) {
+ }
+
+ public void refreshUI() {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ if (dialogImpl != null) dialogImpl.refreshView();
+ }
+ });
+ }
+
+ public void dismiss() {
+ if (dialogImpl == null) return;
+ dialogImpl.doDismiss(null);
+ }
+
+ public DialogLifecycleCallback getDialogLifecycleCallback() {
+ return dialogLifecycleCallback == null ? new DialogLifecycleCallback() {
+ } : dialogLifecycleCallback;
+ }
+
+ public BottomDialog setDialogLifecycleCallback(DialogLifecycleCallback dialogLifecycleCallback) {
+ this.dialogLifecycleCallback = dialogLifecycleCallback;
+ if (isShow) dialogLifecycleCallback.onShow(me);
+ return this;
+ }
+
+ public OnBackPressedListener getOnBackPressedListener() {
+ return onBackPressedListener;
+ }
+
+ public BottomDialog setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
+ this.onBackPressedListener = onBackPressedListener;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setStyle(DialogXStyle style) {
+ this.style = style;
+ return this;
+ }
+
+ public BottomDialog setTheme(DialogX.THEME theme) {
+ this.theme = theme;
+ return this;
+ }
+
+ public boolean isCancelable() {
+ if (privateCancelable != null) {
+ return privateCancelable == BOOLEAN.TRUE;
+ }
+ if (overrideCancelable != null) {
+ return overrideCancelable == BOOLEAN.TRUE;
+ }
+ return cancelable;
+ }
+
+ public BottomDialog setCancelable(boolean cancelable) {
+ this.privateCancelable = cancelable ? BOOLEAN.TRUE : BOOLEAN.FALSE;
+ refreshUI();
+ return this;
+ }
+
+ public DialogImpl getDialogImpl() {
+ return dialogImpl;
+ }
+
+ public CharSequence getTitle() {
+ return title;
+ }
+
+ public BottomDialog setTitle(CharSequence title) {
+ this.title = title;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setTitle(int titleResId) {
+ this.title = getString(titleResId);
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getMessage() {
+ return message;
+ }
+
+ public BottomDialog setMessage(CharSequence message) {
+ this.message = message;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setMessage(int messageResId) {
+ this.message = getString(messageResId);
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getCancelButton() {
+ return cancelText;
+ }
+
+ public BottomDialog setCancelButton(CharSequence cancelText) {
+ this.cancelText = cancelText;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setCancelButton(int cancelTextResId) {
+ this.cancelText = getString(cancelTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setCancelButton(OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ return this;
+ }
+
+ public BottomDialog setCancelButton(CharSequence cancelText, OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelText = cancelText;
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setCancelButton(int cancelTextResId, OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelText = getString(cancelTextResId);
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setCustomView(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ refreshUI();
+ return this;
+ }
+
+ public View getCustomView() {
+ if (onBindView == null) return null;
+ return onBindView.getCustomView();
+ }
+
+ public BottomDialog removeCustomView() {
+ this.onBindView.clean();
+ refreshUI();
+ return this;
+ }
+
+ public boolean isAllowInterceptTouch() {
+ if (style.overrideBottomDialogRes() == null) {
+ return false;
+ } else {
+ return allowInterceptTouch && style.overrideBottomDialogRes().touchSlide();
+ }
+ }
+
+ public BottomDialog setAllowInterceptTouch(boolean allowInterceptTouch) {
+ this.allowInterceptTouch = allowInterceptTouch;
+ refreshUI();
+ return this;
+ }
+
+ public OnDialogButtonClickListener getCancelButtonClickListener() {
+ return cancelButtonClickListener;
+ }
+
+ public BottomDialog setCancelButtonClickListener(OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ return this;
+ }
+
+ public TextInfo getTitleTextInfo() {
+ return titleTextInfo;
+ }
+
+ public BottomDialog setTitleTextInfo(TextInfo titleTextInfo) {
+ this.titleTextInfo = titleTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getMessageTextInfo() {
+ return messageTextInfo;
+ }
+
+ public BottomDialog setMessageTextInfo(TextInfo messageTextInfo) {
+ this.messageTextInfo = messageTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getCancelTextInfo() {
+ return cancelTextInfo;
+ }
+
+ public BottomDialog setCancelTextInfo(TextInfo cancelTextInfo) {
+ this.cancelTextInfo = cancelTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public int getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public BottomDialog setBackgroundColor(@ColorInt int backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setBackgroundColorRes(@ColorRes int backgroundRes) {
+ this.backgroundColor = getColor(backgroundRes);
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getOkButton() {
+ return okText;
+ }
+
+ public BottomDialog setOkButton(CharSequence okText) {
+ this.okText = okText;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setOkButton(int OkTextResId) {
+ this.okText = getString(OkTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setOkButton(OnDialogButtonClickListener OkButtonClickListener) {
+ this.okButtonClickListener = OkButtonClickListener;
+ return this;
+ }
+
+ public BottomDialog setOkButton(CharSequence OkText, OnDialogButtonClickListener OkButtonClickListener) {
+ this.okText = OkText;
+ this.okButtonClickListener = OkButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setOkButton(int OkTextResId, OnDialogButtonClickListener OkButtonClickListener) {
+ this.okText = getString(OkTextResId);
+ this.okButtonClickListener = OkButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getOtherButton() {
+ return otherText;
+ }
+
+ public BottomDialog setOtherButton(CharSequence otherText) {
+ this.otherText = otherText;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setOtherButton(int OtherTextResId) {
+ this.otherText = getString(OtherTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setOtherButton(OnDialogButtonClickListener OtherButtonClickListener) {
+ this.otherButtonClickListener = OtherButtonClickListener;
+ return this;
+ }
+
+ public BottomDialog setOtherButton(CharSequence OtherText, OnDialogButtonClickListener OtherButtonClickListener) {
+ this.otherText = OtherText;
+ this.otherButtonClickListener = OtherButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setOtherButton(int OtherTextResId, OnDialogButtonClickListener OtherButtonClickListener) {
+ this.otherText = getString(OtherTextResId);
+ this.otherButtonClickListener = OtherButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public BottomDialog setMaskColor(@ColorInt int maskColor) {
+ this.maskColor = maskColor;
+ refreshUI();
+ return this;
+ }
+
+ public long getEnterAnimDuration() {
+ return enterAnimDuration;
+ }
+
+ public BottomDialog setEnterAnimDuration(long enterAnimDuration) {
+ this.enterAnimDuration = enterAnimDuration;
+ return this;
+ }
+
+ public long getExitAnimDuration() {
+ return exitAnimDuration;
+ }
+
+ public BottomDialog setExitAnimDuration(long exitAnimDuration) {
+ this.exitAnimDuration = exitAnimDuration;
+ return this;
+ }
+
+ @Override
+ public void onUIModeChange(Configuration newConfig) {
+ if (dialogView != null) {
+ dismiss(dialogView);
+ }
+ if (getDialogImpl().boxCustom != null) {
+ getDialogImpl().boxCustom.removeAllViews();
+ }
+ if (getDialogImpl().boxList != null) {
+ getDialogImpl().boxList.removeAllViews();
+ }
+ int layoutId = isLightTheme() ? R.layout.layout_dialogx_bottom_material : R.layout.layout_dialogx_bottom_material_dark;
+ if (style.overrideBottomDialogRes() != null) {
+ layoutId = style.overrideBottomDialogRes().overrideDialogLayout(isLightTheme());
+ }
+
+ enterAnimDuration = 0;
+ dialogView = createView(layoutId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/dialogs/BottomMenu.java b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/BottomMenu.java
new file mode 100644
index 0000000..110a476
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/BottomMenu.java
@@ -0,0 +1,1065 @@
+package com.kongzue.dialogx.dialogs;
+
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.R;
+import com.kongzue.dialogx.interfaces.BottomMenuListViewTouchEvent;
+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.OnIconChangeCallBack;
+import com.kongzue.dialogx.interfaces.OnMenuItemClickListener;
+import com.kongzue.dialogx.interfaces.OnMenuItemSelectListener;
+import com.kongzue.dialogx.util.NormalMenuArrayAdapter;
+import com.kongzue.dialogx.util.TextInfo;
+import com.kongzue.dialogx.util.views.BottomDialogListView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static android.view.View.OVER_SCROLL_NEVER;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/6 23:48
+ */
+public class BottomMenu extends BottomDialog {
+
+ public enum SELECT_MODE {
+ NONE,
+ SINGLE,
+ MULTIPLE
+ }
+
+ protected BottomMenu me = this;
+ protected int selectionIndex = -1;
+ protected SELECT_MODE selectMode = SELECT_MODE.NONE;
+ protected ArrayList selectionItems;
+
+ protected OnMenuItemClickListener onMenuItemClickListener;
+
+ public static BottomMenu build() {
+ return new BottomMenu();
+ }
+
+ protected BottomMenu() {
+ super();
+ if (style.overrideBottomDialogRes() != null) {
+ bottomDialogMaxHeight = style.overrideBottomDialogRes().overrideBottomDialogMaxHeight();
+ }
+ if (bottomDialogMaxHeight <= 1 && bottomDialogMaxHeight > 0f) {
+ bottomDialogMaxHeight = (int) (getRootFrameLayout().getMeasuredHeight() * bottomDialogMaxHeight);
+ }
+ }
+
+ private OnIconChangeCallBack onIconChangeCallBack;
+ private BottomDialogListView listView;
+ private BaseAdapter menuListAdapter;
+ private List menuList;
+
+ public static BottomMenu show(List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu showStringList(List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.setMenuStringList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu showStringList(List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.setMenuStringList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(String[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(String[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, CharSequence message, List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, CharSequence message, List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu showStringList(CharSequence title, CharSequence message, List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuStringList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu showStringList(CharSequence title, CharSequence message, List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuStringList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, CharSequence message, String[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, CharSequence message, String[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, CharSequence message, CharSequence[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, CharSequence message, CharSequence[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(String title, String message, List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(String title, String message, List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu showStringList(String title, String message, List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuStringList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu showStringList(String title, String message, List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuStringList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(String title, String message, String[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(String title, String message, String[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(String title, String message, CharSequence[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(String title, String message, CharSequence[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.message = message;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, int messageResId, List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.message = bottomMenu.getString(messageResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu showStringList(int titleResId, int messageResId, List menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.message = bottomMenu.getString(messageResId);
+ bottomMenu.setMenuStringList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, int messageResId, String[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.message = bottomMenu.getString(messageResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, int messageResId, CharSequence[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.message = bottomMenu.getString(messageResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, int messageResId, List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.message = bottomMenu.getString(messageResId);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu showStringList(int titleResId, int messageResId, List menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.message = bottomMenu.getString(messageResId);
+ bottomMenu.setMenuStringList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, int messageResId, String[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.message = bottomMenu.getString(messageResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, int messageResId, CharSequence[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.message = bottomMenu.getString(messageResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, CharSequence[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, String[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, CharSequence[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(CharSequence title, String[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = title;
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, CharSequence[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, String[] menuList) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, CharSequence[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ public static BottomMenu show(int titleResId, String[] menuList, OnMenuItemClickListener onMenuItemClickListener) {
+ BottomMenu bottomMenu = new BottomMenu();
+ bottomMenu.title = bottomMenu.getString(titleResId);
+ bottomMenu.setMenuList(menuList);
+ bottomMenu.setOnMenuItemClickListener(onMenuItemClickListener);
+ bottomMenu.show();
+ return bottomMenu;
+ }
+
+ private float curTouchY;
+
+ public static final int ITEM_CLICK_DELAY = 100;
+ private long lastClickTime = 0;
+
+ @Override
+ protected void onDialogInit(final DialogImpl dialog) {
+ if (dialog != null) {
+ dialog.boxList.setVisibility(View.VISIBLE);
+
+ if (!isAllowInterceptTouch()) {
+ dialog.bkg.setMaxHeight((int) bottomDialogMaxHeight);
+ if (bottomDialogMaxHeight != 0) {
+ dialogImpl.scrollView.setEnabled(false);
+ }
+ }
+
+ int dividerDrawableResId = 0;
+ int dividerHeight = 1;
+ if (style.overrideBottomDialogRes() != null) {
+ dividerDrawableResId = style.overrideBottomDialogRes().overrideMenuDividerDrawableRes(isLightTheme());
+ dividerHeight = style.overrideBottomDialogRes().overrideMenuDividerHeight(isLightTheme());
+ }
+ if (dividerDrawableResId == 0) {
+ dividerDrawableResId = isLightTheme() ? R.drawable.rect_dialogx_material_menu_split_divider : R.drawable.rect_dialogx_material_menu_split_divider_night;
+ }
+
+ listView = new BottomDialogListView(dialog, getContext());
+ listView.setOverScrollMode(OVER_SCROLL_NEVER);
+ listView.setDivider(getResources().getDrawable(dividerDrawableResId));
+ listView.setDividerHeight(dividerHeight);
+
+ listView.setBottomMenuListViewTouchEvent(new BottomMenuListViewTouchEvent() {
+ @Override
+ public void down(MotionEvent event) {
+ curTouchY = dialog.bkg.getY();
+ }
+
+ @Override
+ public void move(MotionEvent event) {
+ curTouchY = event.getRawY();
+ }
+ });
+
+ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ long currentTime = System.currentTimeMillis();
+ if (currentTime - lastClickTime > ITEM_CLICK_DELAY) {
+ lastClickTime = currentTime;
+ float deltaY = Math.abs(curTouchY - dialog.bkg.getY());
+ if (deltaY > dip2px(15)) {
+ return;
+ }
+ switch (selectMode) {
+ case NONE:
+ if (onMenuItemClickListener != null) {
+ if (!onMenuItemClickListener.onClick(me, menuList.get(position), position)) {
+ dismiss();
+ }
+ } else {
+ dismiss();
+ }
+ break;
+ case SINGLE:
+ if (onMenuItemClickListener instanceof OnMenuItemSelectListener) {
+ OnMenuItemSelectListener onMenuItemSelectListener = (OnMenuItemSelectListener) onMenuItemClickListener;
+ if (!onMenuItemSelectListener.onClick(me, menuList.get(position), position)) {
+ dismiss();
+ } else {
+ selectionIndex = position;
+ menuListAdapter.notifyDataSetInvalidated();
+ menuListAdapter.notifyDataSetChanged();
+ onMenuItemSelectListener.onOneItemSelect(me, menuList.get(position), position);
+ }
+ } else {
+ if (onMenuItemClickListener != null) {
+ if (!onMenuItemClickListener.onClick(me, menuList.get(position), position)) {
+ dismiss();
+ }
+ } else {
+ dismiss();
+ }
+ }
+ break;
+ case MULTIPLE:
+ if (onMenuItemClickListener instanceof OnMenuItemSelectListener) {
+ OnMenuItemSelectListener onMenuItemSelectListener = (OnMenuItemSelectListener) onMenuItemClickListener;
+ if (!onMenuItemSelectListener.onClick(me, menuList.get(position), position)) {
+ dismiss();
+ } else {
+ if (selectionItems.contains(position)) {
+ selectionItems.remove(new Integer(position));
+ } else {
+ selectionItems.add(position);
+ }
+ menuListAdapter.notifyDataSetInvalidated();
+ menuListAdapter.notifyDataSetChanged();
+ int[] resultArray = new int[selectionItems.size()];
+ CharSequence[] selectTextArray = new CharSequence[selectionItems.size()];
+ for (int i = 0; i < selectionItems.size(); i++) {
+ resultArray[i] = selectionItems.get(i);
+ selectTextArray[i] = menuList.get(resultArray[i]);
+ }
+ onMenuItemSelectListener.onMultiItemSelect(me, selectTextArray, resultArray);
+ }
+ } else {
+ if (onMenuItemClickListener != null) {
+ if (!onMenuItemClickListener.onClick(me, menuList.get(position), position)) {
+ dismiss();
+ }
+ } else {
+ dismiss();
+ }
+ }
+ break;
+ }
+ }
+ }
+ });
+ if (style.overrideBottomDialogRes() != null) {
+ if (style.overrideBottomDialogRes().overrideMenuItemLayout(true, 0, 0, false) != 0) {
+ listView.setSelector(R.color.empty);
+ }
+ }
+
+ RelativeLayout.LayoutParams listViewLp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ dialog.boxList.addView(listView, listViewLp);
+
+ refreshUI();
+ }
+ }
+
+ @Override
+ public void refreshUI() {
+ if (listView != null) {
+ if (menuListAdapter == null) {
+ menuListAdapter = new NormalMenuArrayAdapter(me, getContext(), menuList);
+ }
+ if (listView.getAdapter() == null) {
+ listView.setAdapter(menuListAdapter);
+ } else {
+ if (listView.getAdapter() != menuListAdapter) {
+ listView.setAdapter(menuListAdapter);
+ } else {
+ menuListAdapter.notifyDataSetChanged();
+ }
+ }
+ }
+ super.refreshUI();
+ }
+
+ public void preRefreshUI(){
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ refreshUI();
+ }
+ });
+ }
+
+ @Override
+ public String dialogKey() {
+ return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")";
+ }
+
+ public List getMenuList() {
+ return menuList;
+ }
+
+ public BottomMenu setMenuList(List menuList) {
+ this.menuList = menuList;
+ this.menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ private boolean isSameSize(int menuListSize) {
+ if (this.menuList == null || this.menuList.size() == 0) {
+ return true;
+ }
+ return this.menuList.size() == menuListSize;
+ }
+
+ public BottomMenu setMenuStringList(List menuList) {
+ this.menuList = new ArrayList<>();
+ this.menuList.addAll(menuList);
+ this.menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setMenuList(String[] menuList) {
+ this.menuList = new ArrayList<>();
+ this.menuList.addAll(Arrays.asList(menuList));
+ this.menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setMenuList(CharSequence[] menuList) {
+ this.menuList = Arrays.asList(menuList);
+ this.menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ public OnIconChangeCallBack getOnIconChangeCallBack() {
+ return onIconChangeCallBack;
+ }
+
+ public BottomMenu setOnIconChangeCallBack(OnIconChangeCallBack onIconChangeCallBack) {
+ this.onIconChangeCallBack = onIconChangeCallBack;
+ return this;
+ }
+
+ public OnBackPressedListener getOnBackPressedListener() {
+ return onBackPressedListener;
+ }
+
+ public BottomMenu setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
+ this.onBackPressedListener = onBackPressedListener;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setDialogLifecycleCallback(DialogLifecycleCallback dialogLifecycleCallback) {
+ this.dialogLifecycleCallback = dialogLifecycleCallback;
+ if (isShow) dialogLifecycleCallback.onShow(me);
+ return this;
+ }
+
+ public BottomMenu setStyle(DialogXStyle style) {
+ this.style = style;
+ return this;
+ }
+
+ public BottomMenu setTheme(DialogX.THEME theme) {
+ this.theme = theme;
+ return this;
+ }
+
+ public boolean isCancelable() {
+ if (privateCancelable != null) {
+ return privateCancelable == BOOLEAN.TRUE;
+ }
+ if (overrideCancelable != null) {
+ return overrideCancelable == BOOLEAN.TRUE;
+ }
+ return cancelable;
+ }
+
+ public BottomMenu setCancelable(boolean cancelable) {
+ this.privateCancelable = cancelable ? BOOLEAN.TRUE : BOOLEAN.FALSE;
+ preRefreshUI();
+ return this;
+ }
+
+ public DialogImpl getDialogImpl() {
+ return dialogImpl;
+ }
+
+ public CharSequence getTitle() {
+ return title;
+ }
+
+ public BottomMenu setTitle(CharSequence title) {
+ this.title = title;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setTitle(int titleResId) {
+ this.title = getString(titleResId);
+ preRefreshUI();
+ return this;
+ }
+
+ public CharSequence getMessage() {
+ return message;
+ }
+
+ public BottomMenu setMessage(CharSequence message) {
+ this.message = message;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setMessage(int messageResId) {
+ this.message = getString(messageResId);
+ preRefreshUI();
+ return this;
+ }
+
+ public CharSequence getCancelButton() {
+ return cancelText;
+ }
+
+ public BottomMenu setCancelButton(CharSequence cancelText) {
+ this.cancelText = cancelText;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setCancelButton(int cancelTextResId) {
+ this.cancelText = getString(cancelTextResId);
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setCancelButton(OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ return this;
+ }
+
+ public BottomMenu setCancelButton(CharSequence cancelText, OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelText = cancelText;
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setCancelButton(int cancelTextResId, OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelText = getString(cancelTextResId);
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setCustomView(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ preRefreshUI();
+ return this;
+ }
+
+ public View getCustomView() {
+ if (onBindView == null) return null;
+ return onBindView.getCustomView();
+ }
+
+ public BottomMenu removeCustomView() {
+ this.onBindView.clean();
+ preRefreshUI();
+ return this;
+ }
+
+ public boolean isAllowInterceptTouch() {
+ return super.isAllowInterceptTouch();
+ }
+
+ public BottomMenu setAllowInterceptTouch(boolean allowInterceptTouch) {
+ this.allowInterceptTouch = allowInterceptTouch;
+ preRefreshUI();
+ return this;
+ }
+
+ public float getBottomDialogMaxHeight() {
+ return bottomDialogMaxHeight;
+ }
+
+ public BottomMenu setBottomDialogMaxHeight(float bottomDialogMaxHeight) {
+ this.bottomDialogMaxHeight = bottomDialogMaxHeight;
+ return this;
+ }
+
+ public OnMenuItemClickListener getOnMenuItemClickListener() {
+ return onMenuItemClickListener;
+ }
+
+ public BottomMenu setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
+ this.onMenuItemClickListener = onMenuItemClickListener;
+ return this;
+ }
+
+ public BaseAdapter getMenuListAdapter() {
+ return menuListAdapter;
+ }
+
+ public BottomMenu setMenuListAdapter(BaseAdapter menuListAdapter) {
+ this.menuListAdapter = menuListAdapter;
+ return this;
+ }
+
+ public OnDialogButtonClickListener getCancelButtonClickListener() {
+ return cancelButtonClickListener;
+ }
+
+ public BottomMenu setCancelButtonClickListener(OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ return this;
+ }
+
+ public TextInfo getTitleTextInfo() {
+ return titleTextInfo;
+ }
+
+ public BottomMenu setTitleTextInfo(TextInfo titleTextInfo) {
+ this.titleTextInfo = titleTextInfo;
+ preRefreshUI();
+ return this;
+ }
+
+ public TextInfo getMessageTextInfo() {
+ return messageTextInfo;
+ }
+
+ public BottomMenu setMessageTextInfo(TextInfo messageTextInfo) {
+ this.messageTextInfo = messageTextInfo;
+ preRefreshUI();
+ return this;
+ }
+
+ public TextInfo getCancelTextInfo() {
+ return cancelTextInfo;
+ }
+
+ public BottomMenu setCancelTextInfo(TextInfo cancelTextInfo) {
+ this.cancelTextInfo = cancelTextInfo;
+ preRefreshUI();
+ return this;
+ }
+
+ public int getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public BottomMenu setBackgroundColor(@ColorInt int backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ preRefreshUI();
+ return this;
+ }
+
+ public int getSelection() {
+ return selectionIndex;
+ }
+
+ public ArrayList getSelectionList() {
+ return selectionItems;
+ }
+
+ public BottomMenu setSelection(int selectionIndex) {
+ this.selectMode = SELECT_MODE.SINGLE;
+ this.selectionIndex = selectionIndex;
+ this.selectionItems = null;
+ menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setSingleSelection() {
+ this.selectMode = SELECT_MODE.SINGLE;
+ this.selectionIndex = -1;
+ this.selectionItems = null;
+ menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setSelection(int[] selectionItems) {
+ this.selectMode = SELECT_MODE.MULTIPLE;
+ this.selectionIndex = -1;
+ this.selectionItems = new ArrayList<>();
+ if (selectionItems != null) {
+ for (int itemIndex : selectionItems) {
+ this.selectionItems.add(itemIndex);
+ }
+ }
+ menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setMultiSelection() {
+ this.selectMode = SELECT_MODE.MULTIPLE;
+ this.selectionIndex = -1;
+ this.selectionItems = new ArrayList<>();
+ menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setSelection(List selectionItems) {
+ this.selectMode = SELECT_MODE.MULTIPLE;
+ this.selectionIndex = -1;
+ this.selectionItems = new ArrayList<>(selectionItems);
+ menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setNoSelect() {
+ this.selectMode = SELECT_MODE.NONE;
+ this.selectionIndex = -1;
+ this.selectionItems = null;
+ menuListAdapter = null;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setBackgroundColorRes(@ColorRes int backgroundRes) {
+ this.backgroundColor = getColor(backgroundRes);
+ preRefreshUI();
+ return this;
+ }
+
+ public CharSequence getOkButton() {
+ return okText;
+ }
+
+ public BottomMenu setOkButton(CharSequence okText) {
+ this.okText = okText;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setOkButton(int OkTextResId) {
+ this.okText = getString(OkTextResId);
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setOkButton(OnDialogButtonClickListener OkButtonClickListener) {
+ this.okButtonClickListener = OkButtonClickListener;
+ return this;
+ }
+
+ public BottomMenu setOkButton(CharSequence OkText, OnDialogButtonClickListener OkButtonClickListener) {
+ this.okText = OkText;
+ this.okButtonClickListener = OkButtonClickListener;
+ return this;
+ }
+
+ public BottomMenu setOkButton(int OkTextResId, OnDialogButtonClickListener OkButtonClickListener) {
+ this.okText = getString(OkTextResId);
+ this.okButtonClickListener = OkButtonClickListener;
+ return this;
+ }
+
+ public CharSequence getOtherButton() {
+ return otherText;
+ }
+
+ public BottomMenu setOtherButton(CharSequence otherText) {
+ this.otherText = otherText;
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setOtherButton(int OtherTextResId) {
+ this.otherText = getString(OtherTextResId);
+ preRefreshUI();
+ return this;
+ }
+
+ public BottomMenu setOtherButton(OnDialogButtonClickListener OtherButtonClickListener) {
+ this.otherButtonClickListener = OtherButtonClickListener;
+ return this;
+ }
+
+ public BottomMenu setOtherButton(CharSequence OtherText, OnDialogButtonClickListener OtherButtonClickListener) {
+ this.otherText = OtherText;
+ this.otherButtonClickListener = OtherButtonClickListener;
+ return this;
+ }
+
+ public BottomMenu setOtherButton(int OtherTextResId, OnDialogButtonClickListener OtherButtonClickListener) {
+ this.otherText = getString(OtherTextResId);
+ this.otherButtonClickListener = OtherButtonClickListener;
+ return this;
+ }
+
+ public BottomMenu setMaskColor(@ColorInt int maskColor) {
+ this.maskColor = maskColor;
+ preRefreshUI();
+ return this;
+ }
+
+ public long getEnterAnimDuration() {
+ return enterAnimDuration;
+ }
+
+ public BottomMenu setEnterAnimDuration(long enterAnimDuration) {
+ this.enterAnimDuration = enterAnimDuration;
+ return this;
+ }
+
+ public long getExitAnimDuration() {
+ return exitAnimDuration;
+ }
+
+ public BottomMenu setExitAnimDuration(long exitAnimDuration) {
+ this.exitAnimDuration = exitAnimDuration;
+ return this;
+ }
+
+ public SELECT_MODE getSelectMode() {
+ return selectMode;
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/dialogs/CustomDialog.java b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/CustomDialog.java
new file mode 100644
index 0000000..8e25f7c
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/CustomDialog.java
@@ -0,0 +1,477 @@
+package com.kongzue.dialogx.dialogs;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.ColorInt;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.R;
+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.util.views.DialogXBaseRelativeLayout;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/20 11:59
+ */
+public class CustomDialog extends BaseDialog {
+
+ public static int overrideEnterDuration = -1;
+ public static int overrideExitDuration = -1;
+ public static int overrideEnterAnimRes = 0;
+ public static int overrideExitAnimRes = 0;
+ public static int overrideMaskEnterAnimRes = R.anim.anim_dialogx_default_alpha_enter;
+ public static int overrideMaskExitAnimRes = R.anim.anim_dialogx_default_exit;
+ public static BOOLEAN overrideCancelable;
+ protected OnBindView onBindView;
+ protected DialogLifecycleCallback dialogLifecycleCallback;
+ protected CustomDialog me = this;
+ protected DialogImpl dialogImpl;
+ protected int enterAnimResId = R.anim.anim_dialogx_default_enter;
+ protected int exitAnimResId = R.anim.anim_dialogx_default_exit;
+ protected ALIGN align = ALIGN.CENTER;
+ protected boolean autoUnsafePlacePadding = true;
+ private View dialogView;
+ protected int maskColor = Color.TRANSPARENT;
+ protected BOOLEAN privateCancelable;
+
+ public enum ALIGN {
+ CENTER,
+ TOP,
+ BOTTOM,
+ LEFT,
+ RIGHT
+ }
+
+ protected CustomDialog() {
+ super();
+ }
+
+ public static CustomDialog build() {
+ return new CustomDialog();
+ }
+
+ public CustomDialog(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ }
+
+ public static CustomDialog show(OnBindView onBindView) {
+ CustomDialog customDialog = new CustomDialog(onBindView);
+ customDialog.show();
+ return customDialog;
+ }
+
+ public static CustomDialog show(OnBindView onBindView, ALIGN align) {
+ CustomDialog customDialog = new CustomDialog(onBindView);
+ customDialog.align = align;
+ customDialog.show();
+ return customDialog;
+ }
+
+ public void show() {
+ super.beforeShow();
+ dialogView = createView(R.layout.layout_dialogx_custom);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+
+ public void show(Activity activity) {
+ super.beforeShow();
+ dialogView = createView(R.layout.layout_dialogx_custom);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(activity, dialogView);
+ }
+
+ public class DialogImpl implements DialogConvertViewInterface {
+
+ public DialogXBaseRelativeLayout boxRoot;
+ public RelativeLayout boxCustom;
+
+ public DialogImpl(View convertView) {
+ boxRoot = convertView.findViewById(R.id.box_root);
+ boxCustom = convertView.findViewById(R.id.box_custom);
+
+ init();
+ dialogImpl = this;
+ refreshView();
+ }
+
+ @Override
+ public void init() {
+ boxRoot.setParentDialog(me);
+ boxRoot.setOnLifecycleCallBack(new DialogXBaseRelativeLayout.OnLifecycleCallBack() {
+ @Override
+ public void onShow() {
+ isShow = true;
+ getDialogLifecycleCallback().onShow(me);
+ boxCustom.setVisibility(View.GONE);
+ }
+
+ @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 (isCancelable()) {
+ dismiss();
+ }
+ return false;
+ }
+ });
+
+ boxRoot.post(new Runnable() {
+ @Override
+ public void run() {
+ Animation enterAnim;
+ if (enterAnimResId == R.anim.anim_dialogx_default_enter && exitAnimResId == R.anim.anim_dialogx_default_exit) {
+ switch (align) {
+ case TOP:
+ enterAnimResId = R.anim.anim_dialogx_top_enter;
+ exitAnimResId = R.anim.anim_dialogx_top_exit;
+ break;
+ case BOTTOM:
+ enterAnimResId = R.anim.anim_dialogx_bottom_enter;
+ exitAnimResId = R.anim.anim_dialogx_bottom_exit;
+ break;
+ case LEFT:
+ enterAnimResId = R.anim.anim_dialogx_left_enter;
+ exitAnimResId = R.anim.anim_dialogx_left_exit;
+ break;
+ case RIGHT:
+ enterAnimResId = R.anim.anim_dialogx_right_enter;
+ exitAnimResId = R.anim.anim_dialogx_right_exit;
+ break;
+ }
+ enterAnim = AnimationUtils.loadAnimation(getContext(), enterAnimResId);
+ enterAnim.setInterpolator(new DecelerateInterpolator(2f));
+ } else {
+ int enterAnimResIdTemp = R.anim.anim_dialogx_default_enter;
+ if (overrideEnterAnimRes != 0) {
+ enterAnimResIdTemp = overrideEnterAnimRes;
+ }
+ if (enterAnimResId != 0) {
+ enterAnimResIdTemp = enterAnimResId;
+ }
+ enterAnim = AnimationUtils.loadAnimation(getContext(), enterAnimResIdTemp);
+ }
+ long enterAnimDurationTemp = enterAnim.getDuration();
+ if (overrideEnterDuration >= 0) {
+ enterAnimDurationTemp = overrideEnterDuration;
+ }
+ if (enterAnimDuration >= 0) {
+ enterAnimDurationTemp = enterAnimDuration;
+ }
+ enterAnim.setDuration(enterAnimDurationTemp);
+ boxCustom.setVisibility(View.VISIBLE);
+ boxCustom.startAnimation(enterAnim);
+
+ boxRoot.setBackgroundColor(maskColor);
+ if (overrideMaskEnterAnimRes != 0) {
+ Animation maskEnterAnim = AnimationUtils.loadAnimation(getContext(), overrideMaskEnterAnimRes);
+ maskEnterAnim.setInterpolator(new DecelerateInterpolator(2f));
+ maskEnterAnim.setDuration(enterAnimDurationTemp);
+ boxRoot.startAnimation(maskEnterAnim);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void refreshView() {
+ RelativeLayout.LayoutParams rlp;
+ rlp = ((RelativeLayout.LayoutParams) boxCustom.getLayoutParams());
+ switch (align) {
+ case TOP:
+ rlp.removeRule(RelativeLayout.CENTER_IN_PARENT);
+ rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ break;
+ case BOTTOM:
+ rlp.removeRule(RelativeLayout.CENTER_IN_PARENT);
+ rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ break;
+ case CENTER:
+ rlp.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
+ rlp.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ rlp.addRule(RelativeLayout.CENTER_IN_PARENT);
+ break;
+ case LEFT:
+ rlp.removeRule(RelativeLayout.CENTER_IN_PARENT);
+ rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ rlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
+ break;
+ case RIGHT:
+ rlp.removeRule(RelativeLayout.CENTER_IN_PARENT);
+ rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ rlp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+ break;
+ }
+ boxCustom.setLayoutParams(rlp);
+
+ boxRoot.setAutoUnsafePlacePadding(autoUnsafePlacePadding);
+ if (isCancelable()) {
+ boxRoot.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ doDismiss(v);
+ }
+ });
+ } else {
+ boxRoot.setOnClickListener(null);
+ }
+
+ if (onBindView != null && onBindView.getCustomView() != null) {
+ onBindView.bindParent(boxCustom, me);
+ }
+ }
+
+ @Override
+ public void doDismiss(View v) {
+ if (v != null) v.setEnabled(false);
+
+ int exitAnimResIdTemp = R.anim.anim_dialogx_default_exit;
+ if (overrideExitAnimRes != 0) {
+ exitAnimResIdTemp = overrideExitAnimRes;
+ }
+ if (exitAnimResId != 0) {
+ exitAnimResIdTemp = exitAnimResId;
+ }
+ Animation exitAnim = AnimationUtils.loadAnimation(getContext(), exitAnimResIdTemp);
+
+ long exitAnimDurationTemp = exitAnim.getDuration();
+ if (overrideExitDuration >= 0) {
+ exitAnimDurationTemp = overrideExitDuration;
+ }
+ if (exitAnimDuration >= 0) {
+ exitAnimDurationTemp = exitAnimDuration;
+ }
+ exitAnim.setDuration(exitAnimDurationTemp);
+ exitAnim.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ dismiss(dialogView);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+
+ }
+ });
+ boxCustom.startAnimation(exitAnim);
+
+ if (overrideMaskExitAnimRes != 0) {
+ Animation maskExitAnim = AnimationUtils.loadAnimation(getContext(), overrideMaskExitAnimRes);
+ maskExitAnim.setDuration(exitAnimDurationTemp);
+ maskExitAnim.setInterpolator(new DecelerateInterpolator(2f));
+ boxRoot.startAnimation(maskExitAnim);
+ }
+ }
+ }
+
+ @Override
+ public String dialogKey() {
+ return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")";
+ }
+
+ public void refreshUI() {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ if (dialogImpl != null) dialogImpl.refreshView();
+ }
+ });
+ }
+
+ public void dismiss() {
+ if (dialogImpl == null) return;
+ dialogImpl.doDismiss(null);
+ }
+
+ public DialogLifecycleCallback getDialogLifecycleCallback() {
+ return dialogLifecycleCallback == null ? new DialogLifecycleCallback() {
+ } : dialogLifecycleCallback;
+ }
+
+ public CustomDialog setDialogLifecycleCallback(DialogLifecycleCallback dialogLifecycleCallback) {
+ this.dialogLifecycleCallback = dialogLifecycleCallback;
+ if (isShow) dialogLifecycleCallback.onShow(me);
+ return this;
+ }
+
+ public OnBackPressedListener getOnBackPressedListener() {
+ return onBackPressedListener;
+ }
+
+ public CustomDialog setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
+ this.onBackPressedListener = onBackPressedListener;
+ refreshUI();
+ return this;
+ }
+
+ public CustomDialog setStyle(DialogXStyle style) {
+ this.style = style;
+ return this;
+ }
+
+ public CustomDialog setTheme(DialogX.THEME theme) {
+ this.theme = theme;
+ return this;
+ }
+
+ public boolean isCancelable() {
+ if (privateCancelable != null) {
+ return privateCancelable == BOOLEAN.TRUE;
+ }
+ if (overrideCancelable != null) {
+ return overrideCancelable == BOOLEAN.TRUE;
+ }
+ return cancelable;
+ }
+
+ public CustomDialog setCancelable(boolean cancelable) {
+ this.privateCancelable = cancelable ? BOOLEAN.TRUE : BOOLEAN.FALSE;
+ refreshUI();
+ return this;
+ }
+
+ public CustomDialog.DialogImpl getDialogImpl() {
+ return dialogImpl;
+ }
+
+ public CustomDialog setCustomView(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ refreshUI();
+ return this;
+ }
+
+ public View getCustomView() {
+ if (onBindView == null) return null;
+ return onBindView.getCustomView();
+ }
+
+ public CustomDialog removeCustomView() {
+ this.onBindView.clean();
+ refreshUI();
+ return this;
+ }
+
+ public int getEnterAnimResId() {
+ return enterAnimResId;
+ }
+
+ public CustomDialog setEnterAnimResId(int enterAnimResId) {
+ this.enterAnimResId = enterAnimResId;
+ return this;
+ }
+
+ public int getExitAnimResId() {
+ return exitAnimResId;
+ }
+
+ public CustomDialog setExitAnimResId(int exitAnimResId) {
+ this.exitAnimResId = exitAnimResId;
+ return this;
+ }
+
+ public CustomDialog setAnimResId(int enterAnimResId, int exitAnimResId) {
+ this.enterAnimResId = enterAnimResId;
+ this.exitAnimResId = exitAnimResId;
+ return this;
+ }
+
+ public ALIGN getAlign() {
+ return align;
+ }
+
+ public CustomDialog setAlign(ALIGN align) {
+ this.align = align;
+ return this;
+ }
+
+ public boolean isAutoUnsafePlacePadding() {
+ return autoUnsafePlacePadding;
+ }
+
+ public CustomDialog setAutoUnsafePlacePadding(boolean autoUnsafePlacePadding) {
+ this.autoUnsafePlacePadding = autoUnsafePlacePadding;
+ refreshUI();
+ return this;
+ }
+
+ public CustomDialog setFullScreen(boolean fullscreen) {
+ this.autoUnsafePlacePadding = !autoUnsafePlacePadding;
+ refreshUI();
+ return this;
+ }
+
+ public CustomDialog setMaskColor(@ColorInt int maskColor) {
+ this.maskColor = maskColor;
+ refreshUI();
+ return this;
+ }
+
+ public long getEnterAnimDuration() {
+ return enterAnimDuration;
+ }
+
+ public CustomDialog setEnterAnimDuration(long enterAnimDuration) {
+ this.enterAnimDuration = enterAnimDuration;
+ return this;
+ }
+
+ public long getExitAnimDuration() {
+ return exitAnimDuration;
+ }
+
+ public CustomDialog setExitAnimDuration(long exitAnimDuration) {
+ this.exitAnimDuration = exitAnimDuration;
+ return this;
+ }
+
+ @Override
+ public void onUIModeChange(Configuration newConfig) {
+ if (dialogView != null) {
+ dismiss(dialogView);
+ }
+ if (getDialogImpl().boxCustom != null) {
+ getDialogImpl().boxCustom.removeAllViews();
+ }
+
+ enterAnimDuration = 0;
+ dialogView = createView(R.layout.layout_dialogx_custom);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/dialogs/FullScreenDialog.java b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/FullScreenDialog.java
new file mode 100644
index 0000000..2d83beb
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/FullScreenDialog.java
@@ -0,0 +1,407 @@
+package com.kongzue.dialogx.dialogs;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+
+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.OnSafeInsetsChangeListener;
+import com.kongzue.dialogx.util.FullScreenDialogTouchEventInterceptor;
+import com.kongzue.dialogx.util.views.ActivityScreenShotImageView;
+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 {
+
+ public static int overrideEnterDuration = -1;
+ public static int overrideExitDuration = -1;
+ public static BOOLEAN overrideCancelable;
+
+ protected OnBindView onBindView;
+ protected BOOLEAN privateCancelable;
+
+ protected DialogLifecycleCallback dialogLifecycleCallback;
+
+ protected FullScreenDialog me = this;
+
+ protected FullScreenDialog() {
+ super();
+ }
+
+ private View dialogView;
+
+ public static FullScreenDialog build() {
+ return new FullScreenDialog();
+ }
+
+ public FullScreenDialog(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ }
+
+ public static FullScreenDialog show(OnBindView onBindView) {
+ FullScreenDialog fullScreenDialog = new FullScreenDialog(onBindView);
+ fullScreenDialog.show();
+ return fullScreenDialog;
+ }
+
+ public void show() {
+ super.beforeShow();
+ dialogView = createView(isLightTheme() ? R.layout.layout_dialogx_fullscreen : R.layout.layout_dialogx_fullscreen_dark);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+
+ public void show(Activity activity) {
+ super.beforeShow();
+ dialogView = createView(isLightTheme() ? R.layout.layout_dialogx_fullscreen : R.layout.layout_dialogx_fullscreen_dark);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(activity, 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();
+ dialogImpl = this;
+ refreshView();
+ }
+
+ public float bkgEnterAimY = -1;
+ private long enterAnimDurationTemp = 300;
+
+ @Override
+ public void init() {
+ boxRoot.setParentDialog(me);
+ boxRoot.setOnLifecycleCallBack(new DialogXBaseRelativeLayout.OnLifecycleCallBack() {
+ @Override
+ public void onShow() {
+ isShow = true;
+ boxRoot.setAlpha(0f);
+
+ getDialogLifecycleCallback().onShow(me);
+ }
+
+ @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 (isCancelable()) {
+ dismiss();
+ }
+ return false;
+ }
+ });
+
+ fullScreenDialogTouchEventInterceptor = new FullScreenDialogTouchEventInterceptor(me, dialogImpl);
+
+ enterAnimDurationTemp = 300;
+ if (overrideEnterDuration >= 0) {
+ enterAnimDurationTemp = overrideEnterDuration;
+ }
+ if (enterAnimDuration >= 0) {
+ enterAnimDurationTemp = enterAnimDuration;
+ }
+
+ boxRoot.post(new Runnable() {
+ @Override
+ public void run() {
+ bkgEnterAimY = boxRoot.getSafeHeight() - boxCustom.getHeight();
+ if (bkgEnterAimY < 0) bkgEnterAimY = 0;
+ boxRoot.animate()
+ .setDuration(enterAnimDurationTemp)
+ .alpha(1f)
+ .setInterpolator(new DecelerateInterpolator())
+ .setListener(null);
+
+ ObjectAnimator exitAnim = ObjectAnimator.ofFloat(bkg, "y", boxRoot.getHeight(), bkgEnterAimY);
+ exitAnim.setDuration(enterAnimDurationTemp);
+ 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(enterAnimDurationTemp);
+ enterAnim.start();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void refreshView() {
+ if (backgroundColor != -1) {
+ tintColor(bkg, backgroundColor);
+ }
+
+ if (isCancelable()) {
+ boxRoot.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ doDismiss(v);
+ }
+ });
+ } else {
+ boxRoot.setOnClickListener(null);
+ }
+
+ if (onBindView != null && onBindView.getCustomView() != null) {
+ onBindView.bindParent(boxCustom, me);
+ }
+
+ fullScreenDialogTouchEventInterceptor.refresh(me, this);
+ }
+
+ @Override
+ public void doDismiss(View v) {
+ if (v != null) v.setEnabled(false);
+
+ long exitAnimDurationTemp = 300;
+ if (overrideExitDuration >= 0) {
+ exitAnimDurationTemp = overrideExitDuration;
+ }
+ if (exitAnimDuration >= 0) {
+ exitAnimDurationTemp = exitAnimDuration;
+ }
+
+ ObjectAnimator exitAnim = ObjectAnimator.ofFloat(bkg, "y", bkg.getY(), boxBkg.getHeight());
+ exitAnim.setDuration(exitAnimDurationTemp);
+ exitAnim.start();
+
+ boxRoot.animate()
+ .alpha(0f)
+ .setInterpolator(new AccelerateInterpolator())
+ .setDuration(exitAnimDurationTemp);
+
+ new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ dismiss(dialogView);
+ }
+ },exitAnimDurationTemp);
+ }
+
+ public void preDismiss() {
+ if (isCancelable()) {
+ doDismiss(boxRoot);
+ } else {
+ long exitAnimDurationTemp = 300;
+ if (overrideExitDuration >= 0) {
+ exitAnimDurationTemp = overrideExitDuration;
+ }
+ if (exitAnimDuration >= 0) {
+ exitAnimDurationTemp = exitAnimDuration;
+ }
+
+ ObjectAnimator enterAnim = ObjectAnimator.ofFloat(bkg, "y", bkg.getY(), bkgEnterAimY);
+ enterAnim.setDuration(exitAnimDurationTemp);
+ enterAnim.start();
+ }
+ }
+ }
+
+ @Override
+ public String dialogKey() {
+ return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")";
+ }
+
+ public void refreshUI() {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ if (dialogImpl != null) dialogImpl.refreshView();
+ }
+ });
+ }
+
+ public void dismiss() {
+ if (dialogImpl == null) return;
+ dialogImpl.doDismiss(null);
+ }
+
+ public DialogLifecycleCallback getDialogLifecycleCallback() {
+ return dialogLifecycleCallback == null ? new DialogLifecycleCallback() {
+ } : dialogLifecycleCallback;
+ }
+
+ public FullScreenDialog setDialogLifecycleCallback(DialogLifecycleCallback dialogLifecycleCallback) {
+ this.dialogLifecycleCallback = dialogLifecycleCallback;
+ if (isShow) dialogLifecycleCallback.onShow(me);
+ 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() {
+ if (privateCancelable != null) {
+ return privateCancelable == BOOLEAN.TRUE;
+ }
+ if (overrideCancelable != null) {
+ return overrideCancelable == BOOLEAN.TRUE;
+ }
+ return cancelable;
+ }
+
+ public FullScreenDialog setCancelable(boolean cancelable) {
+ this.privateCancelable = cancelable ? BOOLEAN.TRUE : BOOLEAN.FALSE;
+ refreshUI();
+ return this;
+ }
+
+ public DialogImpl getDialogImpl() {
+ return dialogImpl;
+ }
+
+ public FullScreenDialog setCustomView(OnBindView 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;
+ }
+
+ public FullScreenDialog setBackgroundColorRes(@ColorRes int backgroundColorRes) {
+ this.backgroundColor = getColor(backgroundColorRes);
+ refreshUI();
+ return this;
+ }
+
+ public long getEnterAnimDuration() {
+ return enterAnimDuration;
+ }
+
+ public FullScreenDialog setEnterAnimDuration(long enterAnimDuration) {
+ this.enterAnimDuration = enterAnimDuration;
+ return this;
+ }
+
+ public long getExitAnimDuration() {
+ return exitAnimDuration;
+ }
+
+ public FullScreenDialog setExitAnimDuration(long exitAnimDuration) {
+ this.exitAnimDuration = exitAnimDuration;
+ return this;
+ }
+
+ @Override
+ public void onUIModeChange(Configuration newConfig) {
+ if (dialogView != null) {
+ dismiss(dialogView);
+ }
+ if (getDialogImpl().boxCustom != null) {
+ getDialogImpl().boxCustom.removeAllViews();
+ }
+ enterAnimDuration = 0;
+ dialogView = createView(isLightTheme() ? R.layout.layout_dialogx_fullscreen : R.layout.layout_dialogx_fullscreen_dark);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/dialogs/InputDialog.java b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/InputDialog.java
new file mode 100644
index 0000000..5d2a5c4
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/InputDialog.java
@@ -0,0 +1,550 @@
+package com.kongzue.dialogx.dialogs;
+
+import android.content.res.Configuration;
+import android.view.View;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.R;
+import com.kongzue.dialogx.interfaces.OnBackPressedListener;
+import com.kongzue.dialogx.interfaces.OnBindView;
+import com.kongzue.dialogx.interfaces.OnInputDialogButtonClickListener;
+import com.kongzue.dialogx.interfaces.OnInputDialogButtonClickListener;
+import com.kongzue.dialogx.util.InputInfo;
+import com.kongzue.dialogx.util.TextInfo;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/24 13:53
+ */
+public class InputDialog extends MessageDialog {
+
+ protected InputDialog() {
+ super();
+ }
+
+ public static InputDialog build() {
+ return new InputDialog();
+ }
+
+ public InputDialog(CharSequence title, CharSequence message, CharSequence okText) {
+ cancelable = DialogX.cancelable;
+ this.title = title;
+ this.message = message;
+ this.okText = okText;
+ }
+
+ public InputDialog(int titleResId, int messageResId, int okTextResId) {
+ cancelable = DialogX.cancelable;
+ this.title = getString(titleResId);
+ this.message = getString(messageResId);
+ this.okText = getString(okTextResId);
+ }
+
+ public static InputDialog show(CharSequence title, CharSequence message, CharSequence okText) {
+ InputDialog inputDialog = new InputDialog(title, message, okText);
+ inputDialog.show();
+ return inputDialog;
+ }
+
+ public static InputDialog show(int titleResId, int messageResId, int okTextResId) {
+ InputDialog inputDialog = new InputDialog(titleResId, messageResId, okTextResId);
+ inputDialog.show();
+ return inputDialog;
+ }
+
+ public InputDialog(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText) {
+ cancelable = DialogX.cancelable;
+ this.title = title;
+ this.message = message;
+ this.okText = okText;
+ this.cancelText = cancelText;
+ }
+
+ public InputDialog(int titleResId, int messageResId, int okTextResId, int cancelTextResId) {
+ cancelable = DialogX.cancelable;
+ this.title = getString(titleResId);
+ this.message = getString(messageResId);
+ this.okText = getString(okTextResId);
+ this.cancelText = getString(cancelTextResId);
+ }
+
+ public static InputDialog show(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText) {
+ InputDialog inputDialog = new InputDialog(title, message, okText, cancelText);
+ inputDialog.show();
+ return inputDialog;
+ }
+
+ public static InputDialog show(int titleResId, int messageResId, int okTextResId, int cancelTextResId) {
+ InputDialog inputDialog = new InputDialog(titleResId, messageResId, okTextResId, cancelTextResId);
+ inputDialog.show();
+ return inputDialog;
+ }
+
+ public InputDialog(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText, String inputText) {
+ cancelable = DialogX.cancelable;
+ this.title = title;
+ this.message = message;
+ this.okText = okText;
+ this.cancelText = cancelText;
+ this.inputText = inputText;
+ }
+
+ public static InputDialog show(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText, String inputText) {
+ InputDialog inputDialog = new InputDialog(title, message, okText, cancelText, inputText);
+ inputDialog.show();
+ return inputDialog;
+ }
+
+ public InputDialog(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText, CharSequence otherText) {
+ cancelable = DialogX.cancelable;
+ this.title = title;
+ this.message = message;
+ this.okText = okText;
+ this.cancelText = cancelText;
+ this.otherText = otherText;
+ }
+
+ public InputDialog(int titleResId, int messageResId, int okTextResId, int cancelTextResId, int otherTextResId) {
+ cancelable = DialogX.cancelable;
+ this.title = getString(titleResId);
+ this.message = getString(messageResId);
+ this.okText = getString(okTextResId);
+ this.cancelText = getString(cancelTextResId);
+ this.otherText = getString(otherTextResId);
+ }
+
+ public static InputDialog show(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText, CharSequence otherText) {
+ InputDialog inputDialog = new InputDialog(title, message, okText, cancelText, otherText);
+ inputDialog.show();
+ return inputDialog;
+ }
+
+ public static InputDialog show(int titleResId, int messageResId, int okTextResId, int cancelTextResId, int otherTextResId) {
+ InputDialog inputDialog = new InputDialog(titleResId, messageResId, okTextResId, cancelTextResId, otherTextResId);
+ inputDialog.show();
+ return inputDialog;
+ }
+
+ public InputDialog(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText, CharSequence otherText, String inputText) {
+ cancelable = DialogX.cancelable;
+ this.title = title;
+ this.message = message;
+ this.okText = okText;
+ this.cancelText = cancelText;
+ this.otherText = otherText;
+ this.inputText = inputText;
+ }
+
+ public InputDialog(int titleResId, int messageResId, int okTextResId, int cancelTextResId, int otherTextResId, int inputTextResId) {
+ cancelable = DialogX.cancelable;
+ this.title = getString(titleResId);
+ this.message = getString(messageResId);
+ this.okText = getString(okTextResId);
+ this.cancelText = getString(cancelTextResId);
+ this.otherText = getString(otherTextResId);
+ this.inputText = getString(inputTextResId);
+ }
+
+ public static InputDialog show(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText, CharSequence otherText, String inputText) {
+ InputDialog inputDialog = new InputDialog(title, message, okText, cancelText, otherText, inputText);
+ inputDialog.show();
+ return inputDialog;
+ }
+
+ public static InputDialog show(int titleResId, int messageResId, int okTextResId, int cancelTextResId, int otherTextResId, int inputTextResId) {
+ InputDialog inputDialog = new InputDialog(titleResId, messageResId, okTextResId, cancelTextResId, otherTextResId, inputTextResId);
+ inputDialog.show();
+ return inputDialog;
+ }
+
+ @Override
+ public String dialogKey() {
+ return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")";
+ }
+
+ public CharSequence getOkButton() {
+ return okText;
+ }
+
+ public InputDialog setOkButton(CharSequence okText) {
+ this.okText = okText;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setOkButton(int okTextResId) {
+ this.okText = getString(okTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setOkButton(OnInputDialogButtonClickListener okButtonClickListener) {
+ this.okButtonClickListener = okButtonClickListener;
+ return this;
+ }
+
+ public InputDialog setOkButton(CharSequence okText, OnInputDialogButtonClickListener okButtonClickListener) {
+ this.okText = okText;
+ this.okButtonClickListener = okButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setOkButton(int okTextResId, OnInputDialogButtonClickListener okButtonClickListener) {
+ this.okText = getString(okTextResId);
+ this.okButtonClickListener = okButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getCancelButton() {
+ return cancelText;
+ }
+
+ public InputDialog setCancelButton(CharSequence cancelText) {
+ this.cancelText = cancelText;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setCancelButton(int cancelTextResId) {
+ this.cancelText = getString(cancelTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setCancelButton(OnInputDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ return this;
+ }
+
+ public InputDialog setCancelButton(CharSequence cancelText, OnInputDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelText = cancelText;
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setCancelButton(int cancelTextResId, OnInputDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelText = getString(cancelTextResId);
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getOtherButton() {
+ return otherText;
+ }
+
+ public InputDialog setOtherButton(CharSequence otherText) {
+ this.otherText = otherText;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setOtherButton(int otherTextResId) {
+ this.otherText = getString(otherTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setOtherButton(OnInputDialogButtonClickListener otherButtonClickListener) {
+ this.otherButtonClickListener = otherButtonClickListener;
+ return this;
+ }
+
+ public InputDialog setOtherButton(CharSequence otherText, OnInputDialogButtonClickListener otherButtonClickListener) {
+ this.otherText = otherText;
+ this.otherButtonClickListener = otherButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setOtherButton(int otherTextResId, OnInputDialogButtonClickListener otherButtonClickListener) {
+ this.otherText = getString(otherTextResId);
+ this.otherButtonClickListener = otherButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public OnInputDialogButtonClickListener getInputOkButtonClickListener() {
+ return (OnInputDialogButtonClickListener) okButtonClickListener;
+ }
+
+ public InputDialog setOkButtonClickListener(OnInputDialogButtonClickListener okButtonClickListener) {
+ this.okButtonClickListener = okButtonClickListener;
+ return this;
+ }
+
+ public OnInputDialogButtonClickListener getInputCancelButtonClickListener() {
+ return (OnInputDialogButtonClickListener) cancelButtonClickListener;
+ }
+
+ public InputDialog setCancelButtonClickListener(OnInputDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ return this;
+ }
+
+ public OnInputDialogButtonClickListener getInputOtherButtonClickListener() {
+ return (OnInputDialogButtonClickListener) otherButtonClickListener;
+ }
+
+ public InputDialog setOtherButtonClickListener(OnInputDialogButtonClickListener otherButtonClickListener) {
+ this.otherButtonClickListener = otherButtonClickListener;
+ return this;
+ }
+
+ public CharSequence getTitle() {
+ return title;
+ }
+
+ public InputDialog setTitle(CharSequence title) {
+ this.title = title;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setTitle(int titleResId) {
+ this.title = getString(titleResId);
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getMessage() {
+ return message;
+ }
+
+ public InputDialog setMessage(CharSequence message) {
+ this.message = message;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setMessage(int messageResId) {
+ this.message = getString(messageResId);
+ refreshUI();
+ return this;
+ }
+
+ public String getInputText() {
+ if (getDialogImpl() != null && getDialogImpl().txtInput != null) {
+ return getDialogImpl().txtInput.getText().toString();
+ }
+ return inputText;
+ }
+
+ public InputDialog setInputText(String inputText) {
+ this.inputText = inputText;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setInputText(int inputTextResId) {
+ this.inputText = getString(inputTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public String getInputHintText() {
+ return inputHintText;
+ }
+
+ public InputDialog setInputHintText(String inputHintText) {
+ this.inputHintText = inputHintText;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setInputHintText(int inputHintTextResId) {
+ this.inputHintText = getString(inputHintTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getTitleTextInfo() {
+ return titleTextInfo;
+ }
+
+ public InputDialog setTitleTextInfo(TextInfo titleTextInfo) {
+ this.titleTextInfo = titleTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getMessageTextInfo() {
+ return messageTextInfo;
+ }
+
+ public InputDialog setMessageTextInfo(TextInfo messageTextInfo) {
+ this.messageTextInfo = messageTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getOkTextInfo() {
+ return okTextInfo;
+ }
+
+ public InputDialog setOkTextInfo(TextInfo okTextInfo) {
+ this.okTextInfo = okTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getCancelTextInfo() {
+ return cancelTextInfo;
+ }
+
+ public InputDialog setCancelTextInfo(TextInfo cancelTextInfo) {
+ this.cancelTextInfo = cancelTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getOtherTextInfo() {
+ return otherTextInfo;
+ }
+
+ public InputDialog setOtherTextInfo(TextInfo otherTextInfo) {
+ this.otherTextInfo = otherTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public InputInfo getInputInfo() {
+ return inputInfo;
+ }
+
+ public InputDialog setInputInfo(InputInfo inputInfo) {
+ this.inputInfo = inputInfo;
+ refreshUI();
+ return this;
+ }
+
+ public int getButtonOrientation() {
+ return buttonOrientation;
+ }
+
+ public InputDialog setButtonOrientation(int buttonOrientation) {
+ this.buttonOrientation = buttonOrientation;
+ refreshUI();
+ return this;
+ }
+
+ public boolean isCancelable() {
+ if (privateCancelable != null) {
+ return privateCancelable == BOOLEAN.TRUE;
+ }
+ if (overrideCancelable != null) {
+ return overrideCancelable == BOOLEAN.TRUE;
+ }
+ return cancelable;
+ }
+
+ public InputDialog setCancelable(boolean cancelable) {
+ this.privateCancelable = cancelable ? BOOLEAN.TRUE : BOOLEAN.FALSE;
+ refreshUI();
+ return this;
+ }
+
+ public OnBackPressedListener getOnBackPressedListener() {
+ return onBackPressedListener;
+ }
+
+ public InputDialog setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
+ this.onBackPressedListener = onBackPressedListener;
+ return this;
+ }
+
+ public boolean isAutoShowInputKeyboard() {
+ return autoShowInputKeyboard;
+ }
+
+ public InputDialog setAutoShowInputKeyboard(boolean autoShowInputKeyboard) {
+ this.autoShowInputKeyboard = autoShowInputKeyboard;
+ return this;
+ }
+
+ public InputDialog setCustomView(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ refreshUI();
+ return this;
+ }
+
+ public View getCustomView() {
+ if (onBindView == null) return null;
+ return onBindView.getCustomView();
+ }
+
+ public InputDialog removeCustomView() {
+ this.onBindView.clean();
+ refreshUI();
+ return this;
+ }
+
+ public int getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public InputDialog setBackgroundColor(@ColorInt int backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setBackgroundColorRes(@ColorRes int backgroundColorResId) {
+ this.backgroundColor = getColor(backgroundColorResId);
+ refreshUI();
+ return this;
+ }
+
+ public InputDialog setMaskColor(@ColorInt int maskColor) {
+ this.maskColor = maskColor;
+ refreshUI();
+ return this;
+ }
+
+ public long getEnterAnimDuration() {
+ return enterAnimDuration;
+ }
+
+ public InputDialog setEnterAnimDuration(long enterAnimDuration) {
+ this.enterAnimDuration = enterAnimDuration;
+ return this;
+ }
+
+ public long getExitAnimDuration() {
+ return exitAnimDuration;
+ }
+
+ public InputDialog setExitAnimDuration(long exitAnimDuration) {
+ this.exitAnimDuration = exitAnimDuration;
+ return this;
+ }
+
+ @Override
+ public void onUIModeChange(Configuration newConfig) {
+ if (dialogView != null) {
+ dismiss(dialogView);
+ }
+ if (getDialogImpl().boxCustom!=null){
+ getDialogImpl().boxCustom.removeAllViews();
+ }
+ int layoutId = style.layout(isLightTheme());
+ layoutId = layoutId == 0 ? (isLightTheme() ? R.layout.layout_dialogx_material : R.layout.layout_dialogx_material_dark) : layoutId;
+
+ String inputText = getInputText();
+ enterAnimDuration = 0;
+ dialogView = createView(layoutId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ setInputText(inputText);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/dialogs/MessageDialog.java b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/MessageDialog.java
new file mode 100644
index 0000000..4807f07
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/MessageDialog.java
@@ -0,0 +1,1038 @@
+package com.kongzue.dialogx.dialogs;
+
+import android.animation.Animator;
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.InputFilter;
+import android.text.InputType;
+import android.text.method.LinkMovementMethod;
+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.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.Space;
+import android.widget.TextView;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+
+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.BaseOnDialogClickCallback;
+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.OnInputDialogButtonClickListener;
+import com.kongzue.dialogx.style.MaterialStyle;
+import com.kongzue.dialogx.util.views.BlurView;
+import com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout;
+import com.kongzue.dialogx.util.InputInfo;
+import com.kongzue.dialogx.util.views.MaxRelativeLayout;
+import com.kongzue.dialogx.util.TextInfo;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/21 17:08
+ */
+public class MessageDialog extends BaseDialog {
+
+ public static int overrideEnterDuration = -1;
+ public static int overrideExitDuration = -1;
+ public static int overrideEnterAnimRes = 0;
+ public static int overrideExitAnimRes = 0;
+ public static BOOLEAN overrideCancelable;
+ protected OnBindView onBindView;
+ protected MessageDialog me = this;
+ protected BOOLEAN privateCancelable;
+
+ private DialogLifecycleCallback dialogLifecycleCallback;
+
+ protected MessageDialog() {
+ super();
+ }
+
+ protected View dialogView;
+
+ protected CharSequence title;
+ protected CharSequence message;
+ protected CharSequence okText;
+ protected CharSequence cancelText;
+ protected CharSequence otherText;
+ protected String inputText;
+ protected String inputHintText;
+ protected int maskColor = -1;
+
+ protected TextInfo titleTextInfo;
+ protected TextInfo messageTextInfo;
+ protected TextInfo okTextInfo;
+ protected TextInfo cancelTextInfo;
+ protected TextInfo otherTextInfo;
+ protected InputInfo inputInfo;
+
+ protected BaseOnDialogClickCallback okButtonClickListener;
+ protected BaseOnDialogClickCallback cancelButtonClickListener;
+ protected BaseOnDialogClickCallback otherButtonClickListener;
+
+ protected int buttonOrientation;
+
+ public static MessageDialog build() {
+ return new MessageDialog();
+ }
+
+ public MessageDialog(CharSequence title, CharSequence message) {
+ this.title = title;
+ this.message = message;
+ }
+
+ public MessageDialog(CharSequence title, CharSequence message, CharSequence okText) {
+ this.title = title;
+ this.message = message;
+ this.okText = okText;
+ }
+
+ public MessageDialog(int titleResId, int messageResId, int okTextResId) {
+ this.title = getString(titleResId);
+ this.message = getString(messageResId);
+ this.okText = getString(okTextResId);
+ }
+
+ public MessageDialog(int titleResId, int messageResId) {
+ this.title = getString(titleResId);
+ this.message = getString(messageResId);
+ }
+
+ public static MessageDialog show(CharSequence title, CharSequence message, CharSequence okText) {
+ MessageDialog messageDialog = new MessageDialog(title, message, okText);
+ messageDialog.show();
+ return messageDialog;
+ }
+
+ public static MessageDialog show(int titleResId, int messageResId, int okTextResId) {
+ MessageDialog messageDialog = new MessageDialog(titleResId, messageResId, okTextResId);
+ messageDialog.show();
+ return messageDialog;
+ }
+
+ public static MessageDialog show(CharSequence title, CharSequence message) {
+ MessageDialog messageDialog = new MessageDialog(title, message);
+ messageDialog.show();
+ return messageDialog;
+ }
+
+ public static MessageDialog show(int titleResId, int messageResId) {
+ MessageDialog messageDialog = new MessageDialog(titleResId, messageResId);
+ messageDialog.show();
+ return messageDialog;
+ }
+
+ public MessageDialog(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText) {
+ this.title = title;
+ this.message = message;
+ this.okText = okText;
+ this.cancelText = cancelText;
+ }
+
+ public MessageDialog(int titleResId, int messageResId, int okTextResId, int cancelTextResId) {
+ this.title = getString(titleResId);
+ this.message = getString(messageResId);
+ this.okText = getString(okTextResId);
+ this.cancelText = getString(cancelTextResId);
+ }
+
+ public static MessageDialog show(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText) {
+ MessageDialog messageDialog = new MessageDialog(title, message, okText, cancelText);
+ messageDialog.show();
+ return messageDialog;
+ }
+
+ public static MessageDialog show(int titleResId, int messageResId, int okTextResId, int cancelTextResId) {
+ MessageDialog messageDialog = new MessageDialog(titleResId, messageResId, okTextResId, cancelTextResId);
+ messageDialog.show();
+ return messageDialog;
+ }
+
+ public MessageDialog(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText, CharSequence otherText) {
+ this.title = title;
+ this.message = message;
+ this.okText = okText;
+ this.cancelText = cancelText;
+ this.otherText = otherText;
+ }
+
+ public MessageDialog(int titleResId, int messageResId, int okTextResId, int cancelTextResId, int otherTextResId) {
+ this.title = getString(titleResId);
+ this.message = getString(messageResId);
+ this.okText = getString(okTextResId);
+ this.cancelText = getString(cancelTextResId);
+ this.otherText = getString(otherTextResId);
+ }
+
+ public static MessageDialog show(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText, CharSequence otherText) {
+ MessageDialog messageDialog = new MessageDialog(title, message, okText, cancelText, otherText);
+ messageDialog.show();
+ return messageDialog;
+ }
+
+ public static MessageDialog show(int titleResId, int messageResId, int okTextResId, int cancelTextResId, int otherTextResId) {
+ MessageDialog messageDialog = new MessageDialog(titleResId, messageResId, okTextResId, cancelTextResId, otherTextResId);
+ messageDialog.show();
+ return messageDialog;
+ }
+
+ protected DialogImpl dialogImpl;
+
+ public void show() {
+ super.beforeShow();
+ int layoutId = style.layout(isLightTheme());
+ layoutId = layoutId == 0 ? (isLightTheme() ? R.layout.layout_dialogx_material : R.layout.layout_dialogx_material_dark) : layoutId;
+
+ dialogView = createView(layoutId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+
+ public void show(Activity activity) {
+ super.beforeShow();
+ int layoutId = style.layout(isLightTheme());
+ layoutId = layoutId == 0 ? (isLightTheme() ? R.layout.layout_dialogx_material : R.layout.layout_dialogx_material_dark) : layoutId;
+
+ dialogView = createView(layoutId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(activity, dialogView);
+ }
+
+ public void refreshUI() {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ if (dialogImpl != null) dialogImpl.refreshView();
+ }
+ });
+ }
+
+ public class DialogImpl implements DialogConvertViewInterface {
+ BlurView blurView;
+
+ public DialogXBaseRelativeLayout boxRoot;
+ public MaxRelativeLayout bkg;
+ public TextView txtDialogTitle;
+ public TextView txtDialogTip;
+ public RelativeLayout boxCustom;
+ public EditText txtInput;
+ public LinearLayout boxButton;
+ public TextView btnSelectOther;
+ public View spaceOtherButton;
+ public View splitHorizontal;
+ public TextView btnSelectNegative;
+ public TextView btnSelectPositive;
+
+ public DialogImpl(View convertView) {
+ boxRoot = convertView.findViewById(R.id.box_root);
+ bkg = convertView.findViewById(R.id.bkg);
+ txtDialogTitle = convertView.findViewById(R.id.txt_dialog_title);
+ txtDialogTip = convertView.findViewById(R.id.txt_dialog_tip);
+ boxCustom = convertView.findViewById(R.id.box_custom);
+ txtInput = convertView.findViewById(R.id.txt_input);
+ boxButton = convertView.findViewById(R.id.box_button);
+ btnSelectOther = convertView.findViewById(R.id.btn_selectOther);
+ spaceOtherButton = convertView.findViewById(R.id.space_other_button);
+ splitHorizontal = convertView.findViewWithTag("split");
+ btnSelectNegative = convertView.findViewById(R.id.btn_selectNegative);
+ btnSelectPositive = convertView.findViewById(R.id.btn_selectPositive);
+ init();
+ dialogImpl = this;
+ refreshView();
+ }
+
+ public void init() {
+ if (titleTextInfo == null) titleTextInfo = DialogX.titleTextInfo;
+ if (messageTextInfo == null) messageTextInfo = DialogX.messageTextInfo;
+ if (okTextInfo == null) okTextInfo = DialogX.okButtonTextInfo;
+ if (okTextInfo == null) okTextInfo = DialogX.buttonTextInfo;
+ if (cancelTextInfo == null) cancelTextInfo = DialogX.buttonTextInfo;
+ if (otherTextInfo == null) otherTextInfo = DialogX.buttonTextInfo;
+ if (inputInfo == null) inputInfo = DialogX.inputInfo;
+ if (backgroundColor == -1) backgroundColor = DialogX.backgroundColor;
+
+ txtDialogTitle.getPaint().setFakeBoldText(true);
+ btnSelectNegative.getPaint().setFakeBoldText(true);
+ btnSelectPositive.getPaint().setFakeBoldText(true);
+ btnSelectOther.getPaint().setFakeBoldText(true);
+
+ txtDialogTip.setMovementMethod(LinkMovementMethod.getInstance());
+
+ boxRoot.setParentDialog(me);
+ boxRoot.setOnLifecycleCallBack(new DialogXBaseRelativeLayout.OnLifecycleCallBack() {
+ @Override
+ public void onShow() {
+ isShow = true;
+ boxRoot.setAlpha(0f);
+ int enterAnimResId = style.enterAnimResId() == 0 ? R.anim.anim_dialogx_default_enter : style.enterAnimResId();
+ if (overrideEnterAnimRes != 0) {
+ enterAnimResId = overrideEnterAnimRes;
+ }
+ Animation enterAnim = AnimationUtils.loadAnimation(getContext(), enterAnimResId);
+ long enterAnimDurationTemp = enterAnim.getDuration();
+ if (overrideEnterDuration >= 0) {
+ enterAnimDurationTemp = overrideEnterDuration;
+ }
+ if (enterAnimDuration >= 0) {
+ enterAnimDurationTemp = enterAnimDuration;
+ }
+ enterAnim.setDuration(enterAnimDurationTemp);
+ enterAnim.setInterpolator(new DecelerateInterpolator());
+ bkg.startAnimation(enterAnim);
+
+ boxRoot.animate()
+ .setDuration(enterAnimDurationTemp)
+ .alpha(1f)
+ .setInterpolator(new DecelerateInterpolator())
+ .setListener(null);
+
+ getDialogLifecycleCallback().onShow(me);
+
+ if (style.messageDialogBlurSettings() != null && style.messageDialogBlurSettings().blurBackground()) {
+ bkg.post(new Runnable() {
+ @Override
+ public void run() {
+ int blurFrontColor = getResources().getColor(style.messageDialogBlurSettings().blurForwardColorRes(isLightTheme()));
+ blurView = new BlurView(bkg.getContext(), null);
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(bkg.getWidth(), bkg.getHeight());
+ params.addRule(RelativeLayout.CENTER_IN_PARENT);
+ blurView.setOverlayColor(backgroundColor == -1 ? blurFrontColor : backgroundColor);
+ blurView.setTag("blurView");
+ blurView.setRadiusPx(style.messageDialogBlurSettings().blurBackgroundRoundRadiusPx());
+ bkg.addView(blurView, 0, params);
+ }
+ });
+ }
+
+ if (autoShowInputKeyboard) {
+ txtInput.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (txtInput == null) return;
+ txtInput.requestFocus();
+ txtInput.setFocusableInTouchMode(true);
+ InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(txtInput, InputMethodManager.RESULT_UNCHANGED_SHOWN);
+ txtInput.setSelection(txtInput.getText().length());
+ if (inputInfo != null && inputInfo.isSelectAllText()) {
+ txtInput.selectAll();
+ }
+ }
+ }, 300);
+ } else {
+ if (inputInfo != null && inputInfo.isSelectAllText()) {
+ txtInput.clearFocus();
+ txtInput.requestFocus();
+ txtInput.selectAll();
+ }
+ }
+ }
+
+ @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 (isCancelable()) {
+ dismiss();
+ }
+ return false;
+ }
+ });
+ btnSelectPositive.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (txtInput != null) {
+ InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(txtInput.getWindowToken(), 0);
+ }
+ if (okButtonClickListener != null) {
+ if (okButtonClickListener instanceof OnInputDialogButtonClickListener) {
+ String s = txtInput == null ? "" : txtInput.getText().toString();
+ if (!((OnInputDialogButtonClickListener) okButtonClickListener).onClick(me, v, s)) {
+ doDismiss(v);
+ }
+ } else if (okButtonClickListener instanceof OnDialogButtonClickListener) {
+ if (!((OnDialogButtonClickListener) okButtonClickListener).onClick(me, v)) {
+ doDismiss(v);
+ }
+ }
+ } else {
+ doDismiss(v);
+ }
+ }
+ });
+ btnSelectNegative.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (txtInput != null) {
+ InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(txtInput.getWindowToken(), 0);
+ }
+ if (cancelButtonClickListener != null) {
+ if (cancelButtonClickListener instanceof OnInputDialogButtonClickListener) {
+ String s = txtInput == null ? "" : txtInput.getText().toString();
+ if (!((OnInputDialogButtonClickListener) cancelButtonClickListener).onClick(me, v, s)) {
+ doDismiss(v);
+ }
+ } else {
+ if (!((OnDialogButtonClickListener) cancelButtonClickListener).onClick(me, v)) {
+ doDismiss(v);
+ }
+ }
+ } else {
+ doDismiss(v);
+ }
+ }
+ });
+ btnSelectOther.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (txtInput != null) {
+ InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(txtInput.getWindowToken(), 0);
+ }
+ if (otherButtonClickListener != null) {
+ if (otherButtonClickListener instanceof OnInputDialogButtonClickListener) {
+ String s = txtInput == null ? "" : txtInput.getText().toString();
+ if (!((OnInputDialogButtonClickListener) otherButtonClickListener).onClick(me, v, s)) {
+ doDismiss(v);
+ }
+ } else {
+ if (!((OnDialogButtonClickListener) otherButtonClickListener).onClick(me, v)) {
+ doDismiss(v);
+ }
+ }
+ } else {
+ doDismiss(v);
+ }
+ }
+ });
+ }
+
+ public void refreshView() {
+ if (backgroundColor != -1) {
+ tintColor(bkg, backgroundColor);
+ if (style instanceof MaterialStyle) {
+ tintColor(btnSelectOther, backgroundColor);
+ tintColor(btnSelectNegative, backgroundColor);
+ tintColor(btnSelectPositive, backgroundColor);
+ }
+ }
+
+ bkg.setMaxWidth(DialogX.dialogMaxWidth);
+ if (me instanceof InputDialog) {
+ txtInput.setVisibility(View.VISIBLE);
+ } else {
+ txtInput.setVisibility(View.GONE);
+ }
+ boxRoot.setClickable(true);
+ if (maskColor != -1) boxRoot.setBackgroundColor(maskColor);
+
+ showText(txtDialogTitle, title);
+ showText(txtDialogTip, message);
+ showText(btnSelectPositive, okText);
+ showText(btnSelectNegative, cancelText);
+ showText(btnSelectOther, otherText);
+
+ txtInput.setText(inputText);
+ txtInput.setHint(inputHintText);
+ if (spaceOtherButton != null) {
+ if (otherText == null) {
+ spaceOtherButton.setVisibility(View.GONE);
+ } else {
+ spaceOtherButton.setVisibility(View.VISIBLE);
+ }
+ }
+
+ useTextInfo(txtDialogTitle, titleTextInfo);
+ useTextInfo(txtDialogTip, messageTextInfo);
+ useTextInfo(btnSelectPositive, okTextInfo);
+ useTextInfo(btnSelectNegative, cancelTextInfo);
+ useTextInfo(btnSelectOther, otherTextInfo);
+ if (inputInfo != null) {
+ if (inputInfo.getMAX_LENGTH() != -1)
+ txtInput.setFilters(new InputFilter[]{new InputFilter.LengthFilter(inputInfo.getMAX_LENGTH())});
+ int inputType = InputType.TYPE_CLASS_TEXT | inputInfo.getInputType();
+ if (inputInfo.isMultipleLines()) {
+ inputType = inputType | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
+ }
+ txtInput.setInputType(inputType);
+ if (inputInfo.getTextInfo() != null) {
+ useTextInfo(txtInput, inputInfo.getTextInfo());
+ }
+ }
+
+ int visibleButtonCount = 0;
+ if (!isNull(okText)) {
+ visibleButtonCount = visibleButtonCount + 1;
+ }
+ if (!isNull(cancelText)) {
+ visibleButtonCount = visibleButtonCount + 1;
+ }
+ if (!isNull(otherText)) {
+ visibleButtonCount = visibleButtonCount + 1;
+ }
+
+ if (splitHorizontal != null) {
+ splitHorizontal.setBackgroundColor(getColor(style.splitColorRes(isLightTheme())));
+ }
+
+ boxButton.setOrientation(buttonOrientation);
+ if (buttonOrientation == LinearLayout.VERTICAL) {
+ //纵向
+ if (style.verticalButtonOrder() != null && style.verticalButtonOrder().length != 0) {
+ boxButton.removeAllViews();
+ for (int buttonType : style.verticalButtonOrder()) {
+ switch (buttonType) {
+ case DialogXStyle.BUTTON_OK:
+ boxButton.addView(btnSelectPositive);
+ if (style.overrideVerticalButtonRes() != null) {
+ btnSelectPositive.setBackgroundResource(
+ style.overrideVerticalButtonRes().overrideVerticalOkButtonBackgroundRes(visibleButtonCount, isLightTheme())
+ );
+ }
+ break;
+ case DialogXStyle.BUTTON_OTHER:
+ boxButton.addView(btnSelectOther);
+ if (style.overrideVerticalButtonRes() != null) {
+ btnSelectOther.setBackgroundResource(
+ style.overrideVerticalButtonRes().overrideVerticalOtherButtonBackgroundRes(visibleButtonCount, isLightTheme())
+ );
+ }
+ break;
+ case DialogXStyle.BUTTON_CANCEL:
+ boxButton.addView(btnSelectNegative);
+ if (style.overrideVerticalButtonRes() != null) {
+ btnSelectNegative.setBackgroundResource(
+ style.overrideVerticalButtonRes().overrideVerticalCancelButtonBackgroundRes(visibleButtonCount, isLightTheme())
+ );
+ }
+ break;
+ case DialogXStyle.SPACE:
+ Space space = new Space(getContext());
+ LinearLayout.LayoutParams spaceLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ spaceLp.weight = 1;
+ boxButton.addView(space, spaceLp);
+ break;
+ case DialogXStyle.SPLIT:
+ View splitView = new View(getContext());
+ splitView.setBackgroundColor(getResources().getColor(style.splitColorRes(isLightTheme())));
+ LinearLayout.LayoutParams viewLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, style.splitWidthPx());
+ boxButton.addView(splitView, viewLp);
+ break;
+ }
+ }
+ }
+ } else {
+ //横向
+ if (style.horizontalButtonOrder() != null && style.horizontalButtonOrder().length != 0) {
+ boxButton.removeAllViews();
+ for (int buttonType : style.horizontalButtonOrder()) {
+ switch (buttonType) {
+ case DialogXStyle.BUTTON_OK:
+ boxButton.addView(btnSelectPositive);
+ if (style.overrideHorizontalButtonRes() != null) {
+ btnSelectPositive.setBackgroundResource(
+ style.overrideHorizontalButtonRes().overrideHorizontalOkButtonBackgroundRes(visibleButtonCount, isLightTheme())
+ );
+ }
+ break;
+ case DialogXStyle.BUTTON_OTHER:
+ boxButton.addView(btnSelectOther);
+ if (style.overrideHorizontalButtonRes() != null) {
+ btnSelectOther.setBackgroundResource(
+ style.overrideHorizontalButtonRes().overrideHorizontalOtherButtonBackgroundRes(visibleButtonCount, isLightTheme())
+ );
+ }
+ break;
+ case DialogXStyle.BUTTON_CANCEL:
+ boxButton.addView(btnSelectNegative);
+ if (style.overrideHorizontalButtonRes() != null) {
+ btnSelectNegative.setBackgroundResource(
+ style.overrideHorizontalButtonRes().overrideHorizontalCancelButtonBackgroundRes(visibleButtonCount, isLightTheme())
+ );
+ }
+ break;
+ case DialogXStyle.SPACE:
+ if (boxButton.getChildCount() >= 1) {
+ if (boxButton.getChildAt(boxButton.getChildCount() - 1).getVisibility() == View.GONE) {
+ break;
+ }
+ } else {
+ break;
+ }
+ Space space = new Space(getContext());
+ LinearLayout.LayoutParams spaceLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ spaceLp.weight = 1;
+ boxButton.addView(space, spaceLp);
+ break;
+ case DialogXStyle.SPLIT:
+ if (boxButton.getChildCount() >= 1) {
+ if (boxButton.getChildAt(boxButton.getChildCount() - 1).getVisibility() == View.GONE) {
+ break;
+ }
+ } else {
+ break;
+ }
+ View splitView = new View(getContext());
+ splitView.setBackgroundColor(getResources().getColor(style.splitColorRes(isLightTheme())));
+ LinearLayout.LayoutParams viewLp = new LinearLayout.LayoutParams(style.splitWidthPx(), ViewGroup.LayoutParams.MATCH_PARENT);
+ boxButton.addView(splitView, viewLp);
+ break;
+ }
+ }
+ }
+ }
+
+ //Events
+ if (isCancelable()) {
+ boxRoot.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ doDismiss(v);
+ }
+ });
+ } else {
+ boxRoot.setOnClickListener(null);
+ }
+
+ if (onBindView != null && onBindView.getCustomView() != null) {
+ onBindView.bindParent(boxCustom, me);
+ boxCustom.setVisibility(View.VISIBLE);
+ } else {
+ boxCustom.setVisibility(View.GONE);
+ }
+ }
+
+ public void doDismiss(View v) {
+ if (v != null) v.setEnabled(false);
+
+ int exitAnimResId = style.exitAnimResId() == 0 ? R.anim.anim_dialogx_default_exit : style.exitAnimResId();
+ if (overrideExitAnimRes != 0) {
+ exitAnimResId = overrideExitAnimRes;
+ }
+ Animation exitAnim = AnimationUtils.loadAnimation(getContext(), exitAnimResId);
+ long exitAnimDurationTemp = exitAnim.getDuration();
+ exitAnim.setInterpolator(new AccelerateInterpolator());
+ if (overrideExitDuration >= 0) {
+ exitAnimDurationTemp = overrideExitDuration;
+ }
+ if (exitAnimDuration >= 0) {
+ exitAnimDurationTemp = exitAnimDuration;
+ }
+ exitAnim.setDuration(exitAnimDurationTemp);
+ bkg.startAnimation(exitAnim);
+
+ boxRoot.animate()
+ .alpha(0f)
+ .setInterpolator(new AccelerateInterpolator())
+ .setDuration(exitAnimDuration == -1 ? exitAnim.getDuration() : exitAnimDuration);
+
+ new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ dismiss(dialogView);
+ }
+ },exitAnimDuration == -1 ? exitAnim.getDuration() : exitAnimDuration);
+ }
+ }
+
+ @Override
+ public String dialogKey() {
+ return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")";
+ }
+
+ public void dismiss() {
+ if (dialogImpl == null) return;
+ dialogImpl.doDismiss(dialogImpl.bkg);
+ }
+
+ public DialogLifecycleCallback getDialogLifecycleCallback() {
+ return dialogLifecycleCallback == null ? new DialogLifecycleCallback() {
+ } : dialogLifecycleCallback;
+ }
+
+ public MessageDialog setDialogLifecycleCallback(DialogLifecycleCallback dialogLifecycleCallback) {
+ this.dialogLifecycleCallback = dialogLifecycleCallback;
+ if (isShow) dialogLifecycleCallback.onShow(me);
+ return this;
+ }
+
+ public MessageDialog setStyle(DialogXStyle style) {
+ this.style = style;
+ return this;
+ }
+
+ public MessageDialog setTheme(DialogX.THEME theme) {
+ this.theme = theme;
+ return this;
+ }
+
+ public CharSequence getOkButton() {
+ return okText;
+ }
+
+ public MessageDialog setOkButton(CharSequence okText) {
+ this.okText = okText;
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setOkButton(int okTextRedId) {
+ this.okText = getString(okTextRedId);
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setOkButton(OnDialogButtonClickListener okButtonClickListener) {
+ this.okButtonClickListener = okButtonClickListener;
+ return this;
+ }
+
+ public MessageDialog setOkButton(CharSequence okText, OnDialogButtonClickListener okButtonClickListener) {
+ this.okText = okText;
+ this.okButtonClickListener = okButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setOkButton(int okTextRedId, OnDialogButtonClickListener okButtonClickListener) {
+ this.okText = getString(okTextRedId);
+ this.okButtonClickListener = okButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getCancelButton() {
+ return cancelText;
+ }
+
+ public MessageDialog setCancelButton(CharSequence cancelText) {
+ this.cancelText = cancelText;
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setCancelButton(int cancelTextResId) {
+ this.cancelText = getString(cancelTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setCancelButton(OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ return this;
+ }
+
+ public MessageDialog setCancelButton(CharSequence cancelText, OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelText = cancelText;
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setCancelButton(int cancelTextResId, OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelText = getString(cancelTextResId);
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getOtherButton() {
+ return otherText;
+ }
+
+ public MessageDialog setOtherButton(CharSequence otherText) {
+ this.otherText = otherText;
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setOtherButton(int otherTextResId) {
+ this.otherText = getString(otherTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setOtherButton(OnDialogButtonClickListener otherButtonClickListener) {
+ this.otherButtonClickListener = otherButtonClickListener;
+ return this;
+ }
+
+ public MessageDialog setOtherButton(CharSequence otherText, OnDialogButtonClickListener otherButtonClickListener) {
+ this.otherText = otherText;
+ this.otherButtonClickListener = otherButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setOtherButton(int otherTextResId, OnDialogButtonClickListener otherButtonClickListener) {
+ this.otherText = getString(otherTextResId);
+ this.otherButtonClickListener = otherButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public OnDialogButtonClickListener getOkButtonClickListener() {
+ return (OnDialogButtonClickListener) okButtonClickListener;
+ }
+
+ public MessageDialog setOkButtonClickListener(OnDialogButtonClickListener okButtonClickListener) {
+ this.okButtonClickListener = okButtonClickListener;
+ return this;
+ }
+
+ public OnDialogButtonClickListener getCancelButtonClickListener() {
+ return (OnDialogButtonClickListener) cancelButtonClickListener;
+ }
+
+ public MessageDialog setCancelButtonClickListener(OnDialogButtonClickListener cancelButtonClickListener) {
+ this.cancelButtonClickListener = cancelButtonClickListener;
+ return this;
+ }
+
+ public OnDialogButtonClickListener getOtherButtonClickListener() {
+ return (OnDialogButtonClickListener) otherButtonClickListener;
+ }
+
+ public MessageDialog setOtherButtonClickListener(OnDialogButtonClickListener otherButtonClickListener) {
+ this.otherButtonClickListener = otherButtonClickListener;
+ return this;
+ }
+
+ public CharSequence getTitle() {
+ return title;
+ }
+
+ public MessageDialog setTitle(CharSequence title) {
+ this.title = title;
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setTitle(int titleResId) {
+ this.title = getString(titleResId);
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getMessage() {
+ return message;
+ }
+
+ public MessageDialog setMessage(CharSequence message) {
+ this.message = message;
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setMessage(int messageResId) {
+ this.message = getString(messageResId);
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getTitleTextInfo() {
+ return titleTextInfo;
+ }
+
+ public MessageDialog setTitleTextInfo(TextInfo titleTextInfo) {
+ this.titleTextInfo = titleTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getMessageTextInfo() {
+ return messageTextInfo;
+ }
+
+ public MessageDialog setMessageTextInfo(TextInfo messageTextInfo) {
+ this.messageTextInfo = messageTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getOkTextInfo() {
+ return okTextInfo;
+ }
+
+ public MessageDialog setOkTextInfo(TextInfo okTextInfo) {
+ this.okTextInfo = okTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getCancelTextInfo() {
+ return cancelTextInfo;
+ }
+
+ public MessageDialog setCancelTextInfo(TextInfo cancelTextInfo) {
+ this.cancelTextInfo = cancelTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getOtherTextInfo() {
+ return otherTextInfo;
+ }
+
+ public MessageDialog setOtherTextInfo(TextInfo otherTextInfo) {
+ this.otherTextInfo = otherTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public int getButtonOrientation() {
+ return buttonOrientation;
+ }
+
+ public MessageDialog setButtonOrientation(int buttonOrientation) {
+ this.buttonOrientation = buttonOrientation;
+ refreshUI();
+ return this;
+ }
+
+ public boolean isCancelable() {
+ if (privateCancelable != null) {
+ return privateCancelable == BOOLEAN.TRUE;
+ }
+ if (overrideCancelable != null) {
+ return overrideCancelable == BOOLEAN.TRUE;
+ }
+ return cancelable;
+ }
+
+ public MessageDialog setCancelable(boolean cancelable) {
+ this.privateCancelable = cancelable ? BOOLEAN.TRUE : BOOLEAN.FALSE;
+ refreshUI();
+ return this;
+ }
+
+ public OnBackPressedListener getOnBackPressedListener() {
+ return onBackPressedListener;
+ }
+
+ public MessageDialog setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
+ this.onBackPressedListener = onBackPressedListener;
+ return this;
+ }
+
+ public DialogImpl getDialogImpl() {
+ return dialogImpl;
+ }
+
+ public MessageDialog setCustomView(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ refreshUI();
+ return this;
+ }
+
+ public View getCustomView() {
+ if (onBindView == null) return null;
+ return onBindView.getCustomView();
+ }
+
+ public MessageDialog removeCustomView() {
+ this.onBindView.clean();
+ refreshUI();
+ return this;
+ }
+
+ public int getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public MessageDialog setBackgroundColor(@ColorInt int backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ refreshUI();
+ return this;
+ }
+
+ public String getInputText() {
+ if (dialogImpl.txtInput != null) {
+ return dialogImpl.txtInput.getText().toString();
+ } else {
+ return "";
+ }
+ }
+
+ public MessageDialog setBackgroundColorRes(@ColorRes int backgroundColorResId) {
+ this.backgroundColor = getColor(backgroundColorResId);
+ refreshUI();
+ return this;
+ }
+
+ public MessageDialog setMaskColor(@ColorInt int maskColor) {
+ this.maskColor = maskColor;
+ refreshUI();
+ return this;
+ }
+
+ public long getEnterAnimDuration() {
+ return enterAnimDuration;
+ }
+
+ public MessageDialog setEnterAnimDuration(long enterAnimDuration) {
+ this.enterAnimDuration = enterAnimDuration;
+ return this;
+ }
+
+ public long getExitAnimDuration() {
+ return exitAnimDuration;
+ }
+
+ public MessageDialog setExitAnimDuration(long exitAnimDuration) {
+ this.exitAnimDuration = exitAnimDuration;
+ return this;
+ }
+
+ @Override
+ public void onUIModeChange(Configuration newConfig) {
+ if (dialogView != null) {
+ dismiss(dialogView);
+ }
+ if (getDialogImpl().boxCustom != null) {
+ getDialogImpl().boxCustom.removeAllViews();
+ }
+ int layoutId = style.layout(isLightTheme());
+ layoutId = layoutId == 0 ? (isLightTheme() ? R.layout.layout_dialogx_material : R.layout.layout_dialogx_material_dark) : layoutId;
+
+ enterAnimDuration = 0;
+ dialogView = createView(layoutId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/dialogs/PopTip.java b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/PopTip.java
new file mode 100644
index 0000000..b65051b
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/PopTip.java
@@ -0,0 +1,851 @@
+package com.kongzue.dialogx.dialogs;
+
+import android.animation.Animator;
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+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.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+import androidx.annotation.IdRes;
+
+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.style.MaterialStyle;
+import com.kongzue.dialogx.util.TextInfo;
+import com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/20 11:59
+ */
+public class PopTip extends BaseDialog {
+
+ public static final int TIME_NO_AUTO_DISMISS_DELAY = -1;
+ protected static List popTipList;
+
+ protected OnBindView onBindView;
+ protected DialogLifecycleCallback dialogLifecycleCallback;
+ protected PopTip me = this;
+ protected DialogImpl dialogImpl;
+ protected int enterAnimResId = R.anim.anim_dialogx_default_enter;
+ protected int exitAnimResId = R.anim.anim_dialogx_default_exit;
+ private View dialogView;
+ protected DialogXStyle.PopTipSettings.ALIGN align;
+ protected OnDialogButtonClickListener onButtonClickListener;
+ protected OnDialogButtonClickListener onPopTipClickListener;
+ protected boolean autoTintIconInLightOrDarkMode = true;
+
+ protected int iconResId;
+ protected CharSequence message;
+ protected CharSequence buttonText;
+
+ protected TextInfo messageTextInfo;
+ protected TextInfo buttonTextInfo = new TextInfo().setBold(true);
+
+ protected PopTip() {
+ super();
+ }
+
+ public static PopTip build() {
+ return new PopTip();
+ }
+
+ public PopTip(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ }
+
+ public PopTip(CharSequence message) {
+ this.message = message;
+ }
+
+ public PopTip(int messageResId) {
+ this.message = getString(messageResId);
+ }
+
+ public PopTip(int iconResId, CharSequence message) {
+ this.iconResId = iconResId;
+ this.message = message;
+ }
+
+ public PopTip(int iconResId, CharSequence message, CharSequence buttonText) {
+ this.iconResId = iconResId;
+ this.message = message;
+ this.buttonText = buttonText;
+ }
+
+ public PopTip(int iconResId, int messageResId, int buttonTextResId) {
+ this.iconResId = iconResId;
+ this.message = getString(messageResId);
+ this.buttonText = getString(buttonTextResId);
+ }
+
+ public PopTip(CharSequence message, CharSequence buttonText) {
+ this.message = message;
+ this.buttonText = buttonText;
+ }
+
+ public PopTip(int messageResId, int buttonTextResId) {
+ this.message = getString(messageResId);
+ this.buttonText = getString(buttonTextResId);
+ }
+
+ public PopTip(CharSequence message, OnBindView onBindView) {
+ this.message = message;
+ this.onBindView = onBindView;
+ }
+
+ public PopTip(int messageResId, OnBindView onBindView) {
+ this.message = getString(messageResId);
+ this.onBindView = onBindView;
+ }
+
+ public PopTip(int iconResId, CharSequence message, OnBindView onBindView) {
+ this.iconResId = iconResId;
+ this.message = message;
+ this.onBindView = onBindView;
+ }
+
+ public PopTip(int iconResId, CharSequence message, CharSequence buttonText, OnBindView onBindView) {
+ this.iconResId = iconResId;
+ this.message = message;
+ this.buttonText = buttonText;
+ this.onBindView = onBindView;
+ }
+
+ public PopTip(int iconResId, int messageResId, int buttonTextResId, OnBindView onBindView) {
+ this.iconResId = iconResId;
+ this.message = getString(messageResId);
+ this.buttonText = getString(buttonTextResId);
+ this.onBindView = onBindView;
+ }
+
+ public PopTip(CharSequence message, CharSequence buttonText, OnBindView onBindView) {
+ this.message = message;
+ this.buttonText = buttonText;
+ this.onBindView = onBindView;
+ }
+
+ public PopTip(int messageResId, int buttonTextResId, OnBindView onBindView) {
+ this.message = getString(messageResId);
+ this.buttonText = getString(buttonTextResId);
+ this.onBindView = onBindView;
+ }
+
+ public static PopTip show(OnBindView onBindView) {
+ PopTip popTip = new PopTip(onBindView);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(CharSequence message) {
+ PopTip popTip = new PopTip(message);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(int messageResId) {
+ PopTip popTip = new PopTip(messageResId);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(CharSequence message, OnBindView onBindView) {
+ PopTip popTip = new PopTip(message, onBindView);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(int messageResId, OnBindView onBindView) {
+ PopTip popTip = new PopTip(messageResId, onBindView);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(CharSequence message, CharSequence buttonText) {
+ PopTip popTip = new PopTip(message, buttonText);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(int messageResId, int buttonTextResId) {
+ PopTip popTip = new PopTip(messageResId, buttonTextResId);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(int iconResId, CharSequence message, OnBindView onBindView) {
+ PopTip popTip = new PopTip(iconResId, message, onBindView);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(int iconResId, CharSequence message) {
+ PopTip popTip = new PopTip(iconResId, message);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(int iconResId, CharSequence message, CharSequence buttonText) {
+ PopTip popTip = new PopTip(iconResId, message, buttonText);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(int iconResId, CharSequence message, CharSequence buttonText, OnBindView onBindView) {
+ PopTip popTip = new PopTip(iconResId, message, buttonText, onBindView);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(int iconResId, int messageResId, int buttonTextResId, OnBindView onBindView) {
+ PopTip popTip = new PopTip(iconResId, messageResId, buttonTextResId, onBindView);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(CharSequence message, CharSequence buttonText, OnBindView onBindView) {
+ PopTip popTip = new PopTip(message, buttonText, onBindView);
+ popTip.show();
+ return popTip;
+ }
+
+ public static PopTip show(int messageResId, int buttonTextResId, OnBindView onBindView) {
+ PopTip popTip = new PopTip(messageResId, buttonTextResId, onBindView);
+ popTip.show();
+ return popTip;
+ }
+
+ public void show() {
+ super.beforeShow();
+ if (DialogX.onlyOnePopTip) {
+ PopTip oldInstance = null;
+ if (popTipList != null && !popTipList.isEmpty()) {
+ oldInstance = popTipList.get(popTipList.size() - 1);
+ }
+ if (oldInstance != null) {
+ oldInstance.dismiss();
+ }
+ } else {
+ if (popTipList != null) {
+ for (int i = 0; i < popTipList.size(); i++) {
+ PopTip popInstance = popTipList.get(i);
+ popInstance.moveUp();
+ }
+ }
+ }
+ if (popTipList == null) popTipList = new ArrayList<>();
+ popTipList.add(PopTip.this);
+ int layoutResId = isLightTheme() ? R.layout.layout_dialogx_poptip_material : R.layout.layout_dialogx_poptip_material_dark;
+ if (style.popTipSettings() != null) {
+ if (style.popTipSettings().layout(isLightTheme()) != 0) {
+ layoutResId = style.popTipSettings().layout(isLightTheme());
+ }
+ align = style.popTipSettings().align();
+ if (align == null) align = DialogXStyle.PopTipSettings.ALIGN.BOTTOM;
+ enterAnimResId = style.popTipSettings().enterAnimResId(isLightTheme()) != 0 ? style.popTipSettings().enterAnimResId(isLightTheme()) : R.anim.anim_dialogx_default_enter;
+ exitAnimResId = style.popTipSettings().exitAnimResId(isLightTheme()) != 0 ? style.popTipSettings().exitAnimResId(isLightTheme()) : R.anim.anim_dialogx_default_exit;
+ }
+ dialogView = createView(layoutResId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+
+ public void show(Activity activity) {
+ super.beforeShow();
+ if (DialogX.onlyOnePopTip) {
+ PopTip oldInstance = null;
+ if (popTipList != null && !popTipList.isEmpty()) {
+ oldInstance = popTipList.get(popTipList.size() - 1);
+ }
+ if (oldInstance != null) {
+ oldInstance.dismiss();
+ }
+ } else {
+ if (popTipList != null) {
+ for (int i = 0; i < popTipList.size(); i++) {
+ PopTip popInstance = popTipList.get(i);
+ popInstance.moveUp();
+ }
+ }
+ }
+ if (popTipList == null) popTipList = new ArrayList<>();
+ popTipList.add(PopTip.this);
+ int layoutResId = isLightTheme() ? R.layout.layout_dialogx_poptip_material : R.layout.layout_dialogx_poptip_material_dark;
+ if (style.popTipSettings() != null) {
+ if (style.popTipSettings().layout(isLightTheme()) != 0) {
+ layoutResId = style.popTipSettings().layout(isLightTheme());
+ }
+ align = style.popTipSettings().align();
+ if (align == null) align = DialogXStyle.PopTipSettings.ALIGN.BOTTOM;
+ enterAnimResId = style.popTipSettings().enterAnimResId(isLightTheme()) != 0 ? style.popTipSettings().enterAnimResId(isLightTheme()) : R.anim.anim_dialogx_default_enter;
+ exitAnimResId = style.popTipSettings().exitAnimResId(isLightTheme()) != 0 ? style.popTipSettings().exitAnimResId(isLightTheme()) : R.anim.anim_dialogx_default_exit;
+ }
+ dialogView = createView(layoutResId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(activity, dialogView);
+ }
+
+ @Override
+ public String dialogKey() {
+ return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")";
+ }
+
+ protected Timer autoDismissTimer;
+
+ public PopTip autoDismiss(long delay) {
+ if (autoDismissTimer != null) {
+ autoDismissTimer.cancel();
+ }
+ if (delay < 0) return this;
+ autoDismissTimer = new Timer();
+ autoDismissTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ dismiss();
+ }
+ }, delay);
+ return this;
+ }
+
+ public PopTip showShort() {
+ autoDismiss(2000);
+ return this;
+ }
+
+ public PopTip showLong() {
+ autoDismiss(3500);
+ return this;
+ }
+
+ public PopTip showAlways() {
+ return noAutoDismiss();
+ }
+
+ public PopTip noAutoDismiss() {
+ autoDismiss(TIME_NO_AUTO_DISMISS_DELAY);
+ return this;
+ }
+
+ public class DialogImpl implements DialogConvertViewInterface {
+
+ public DialogXBaseRelativeLayout boxRoot;
+ public LinearLayout boxBody;
+ public ImageView imgDialogxPopIcon;
+ public TextView txtDialogxPopText;
+ public RelativeLayout boxCustom;
+ public TextView txtDialogxButton;
+
+ public DialogImpl(View convertView) {
+ boxRoot = convertView.findViewById(R.id.box_root);
+ boxBody = convertView.findViewById(R.id.box_body);
+ imgDialogxPopIcon = convertView.findViewById(R.id.img_dialogx_pop_icon);
+ txtDialogxPopText = convertView.findViewById(R.id.txt_dialogx_pop_text);
+ boxCustom = convertView.findViewById(R.id.box_custom);
+ txtDialogxButton = convertView.findViewById(R.id.txt_dialogx_button);
+
+ init();
+ dialogImpl = this;
+ refreshView();
+ }
+
+ @Override
+ public void init() {
+ if (messageTextInfo == null) messageTextInfo = DialogX.popTextInfo;
+ if (buttonTextInfo == null) buttonTextInfo = DialogX.buttonTextInfo;
+ if (backgroundColor == -1) backgroundColor = DialogX.backgroundColor;
+
+ if (autoDismissTimer == null) {
+ showShort();
+ }
+
+ boxRoot.setParentDialog(me);
+ boxRoot.setAutoUnsafePlacePadding(false);
+ boxRoot.setOnLifecycleCallBack(new DialogXBaseRelativeLayout.OnLifecycleCallBack() {
+ @Override
+ public void onShow() {
+ isShow = true;
+ boxRoot.setAlpha(0f);
+
+ getDialogLifecycleCallback().onShow(me);
+ }
+
+ @Override
+ public void onDismiss() {
+ if (popTipList != null) popTipList.remove(PopTip.this);
+ isShow = false;
+ getDialogLifecycleCallback().onDismiss(me);
+ }
+ });
+
+ RelativeLayout.LayoutParams rlp;
+ rlp = ((RelativeLayout.LayoutParams) boxBody.getLayoutParams());
+ if (align == null) align = DialogXStyle.PopTipSettings.ALIGN.BOTTOM;
+ switch (align) {
+ case TOP:
+ rlp.removeRule(RelativeLayout.CENTER_IN_PARENT);
+ rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ break;
+ case BOTTOM:
+ rlp.removeRule(RelativeLayout.CENTER_IN_PARENT);
+ rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ boxRoot.setAutoUnsafePlacePadding(true);
+ break;
+ case CENTER:
+ rlp.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
+ rlp.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ rlp.addRule(RelativeLayout.CENTER_IN_PARENT);
+ break;
+ }
+ boxBody.setLayoutParams(rlp);
+
+ boxRoot.setOnSafeInsetsChangeListener(new OnSafeInsetsChangeListener() {
+ @Override
+ public void onChange(Rect unsafeRect) {
+ if (align == DialogXStyle.PopTipSettings.ALIGN.TOP) {
+ boxBody.setY(unsafeRect.top);
+ } else if (align == DialogXStyle.PopTipSettings.ALIGN.TOP_INSIDE) {
+ boxBody.setPadding(0, unsafeRect.top, 0, 0);
+ }
+ }
+ });
+
+ boxRoot.setOnBackPressedListener(new OnBackPressedListener() {
+ @Override
+ public boolean onBackPressed() {
+ return false;
+ }
+ });
+
+ boxRoot.post(new Runnable() {
+ @Override
+ public void run() {
+
+ Animation enterAnim = AnimationUtils.loadAnimation(getContext(), enterAnimResId);
+ enterAnim.setInterpolator(new DecelerateInterpolator(2f));
+ if (enterAnimDuration != -1) {
+ enterAnim.setDuration(enterAnimDuration);
+ }
+ boxBody.startAnimation(enterAnim);
+
+ boxRoot.animate()
+ .setDuration(enterAnimDuration == -1 ? enterAnim.getDuration() : enterAnimDuration)
+ .alpha(1f)
+ .setInterpolator(new DecelerateInterpolator())
+ .setListener(null);
+ }
+ });
+
+ txtDialogxButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (onButtonClickListener != null) {
+ if (!onButtonClickListener.onClick(me, v)) {
+ doDismiss(v);
+ }
+ } else {
+ doDismiss(v);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void refreshView() {
+ if (backgroundColor != -1) {
+ tintColor(boxBody, backgroundColor);
+ }
+
+ if (onBindView != null && onBindView.getCustomView() != null) {
+ onBindView.bindParent(boxCustom, me);
+ boxCustom.setVisibility(View.VISIBLE);
+ } else {
+ boxCustom.setVisibility(View.GONE);
+ }
+
+
+ showText(txtDialogxPopText, message);
+ showText(txtDialogxButton, buttonText);
+
+ useTextInfo(txtDialogxPopText, messageTextInfo);
+ useTextInfo(txtDialogxButton, buttonTextInfo);
+
+ if (iconResId != 0) {
+ imgDialogxPopIcon.setVisibility(View.VISIBLE);
+ imgDialogxPopIcon.setImageResource(iconResId);
+ if (autoTintIconInLightOrDarkMode) {
+ imgDialogxPopIcon.setImageTintList(txtDialogxPopText.getTextColors());
+ } else {
+ imgDialogxPopIcon.setImageTintList(null);
+ }
+ } else {
+ imgDialogxPopIcon.setVisibility(View.GONE);
+ }
+
+ if (onPopTipClickListener != null) {
+ boxBody.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (!onPopTipClickListener.onClick(me, v)) {
+ dismiss();
+ }
+ }
+ });
+ } else {
+ boxBody.setOnClickListener(null);
+ boxBody.setClickable(false);
+ }
+ }
+
+ @Override
+ public void doDismiss(final View v) {
+ boxRoot.post(new Runnable() {
+ @Override
+ public void run() {
+ if (v != null) v.setEnabled(false);
+
+ Animation exitAnim = AnimationUtils.loadAnimation(getContext(), exitAnimResId);
+ if (exitAnimDuration != -1) {
+ exitAnim.setDuration(exitAnimResId);
+ }
+ boxBody.startAnimation(exitAnim);
+
+ boxRoot.animate()
+ .alpha(0f)
+ .setInterpolator(new AccelerateInterpolator())
+ .setDuration(exitAnimDuration == -1 ? exitAnim.getDuration() : exitAnimDuration);
+
+ new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ dismiss(dialogView);
+ }
+ },exitAnimDuration == -1 ? exitAnim.getDuration() : exitAnimDuration);
+ }
+ });
+ }
+ }
+
+ private void moveUp() {
+ if (getDialogImpl() != null && getDialogImpl().boxBody != null) {
+ getDialogImpl().boxBody.post(new Runnable() {
+ @Override
+ public void run() {
+ if (style.popTipSettings() != null) align = style.popTipSettings().align();
+ if (align == null) align = DialogXStyle.PopTipSettings.ALIGN.BOTTOM;
+ switch (align) {
+ case TOP:
+ getDialogImpl().boxBody.animate()
+ .y(getDialogImpl().boxBody.getY() + getDialogImpl().boxBody.getHeight() * 1.3f)
+ .setDuration(enterAnimDuration == -1 ? 300 : enterAnimDuration)
+ .setInterpolator(new DecelerateInterpolator(2f))
+ ;
+ break;
+ case TOP_INSIDE:
+ getDialogImpl().boxBody.animate()
+ .y(getDialogImpl().boxBody.getY() + getDialogImpl().boxBody.getHeight() - getDialogImpl().boxBody.getPaddingTop())
+ .setDuration(enterAnimDuration == -1 ? 300 : enterAnimDuration)
+ .setInterpolator(new DecelerateInterpolator(2f))
+ ;
+ break;
+ case CENTER:
+ case BOTTOM:
+ case BOTTOM_INSIDE:
+ getDialogImpl().boxBody.animate()
+ .y(getDialogImpl().boxBody.getY() - getDialogImpl().boxBody.getHeight() * 1.3f)
+ .setDuration(enterAnimDuration == -1 ? 300 : enterAnimDuration)
+ .setInterpolator(new DecelerateInterpolator(2f))
+ ;
+ break;
+ }
+ }
+ });
+ }
+ }
+
+ public void refreshUI() {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ if (dialogImpl != null) dialogImpl.refreshView();
+ }
+ });
+ }
+
+ public void dismiss() {
+ if (dialogImpl == null) return;
+ dialogImpl.doDismiss(null);
+ }
+
+ public DialogLifecycleCallback getDialogLifecycleCallback() {
+ return dialogLifecycleCallback == null ? new DialogLifecycleCallback() {
+ } : dialogLifecycleCallback;
+ }
+
+ public PopTip setDialogLifecycleCallback(DialogLifecycleCallback dialogLifecycleCallback) {
+ this.dialogLifecycleCallback = dialogLifecycleCallback;
+ if (isShow) dialogLifecycleCallback.onShow(me);
+ return this;
+ }
+
+ public PopTip setStyle(DialogXStyle style) {
+ this.style = style;
+ return this;
+ }
+
+ public PopTip setTheme(DialogX.THEME theme) {
+ this.theme = theme;
+ return this;
+ }
+
+ public PopTip.DialogImpl getDialogImpl() {
+ return dialogImpl;
+ }
+
+ public PopTip setCustomView(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ refreshUI();
+ return this;
+ }
+
+ public View getCustomView() {
+ if (onBindView == null) return null;
+ return onBindView.getCustomView();
+ }
+
+ public PopTip removeCustomView() {
+ this.onBindView.clean();
+ refreshUI();
+ return this;
+ }
+
+ public DialogXStyle.PopTipSettings.ALIGN getAlign() {
+ return align;
+ }
+
+ public PopTip setAlign(DialogXStyle.PopTipSettings.ALIGN align) {
+ this.align = align;
+ return this;
+ }
+
+ public int getIconResId() {
+ return iconResId;
+ }
+
+ public PopTip setIconResId(int iconResId) {
+ this.iconResId = iconResId;
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getMessage() {
+ return message;
+ }
+
+ public PopTip setMessage(CharSequence message) {
+ this.message = message;
+ refreshUI();
+ return this;
+ }
+
+ public PopTip setMessage(int messageResId) {
+ this.message = getString(messageResId);
+ refreshUI();
+ return this;
+ }
+
+ public CharSequence getButtonText() {
+ return buttonText;
+ }
+
+ public PopTip setButton(CharSequence buttonText) {
+ this.buttonText = buttonText;
+ refreshUI();
+ return this;
+ }
+
+ public PopTip setButton(int buttonTextResId) {
+ this.buttonText = getString(buttonTextResId);
+ refreshUI();
+ return this;
+ }
+
+ public PopTip setButton(CharSequence buttonText, OnDialogButtonClickListener onButtonClickListener) {
+ this.buttonText = buttonText;
+ this.onButtonClickListener = onButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public PopTip setButton(int buttonTextResId, OnDialogButtonClickListener onButtonClickListener) {
+ this.buttonText = getString(buttonTextResId);
+ this.onButtonClickListener = onButtonClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public PopTip setButton(OnDialogButtonClickListener onButtonClickListener) {
+ this.onButtonClickListener = onButtonClickListener;
+ return this;
+ }
+
+ public TextInfo getMessageTextInfo() {
+ return messageTextInfo;
+ }
+
+ public PopTip setMessageTextInfo(TextInfo messageTextInfo) {
+ this.messageTextInfo = messageTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public TextInfo getButtonTextInfo() {
+ return buttonTextInfo;
+ }
+
+ public PopTip setButtonTextInfo(TextInfo buttonTextInfo) {
+ this.buttonTextInfo = buttonTextInfo;
+ refreshUI();
+ return this;
+ }
+
+ public OnDialogButtonClickListener getOnButtonClickListener() {
+ return onButtonClickListener;
+ }
+
+ public PopTip setOnButtonClickListener(OnDialogButtonClickListener onButtonClickListener) {
+ this.onButtonClickListener = onButtonClickListener;
+ return this;
+ }
+
+ public boolean isAutoTintIconInLightOrDarkMode() {
+ return autoTintIconInLightOrDarkMode;
+ }
+
+ public PopTip setAutoTintIconInLightOrDarkMode(boolean autoTintIconInLightOrDarkMode) {
+ this.autoTintIconInLightOrDarkMode = autoTintIconInLightOrDarkMode;
+ refreshUI();
+ return this;
+ }
+
+ public OnDialogButtonClickListener getOnPopTipClickListener() {
+ return onPopTipClickListener;
+ }
+
+ public PopTip setOnPopTipClickListener(OnDialogButtonClickListener onPopTipClickListener) {
+ this.onPopTipClickListener = onPopTipClickListener;
+ refreshUI();
+ return this;
+ }
+
+ public int getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public PopTip setBackgroundColor(@ColorInt int backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ refreshUI();
+ return this;
+ }
+
+ public PopTip setBackgroundColorRes(@ColorRes int backgroundColorResId) {
+ this.backgroundColor = getColor(backgroundColorResId);
+ refreshUI();
+ return this;
+ }
+
+ public long getEnterAnimDuration() {
+ return enterAnimDuration;
+ }
+
+ public PopTip setEnterAnimDuration(long enterAnimDuration) {
+ this.enterAnimDuration = enterAnimDuration;
+ return this;
+ }
+
+ public long getExitAnimDuration() {
+ return exitAnimDuration;
+ }
+
+ public PopTip setExitAnimDuration(long exitAnimDuration) {
+ this.exitAnimDuration = exitAnimDuration;
+ return this;
+ }
+
+ @Override
+ public void onUIModeChange(Configuration newConfig) {
+ if (dialogView != null) {
+ dismiss(dialogView);
+ }
+ if (getDialogImpl().boxCustom != null) {
+ getDialogImpl().boxCustom.removeAllViews();
+ }
+
+ if (DialogX.onlyOnePopTip) {
+ PopTip oldInstance = null;
+ if (popTipList != null && !popTipList.isEmpty()) {
+ oldInstance = popTipList.get(popTipList.size() - 1);
+ }
+ if (oldInstance != null) {
+ oldInstance.dismiss();
+ }
+ } else {
+ if (popTipList != null) {
+ for (int i = 0; i < popTipList.size(); i++) {
+ PopTip popInstance = popTipList.get(i);
+ popInstance.moveUp();
+ }
+ }
+ }
+ if (popTipList == null) popTipList = new ArrayList<>();
+ popTipList.add(PopTip.this);
+
+ int layoutResId = isLightTheme() ? R.layout.layout_dialogx_poptip_material : R.layout.layout_dialogx_poptip_material_dark;
+ if (style.popTipSettings() != null) {
+ if (style.popTipSettings().layout(isLightTheme()) != 0) {
+ layoutResId = style.popTipSettings().layout(isLightTheme());
+ }
+ align = style.popTipSettings().align();
+ if (align == null) align = DialogXStyle.PopTipSettings.ALIGN.BOTTOM;
+ enterAnimResId = style.popTipSettings().enterAnimResId(isLightTheme()) != 0 ? style.popTipSettings().enterAnimResId(isLightTheme()) : R.anim.anim_dialogx_default_enter;
+ exitAnimResId = style.popTipSettings().exitAnimResId(isLightTheme()) != 0 ? style.popTipSettings().exitAnimResId(isLightTheme()) : R.anim.anim_dialogx_default_exit;
+ }
+ enterAnimDuration = 0;
+ dialogView = createView(layoutResId);
+ dialogImpl = new DialogImpl(dialogView);
+ dialogView.setTag(me);
+ show(dialogView);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/dialogs/TipDialog.java b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/TipDialog.java
new file mode 100644
index 0000000..8f94db5
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/TipDialog.java
@@ -0,0 +1,162 @@
+package com.kongzue.dialogx.dialogs;
+
+import android.app.Activity;
+
+import com.kongzue.dialogx.interfaces.DialogLifecycleCallback;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/28 23:53
+ */
+public class TipDialog extends WaitDialog {
+
+ protected TipDialog() {
+ super();
+ }
+
+ public static WaitDialog show(int messageResId) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(messageResId);
+ if (dialogImpl != null) {
+ dialogImpl.showTip(TYPE.WARNING);
+ } else {
+ me().showTip(messageResId, TYPE.WARNING);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(Activity activity, int messageResId) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(messageResId);
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ dialogImpl.showTip(TYPE.WARNING);
+ } else {
+ me().showTip(activity, messageResId, TYPE.WARNING);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(CharSequence message) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(message);
+ if (dialogImpl != null) {
+ dialogImpl.showTip(TYPE.WARNING);
+ } else {
+ me().showTip(message, TYPE.WARNING);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(Activity activity, CharSequence message) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(message);
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ dialogImpl.showTip(TYPE.WARNING);
+ } else {
+ me().showTip(activity, message, TYPE.WARNING);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(int messageResId, TYPE tip) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(messageResId);
+ if (dialogImpl != null) {
+ dialogImpl.showTip(tip);
+ } else {
+ me().showTip(messageResId, tip);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(Activity activity, int messageResId, TYPE tip) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(messageResId);
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ dialogImpl.showTip(tip);
+ } else {
+ me().showTip(activity, messageResId, tip);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(CharSequence message, TYPE tip) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(message);
+ if (dialogImpl != null) {
+ dialogImpl.showTip(tip);
+ } else {
+ me().showTip(message, tip);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(Activity activity, CharSequence message, TYPE tip) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(message);
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ dialogImpl.showTip(tip);
+ } else {
+ me().showTip(activity, message, tip);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(int messageResId, TYPE tip, long duration) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(messageResId);
+ me().tipShowDuration = duration;
+ if (dialogImpl != null) {
+ dialogImpl.showTip(tip);
+ } else {
+ me().showTip(messageResId, tip);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(Activity activity, int messageResId, TYPE tip, long duration) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(messageResId);
+ me().tipShowDuration = duration;
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ dialogImpl.showTip(tip);
+ } else {
+ me().showTip(activity, messageResId, tip);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(CharSequence message, TYPE tip, long duration) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(message);
+ me().tipShowDuration = duration;
+ if (dialogImpl != null) {
+ dialogImpl.showTip(tip);
+ } else {
+ me().showTip(message, tip);
+ }
+ return me();
+ }
+
+ public static WaitDialog show(Activity activity, CharSequence message, TYPE tip, long duration) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(message);
+ me().tipShowDuration = duration;
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ dialogImpl.showTip(tip);
+ } else {
+ me().showTip(activity, message, tip);
+ }
+ return me();
+ }
+
+ @Override
+ public String dialogKey() {
+ return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")";
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/dialogs/WaitDialog.java b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/WaitDialog.java
new file mode 100644
index 0000000..a6317f9
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/WaitDialog.java
@@ -0,0 +1,750 @@
+package com.kongzue.dialogx.dialogs;
+
+import android.animation.Animator;
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.os.Handler;
+import android.os.Looper;
+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.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+
+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.OnBackPressedListener;
+import com.kongzue.dialogx.interfaces.OnBindView;
+import com.kongzue.dialogx.interfaces.ProgressViewInterface;
+import com.kongzue.dialogx.util.TextInfo;
+import com.kongzue.dialogx.util.views.BlurView;
+import com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout;
+import com.kongzue.dialogx.util.views.MaxRelativeLayout;
+import com.kongzue.dialogx.util.views.ProgressView;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/27 14:50
+ */
+public class WaitDialog extends BaseDialog {
+
+ public static int overrideEnterDuration = -1;
+ public static int overrideExitDuration = -1;
+ public static int overrideEnterAnimRes = 0;
+ public static int overrideExitAnimRes = 0;
+ public static BOOLEAN overrideCancelable;
+ protected OnBindView onBindView;
+
+ public enum TYPE {
+ NONE,
+ SUCCESS,
+ WARNING,
+ ERROR
+ }
+
+ protected static WeakReference me;
+ protected CharSequence message;
+ protected long tipShowDuration = 1500;
+ protected float waitProgress = -1;
+ protected int showType = -1; //-1:Waitdialog 状态标示符,其余为 TipDialog 状态标示
+ protected TextInfo messageTextInfo;
+ protected int maskColor = -1;
+ protected BOOLEAN privateCancelable;
+
+ private DialogLifecycleCallback dialogLifecycleCallback;
+
+ protected WaitDialog() {
+ super();
+ me = new WeakReference<>(this);
+ cancelable = DialogX.cancelableTipDialog;
+ }
+
+ public static WaitDialog show(CharSequence message) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().message = message;
+ me().showType = -1;
+ if (dialogImpl != null) {
+ dialogImpl.progressView.loading();
+ setMessage(message);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.message = message;
+ waitDialog.show();
+ return waitDialog;
+ }
+ }
+
+ public static WaitDialog show(Activity activity, CharSequence message) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().message = message;
+ me().showType = -1;
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ dialogImpl.progressView.loading();
+ setMessage(message);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.message = message;
+ waitDialog.show(activity);
+ return waitDialog;
+ }
+ }
+
+ public static WaitDialog show(int messageResId) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(messageResId);
+ me().showType = -1;
+ if (dialogImpl != null) {
+ dialogImpl.progressView.loading();
+ setMessage(messageResId);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.preMessage(messageResId);
+ waitDialog.show();
+ return waitDialog;
+ }
+ }
+
+ public static WaitDialog show(Activity activity, int messageResId) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().preMessage(messageResId);
+ me().showType = -1;
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ dialogImpl.progressView.loading();
+ setMessage(messageResId);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.preMessage(messageResId);
+ waitDialog.show(activity);
+ return waitDialog;
+ }
+ }
+
+ public static WaitDialog show(CharSequence message, float progress) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().showType = -1;
+ me().preMessage(message);
+ if (dialogImpl != null) {
+ setMessage(message);
+ me().setProgress(progress);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.preMessage(message);
+ waitDialog.show();
+ waitDialog.setProgress(progress);
+ return waitDialog;
+ }
+ }
+
+ public static WaitDialog show(Activity activity, CharSequence message, float progress) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().showType = -1;
+ me().preMessage(message);
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ setMessage(message);
+ me().setProgress(progress);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.preMessage(message);
+ waitDialog.show(activity);
+ waitDialog.setProgress(progress);
+ return waitDialog;
+ }
+ }
+
+ public static WaitDialog show(int messageResId, float progress) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().showType = -1;
+ me().preMessage(messageResId);
+ if (dialogImpl != null) {
+ setMessage(messageResId);
+ me().setProgress(progress);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.preMessage(messageResId);
+ waitDialog.show();
+ waitDialog.setProgress(progress);
+ return waitDialog;
+ }
+ }
+
+ public static WaitDialog show(Activity activity, int messageResId, float progress) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().showType = -1;
+ me().preMessage(messageResId);
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ setMessage(messageResId);
+ me().setProgress(progress);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.preMessage(messageResId);
+ waitDialog.show(activity);
+ waitDialog.setProgress(progress);
+ return waitDialog;
+ }
+ }
+
+ public static WaitDialog show(Activity activity, float progress) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().showType = -1;
+ if (dialogImpl != null && dialogImpl.bkg.getContext() == activity) {
+ me().setProgress(progress);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.show(activity);
+ waitDialog.setProgress(progress);
+ return waitDialog;
+ }
+ }
+
+ public static WaitDialog show(float progress) {
+ DialogImpl dialogImpl = me().dialogImpl;
+ me().showType = -1;
+ if (dialogImpl != null) {
+ me().setProgress(progress);
+ return me();
+ } else {
+ WaitDialog waitDialog = new WaitDialog();
+ waitDialog.show();
+ waitDialog.setProgress(progress);
+ return waitDialog;
+ }
+ }
+
+ public float getProgress() {
+ return waitProgress;
+ }
+
+ public WaitDialog setProgress(float waitProgress) {
+ this.waitProgress = waitProgress;
+ refreshUI();
+ return this;
+ }
+
+ private View dialogView;
+
+ public WaitDialog show() {
+ super.beforeShow();
+ int layoutResId = R.layout.layout_dialogx_wait;
+ if (style.overrideWaitTipRes() != null && style.overrideWaitTipRes().overrideWaitLayout(isLightTheme()) != 0) {
+ layoutResId = style.overrideWaitTipRes().overrideWaitLayout(isLightTheme());
+ }
+ dialogImpl = new DialogImpl(layoutResId);
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ dialogImpl.lazyCreate();
+ dialogView.setTag(me.get());
+ show(dialogView);
+ }
+ });
+ return this;
+ }
+
+ public WaitDialog show(final Activity activity) {
+ super.beforeShow();
+ int layoutResId = R.layout.layout_dialogx_wait;
+ if (style.overrideWaitTipRes() != null && style.overrideWaitTipRes().overrideWaitLayout(isLightTheme()) != 0) {
+ layoutResId = style.overrideWaitTipRes().overrideWaitLayout(isLightTheme());
+ }
+ dialogImpl = new DialogImpl(layoutResId);
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ dialogImpl.lazyCreate();
+ dialogView.setTag(me.get());
+ show(activity, dialogView);
+ }
+ });
+ return this;
+ }
+
+ protected DialogImpl dialogImpl;
+
+ public class DialogImpl implements DialogConvertViewInterface {
+ public DialogXBaseRelativeLayout boxRoot;
+ public MaxRelativeLayout bkg;
+ public BlurView blurView;
+ public RelativeLayout boxProgress;
+ public ProgressViewInterface progressView;
+ public RelativeLayout boxCustomView;
+ public TextView txtInfo;
+
+ private int layoutResId;
+
+ public DialogImpl(int layoutResId) {
+ this.layoutResId = layoutResId;
+ }
+
+ public void lazyCreate(){
+ dialogView = createView(layoutResId);
+ boxRoot = dialogView.findViewById(R.id.box_root);
+ bkg = dialogView.findViewById(R.id.bkg);
+ blurView = dialogView.findViewById(R.id.blurView);
+ boxProgress = dialogView.findViewById(R.id.box_progress);
+ View progressViewCache = (View) style.overrideWaitTipRes().overrideWaitView(getContext(), isLightTheme());
+ if (progressViewCache == null) {
+ progressViewCache = new ProgressView(getContext());
+ }
+ progressView = (ProgressViewInterface) progressViewCache;
+ boxProgress.addView(progressViewCache, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ boxCustomView = dialogView.findViewById(R.id.box_customView);
+ txtInfo = dialogView.findViewById(R.id.txt_info);
+ init();
+ dialogImpl = this;
+ refreshView();
+ }
+
+ public DialogImpl(View convertView) {
+ boxRoot = convertView.findViewById(R.id.box_root);
+ bkg = convertView.findViewById(R.id.bkg);
+ blurView = convertView.findViewById(R.id.blurView);
+ boxProgress = convertView.findViewById(R.id.box_progress);
+ View progressViewCache = (View) style.overrideWaitTipRes().overrideWaitView(getContext(), isLightTheme());
+ if (progressViewCache == null) {
+ progressViewCache = new ProgressView(getContext());
+ }
+ progressView = (ProgressViewInterface) progressViewCache;
+ boxProgress.addView(progressViewCache, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ boxCustomView = convertView.findViewById(R.id.box_customView);
+ txtInfo = convertView.findViewById(R.id.txt_info);
+ init();
+ dialogImpl = this;
+ refreshView();
+ }
+
+ public void init() {
+ if (messageTextInfo == null) messageTextInfo = DialogX.tipTextInfo;
+ if (backgroundColor == -1) backgroundColor = DialogX.tipBackgroundColor;
+
+ if (style.overrideWaitTipRes() == null) {
+ blurView.setRadiusPx(dip2px(15));
+ } else {
+ blurView.setRadiusPx(style.overrideWaitTipRes().overrideRadiusPx() < 0 ? dip2px(15) : style.overrideWaitTipRes().overrideRadiusPx());
+ }
+ boxRoot.setClickable(true);
+
+ boxRoot.setParentDialog(me.get());
+ boxRoot.setOnLifecycleCallBack(new DialogXBaseRelativeLayout.OnLifecycleCallBack() {
+ @Override
+ public void onShow() {
+ isShow = true;
+ boxRoot.setAlpha(0f);
+ bkg.post(new Runnable() {
+ @Override
+ public void run() {
+ int enterAnimResId = R.anim.anim_dialogx_default_enter;
+ if (overrideEnterAnimRes != 0) {
+ enterAnimResId = overrideEnterAnimRes;
+ }
+ Animation enterAnim = AnimationUtils.loadAnimation(getContext(), enterAnimResId);
+ long enterAnimDurationTemp = enterAnim.getDuration();
+ enterAnim.setInterpolator(new DecelerateInterpolator());
+ if (overrideEnterDuration >= 0) {
+ enterAnimDurationTemp = overrideEnterDuration;
+ }
+ if (enterAnimDuration >= 0) {
+ enterAnimDurationTemp = enterAnimDuration;
+ }
+ enterAnim.setDuration(enterAnimDurationTemp);
+ bkg.startAnimation(enterAnim);
+
+ boxRoot.animate()
+ .setDuration(enterAnimDurationTemp)
+ .alpha(1f)
+ .setInterpolator(new DecelerateInterpolator())
+ .setListener(null);
+
+ getDialogLifecycleCallback().onShow(me());
+ }
+ });
+ }
+
+ @Override
+ public void onDismiss() {
+ isShow = false;
+ dialogImpl = null;
+ getDialogLifecycleCallback().onDismiss(me());
+ me.clear();
+ }
+ });
+
+ if (readyTipType != null) {
+ progressView.noLoading();
+ ((View) progressView).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ showTip(readyTipType);
+ }
+ }, 100);
+ }
+
+ boxRoot.setOnBackPressedListener(new OnBackPressedListener() {
+ @Override
+ public boolean onBackPressed() {
+ if (onBackPressedListener != null && onBackPressedListener.onBackPressed()) {
+ dismiss();
+ return false;
+ }
+ if (isCancelable()) {
+ dismiss();
+ }
+ return false;
+ }
+ });
+ }
+
+ private float oldProgress;
+
+ public void refreshView() {
+ if (style.overrideWaitTipRes() != null) {
+ int overrideBackgroundColorRes = style.overrideWaitTipRes().overrideBackgroundColorRes(isLightTheme());
+ if (overrideBackgroundColorRes == 0) {
+ overrideBackgroundColorRes = isLightTheme() ? R.color.dialogxWaitBkgDark : R.color.dialogxWaitBkgLight;
+ }
+ blurView.setOverlayColor(backgroundColor == -1 ? getResources().getColor(overrideBackgroundColorRes) : backgroundColor);
+ int overrideTextColorRes = style.overrideWaitTipRes().overrideTextColorRes(isLightTheme());
+ if (overrideTextColorRes == 0) {
+ overrideTextColorRes = isLightTheme() ? R.color.white : R.color.black;
+ }
+ txtInfo.setTextColor(getResources().getColor(overrideTextColorRes));
+ progressView.setColor(getResources().getColor(overrideTextColorRes));
+ blurView.setUseBlur(style.overrideWaitTipRes().blurBackground());
+ } else {
+ if (isLightTheme()) {
+ blurView.setOverlayColor(backgroundColor == -1 ? getResources().getColor(R.color.dialogxWaitBkgDark) : backgroundColor);
+ progressView.setColor(Color.WHITE);
+ txtInfo.setTextColor(Color.WHITE);
+ } else {
+ blurView.setOverlayColor(backgroundColor == -1 ? getResources().getColor(R.color.dialogxWaitBkgLight) : backgroundColor);
+ progressView.setColor(Color.BLACK);
+ txtInfo.setTextColor(Color.BLACK);
+ }
+ }
+ if (DialogX.tipProgressColor != -1) progressView.setColor(DialogX.tipProgressColor);
+
+ if (waitProgress >= 0 && waitProgress <= 1 && oldProgress != waitProgress) {
+ progressView.progress(waitProgress);
+ oldProgress = waitProgress;
+ }
+
+ showText(txtInfo, message);
+ useTextInfo(txtInfo, messageTextInfo);
+
+ if (maskColor != -1) boxRoot.setBackgroundColor(maskColor);
+
+ if (onBindView != null && onBindView.getCustomView() != null) {
+ onBindView.bindParent(boxCustomView, me.get());
+ boxCustomView.setVisibility(View.VISIBLE);
+ boxProgress.setVisibility(View.GONE);
+ } else {
+ boxCustomView.setVisibility(View.GONE);
+ boxProgress.setVisibility(View.VISIBLE);
+ }
+ }
+
+ public void doDismiss(final View v) {
+ boxRoot.post(new Runnable() {
+ @Override
+ public void run() {
+ if (v != null) v.setEnabled(false);
+
+ int exitAnimResId = R.anim.anim_dialogx_default_exit;
+ if (overrideExitAnimRes != 0) {
+ exitAnimResId = overrideExitAnimRes;
+ }
+ Animation exitAnim = AnimationUtils.loadAnimation(getContext(), exitAnimResId);
+ long exitAnimDurationTemp = exitAnim.getDuration();
+ if (overrideExitDuration >= 0) {
+ exitAnimDurationTemp = overrideExitDuration;
+ }
+ if (exitAnimDuration != -1) {
+ exitAnimDurationTemp = exitAnimDuration;
+ }
+ exitAnim.setDuration(exitAnimDurationTemp);
+ exitAnim.setInterpolator(new AccelerateInterpolator());
+ bkg.startAnimation(exitAnim);
+
+ boxRoot.animate()
+ .alpha(0f)
+ .setInterpolator(new AccelerateInterpolator())
+ .setDuration(exitAnimDurationTemp);
+
+ new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ dismiss(dialogView);
+ }
+ }, exitAnimDurationTemp);
+ }
+ });
+ }
+
+ public void showTip(final TYPE tip) {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ showType = tip.ordinal();
+ if (progressView == null) return;
+ switch (tip) {
+ case NONE:
+ progressView.loading();
+ return;
+ case SUCCESS:
+ progressView.success();
+ break;
+ case WARNING:
+ progressView.warning();
+ break;
+ case ERROR:
+ progressView.error();
+ break;
+ }
+
+ //此事件是在完成衔接动画绘制后执行的逻辑
+ progressView.whenShowTick(new Runnable() {
+ @Override
+ public void run() {
+ getDialogLifecycleCallback().onShow(WaitDialog.this);
+ refreshView();
+ ((View) progressView).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (showType > -1) {
+ doDismiss(null);
+ }
+ }
+ }, tipShowDuration);
+ }
+ });
+ }
+ });
+ }
+ }
+
+ @Override
+ public String dialogKey() {
+ return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")";
+ }
+
+ @Override
+ public boolean isLightTheme() {
+ if (DialogX.tipTheme == null) {
+ return super.isLightTheme();
+ } else {
+ return DialogX.tipTheme == DialogX.THEME.LIGHT;
+ }
+ }
+
+ public void refreshUI() {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ if (dialogImpl != null) dialogImpl.refreshView();
+ }
+ });
+ }
+
+ public void doDismiss() {
+ if (dialogImpl == null) return;
+ dialogImpl.doDismiss(null);
+ }
+
+ public static void dismiss() {
+ me().doDismiss();
+ }
+
+ protected static WaitDialog me() {
+ if (me == null || me.get() == null) me = new WeakReference<>(new WaitDialog());
+ return me.get();
+ }
+
+ protected TYPE readyTipType;
+
+ protected void showTip(CharSequence message, TYPE type) {
+ showType = type.ordinal();
+ this.message = message;
+ readyTipType = type;
+ show();
+ }
+
+ protected void showTip(Activity activity, CharSequence message, TYPE type) {
+ showType = type.ordinal();
+ this.message = message;
+ readyTipType = type;
+ show(activity);
+ }
+
+ protected void showTip(int messageResId, TYPE type) {
+ showType = type.ordinal();
+ this.message = getString(messageResId);
+ readyTipType = type;
+ show();
+ }
+
+ protected void showTip(Activity activity, int messageResId, TYPE type) {
+ showType = type.ordinal();
+ this.message = getString(messageResId);
+ readyTipType = type;
+ show(activity);
+ }
+
+ public static CharSequence getMessage() {
+ return me().message;
+ }
+
+ public static WaitDialog setMessage(CharSequence message) {
+ me().preMessage(message);
+ me().refreshUI();
+ return me();
+ }
+
+ public static WaitDialog setMessage(int messageResId) {
+ me().preMessage(messageResId);
+ me().refreshUI();
+ return me();
+ }
+
+ public boolean isCancelable() {
+ if (privateCancelable != null) {
+ return privateCancelable == BOOLEAN.TRUE;
+ }
+ if (overrideCancelable != null) {
+ return overrideCancelable == BOOLEAN.TRUE;
+ }
+ return cancelable;
+ }
+
+ public WaitDialog setCancelable(boolean cancelable) {
+ privateCancelable = cancelable ? BOOLEAN.TRUE : BOOLEAN.FALSE;
+ return this;
+ }
+
+ /**
+ * 用于从 WaitDialog 到 TipDialog 的消息设置
+ * 此方法不会立即执行,而是等到动画衔接完成后由事件设置
+ *
+ * @param message 消息
+ * @return me
+ */
+ protected WaitDialog preMessage(CharSequence message) {
+ me().message = message;
+ return me();
+ }
+
+ protected WaitDialog preMessage(int messageResId) {
+ me().message = getString(messageResId);
+ return me();
+ }
+
+ public DialogLifecycleCallback getDialogLifecycleCallback() {
+ return dialogLifecycleCallback == null ? new DialogLifecycleCallback() {
+ } : dialogLifecycleCallback;
+ }
+
+ public WaitDialog setDialogLifecycleCallback(DialogLifecycleCallback dialogLifecycleCallback) {
+ this.dialogLifecycleCallback = dialogLifecycleCallback;
+ if (isShow) dialogLifecycleCallback.onShow(me.get());
+ return this;
+ }
+
+ public DialogImpl getDialogImpl() {
+ return dialogImpl;
+ }
+
+ public WaitDialog setCustomView(OnBindView onBindView) {
+ this.onBindView = onBindView;
+ refreshUI();
+ return this;
+ }
+
+ public View getCustomView() {
+ if (onBindView == null) return null;
+ return onBindView.getCustomView();
+ }
+
+ public WaitDialog removeCustomView() {
+ this.onBindView.clean();
+ refreshUI();
+ return this;
+ }
+
+ public OnBackPressedListener getOnBackPressedListener() {
+ return onBackPressedListener;
+ }
+
+ public WaitDialog setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
+ this.onBackPressedListener = onBackPressedListener;
+ refreshUI();
+ return this;
+ }
+
+ public int getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public WaitDialog setBackgroundColor(@ColorInt int backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ refreshUI();
+ return this;
+ }
+
+ public WaitDialog setBackgroundColorRes(@ColorRes int backgroundColorResId) {
+ this.backgroundColor = getColor(backgroundColorResId);
+ refreshUI();
+ return this;
+ }
+
+ public WaitDialog setMaskColor(@ColorInt int maskColor) {
+ this.maskColor = maskColor;
+ refreshUI();
+ return this;
+ }
+
+ public WaitDialog setEnterAnimDuration(long enterAnimDuration) {
+ this.enterAnimDuration = enterAnimDuration;
+ return this;
+ }
+
+ public long getExitAnimDuration() {
+ return exitAnimDuration;
+ }
+
+ public WaitDialog setExitAnimDuration(long exitAnimDuration) {
+ this.exitAnimDuration = exitAnimDuration;
+ return this;
+ }
+
+ @Override
+ public void onUIModeChange(Configuration newConfig) {
+ refreshUI();
+ }
+
+ public static WaitDialog getInstance() {
+ return me();
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/impl/ActivityLifecycleImpl.java b/DialogX/src/main/java/com/kongzue/dialogx/impl/ActivityLifecycleImpl.java
new file mode 100644
index 0000000..a898b8c
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/impl/ActivityLifecycleImpl.java
@@ -0,0 +1,87 @@
+package com.kongzue.dialogx.impl;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Looper;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.kongzue.dialogx.interfaces.BaseDialog;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/22 11:31
+ */
+public class ActivityLifecycleImpl implements Application.ActivityLifecycleCallbacks {
+
+ private onActivityResumeCallBack onActivityResumeCallBack;
+
+ public ActivityLifecycleImpl(ActivityLifecycleImpl.onActivityResumeCallBack onActivityResumeCallBack) {
+ this.onActivityResumeCallBack = onActivityResumeCallBack;
+ }
+
+ public static void init(Context context, ActivityLifecycleImpl.onActivityResumeCallBack onActivityResumeCallBack) {
+ ((Application) context.getApplicationContext()).registerActivityLifecycleCallbacks(new ActivityLifecycleImpl(onActivityResumeCallBack));
+ }
+
+ @Override
+ public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
+ if (onActivityResumeCallBack != null) {
+ onActivityResumeCallBack.getActivity(activity);
+ }
+ }
+
+ @Override
+ public void onActivityStarted(@NonNull Activity activity) {
+
+ }
+
+ @Override
+ public void onActivityResumed(@NonNull Activity activity) {
+ if (activity.isDestroyed() || activity.isFinishing()) {
+ return;
+ }
+ if (onActivityResumeCallBack != null) {
+ onActivityResumeCallBack.getActivity(activity);
+ }
+ }
+
+ @Override
+ public void onActivityPaused(@NonNull Activity activity) {
+ }
+
+ @Override
+ public void onActivityStopped(@NonNull Activity activity) {
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
+
+ }
+
+ @Override
+ public void onActivityDestroyed(@NonNull Activity activity) {
+ if (BaseDialog.getContext()==activity){
+ BaseDialog.cleanContext();
+ }
+ }
+
+ @Override
+ public void onActivityPreDestroyed(@NonNull final Activity activity) {
+ BaseDialog.recycleDialog(activity);
+ }
+
+ public interface onActivityResumeCallBack {
+ void getActivity(Activity activity);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/impl/AnimatorListenerEndCallBack.java b/DialogX/src/main/java/com/kongzue/dialogx/impl/AnimatorListenerEndCallBack.java
new file mode 100644
index 0000000..c0dc335
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/impl/AnimatorListenerEndCallBack.java
@@ -0,0 +1,30 @@
+package com.kongzue.dialogx.impl;
+
+import android.animation.Animator;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/22 14:37
+ */
+public abstract class AnimatorListenerEndCallBack implements Animator.AnimatorListener {
+ @Override
+ public void onAnimationStart(Animator animation) {
+
+ }
+
+ @Override
+ public abstract void onAnimationEnd(Animator animation);
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/BaseDialog.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/BaseDialog.java
new file mode 100644
index 0000000..fda8d9f
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/BaseDialog.java
@@ -0,0 +1,365 @@
+package com.kongzue.dialogx.interfaces;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.ColorRes;
+import androidx.appcompat.app.AppCompatDelegate;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.dialogs.PopTip;
+import com.kongzue.dialogx.impl.ActivityLifecycleImpl;
+import com.kongzue.dialogx.util.TextInfo;
+import com.kongzue.dialogx.util.WindowUtil;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import static com.kongzue.dialogx.DialogX.DEBUGMODE;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/22 14:10
+ */
+public abstract class BaseDialog {
+
+ private static WeakReference rootFrameLayout;
+ private static WeakReference contextWeakReference;
+ protected WeakReference ownActivity;
+ private static List runningDialogList;
+ private WeakReference dialogView;
+
+ public static void init(Context context) {
+ if (context instanceof Activity) {
+ initActivityContext((Activity) context);
+ }
+ ActivityLifecycleImpl.init(context, new ActivityLifecycleImpl.onActivityResumeCallBack() {
+ @Override
+ public void getActivity(Activity activity) {
+ initActivityContext(activity);
+ }
+ });
+ }
+
+ private static void initActivityContext(Activity activity) {
+ try {
+ contextWeakReference = new WeakReference<>(activity);
+ rootFrameLayout = new WeakReference<>((FrameLayout) activity.getWindow().getDecorView());
+ } catch (Exception e) {
+ error("DialogX.init: 初始化异常,找不到Activity的根布局");
+ }
+ }
+
+ protected static void log(Object o) {
+ if (DEBUGMODE) Log.i(">>>", o.toString());
+ }
+
+ protected static void error(Object o) {
+ if (DEBUGMODE) Log.e(">>>", o.toString());
+ }
+
+ public abstract void onUIModeChange(Configuration newConfig);
+
+ protected static void show(final View view) {
+ if (view == null) return;
+ final BaseDialog baseDialog = (BaseDialog) view.getTag();
+ baseDialog.ownActivity = new WeakReference<>(contextWeakReference.get());
+ baseDialog.dialogView = new WeakReference<>(view);
+
+ log(baseDialog.dialogKey() + ".show");
+ addDialogToRunningList(baseDialog);
+ if (DialogX.implIMPLMode == DialogX.IMPL_MODE.VIEW) {
+ if (rootFrameLayout == null || rootFrameLayout.get() == null) return;
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ rootFrameLayout.get().addView(view);
+ }
+ });
+ } else {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ WindowUtil.show(contextWeakReference.get(), view, !(baseDialog instanceof PopTip));
+ }
+ });
+ }
+ }
+
+ protected static void show(final Activity activity, final View view) {
+ if (activity == null || view == null) return;
+ if (activity.isDestroyed()) {
+ error(((BaseDialog) view.getTag()).dialogKey() + ".show ERROR: activity is Destroyed.");
+ return;
+ }
+ final BaseDialog baseDialog = (BaseDialog) view.getTag();
+ baseDialog.ownActivity = new WeakReference<>(activity);
+ baseDialog.dialogView = new WeakReference<>(view);
+
+ log(baseDialog + ".show");
+ addDialogToRunningList(baseDialog);
+ if (DialogX.implIMPLMode == DialogX.IMPL_MODE.VIEW) {
+ final FrameLayout activityRootView = (FrameLayout) activity.getWindow().getDecorView();
+ if (activityRootView == null) {
+ return;
+ }
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ activityRootView.addView(view);
+ }
+ });
+ } else {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ WindowUtil.show(activity, view, !(baseDialog instanceof PopTip));
+ }
+ });
+ }
+ }
+
+ protected static void dismiss(final View dialogView) {
+ if (dialogView == null) return;
+ final BaseDialog baseDialog = (BaseDialog) dialogView.getTag();
+ log(baseDialog.dialogKey() + ".dismiss");
+ removeDialogToRunningList(baseDialog);
+ if (baseDialog.dialogView != null) baseDialog.dialogView.clear();
+ if (DialogX.implIMPLMode == DialogX.IMPL_MODE.VIEW) {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ if (dialogView.getParent() == null || !(dialogView.getParent() instanceof ViewGroup)) {
+ if (rootFrameLayout == null) return;
+ rootFrameLayout.get().removeView(dialogView);
+ } else {
+ ((ViewGroup) dialogView.getParent()).removeView(dialogView);
+ }
+ }
+ });
+ } else {
+ runOnMain(new Runnable() {
+ @Override
+ public void run() {
+ WindowUtil.dismiss(dialogView);
+ }
+ });
+ }
+ }
+
+ private static void addDialogToRunningList(BaseDialog baseDialog) {
+ if (runningDialogList == null) runningDialogList = new ArrayList<>();
+ runningDialogList.add(baseDialog);
+ }
+
+ private static void removeDialogToRunningList(BaseDialog baseDialog) {
+ if (runningDialogList != null) runningDialogList.remove(baseDialog);
+ }
+
+ public static Context getContext() {
+ if (contextWeakReference == null) return null;
+ return contextWeakReference.get();
+ }
+
+ public static void cleanContext() {
+ contextWeakReference.clear();
+ contextWeakReference = null;
+ System.gc();
+ }
+
+ protected boolean cancelable = true;
+ protected OnBackPressedListener onBackPressedListener;
+ protected boolean isShow;
+ protected DialogXStyle style;
+ protected DialogX.THEME theme;
+ protected boolean autoShowInputKeyboard;
+ protected int backgroundColor = -1;
+ protected long enterAnimDuration = -1;
+ protected long exitAnimDuration = -1;
+
+ public BaseDialog() {
+ cancelable = DialogX.cancelable;
+ style = DialogX.globalStyle;
+ theme = DialogX.globalTheme;
+ enterAnimDuration = DialogX.enterAnimDuration;
+ exitAnimDuration = DialogX.exitAnimDuration;
+ autoShowInputKeyboard = DialogX.autoShowInputKeyboard;
+ }
+
+ public View createView(int layoutId) {
+ return LayoutInflater.from(getContext()).inflate(layoutId, null);
+ }
+
+ public boolean isShow() {
+ return isShow;
+ }
+
+ public DialogXStyle getStyle() {
+ return style;
+ }
+
+ public DialogX.THEME getTheme() {
+ return theme;
+ }
+
+ protected void useTextInfo(TextView textView, TextInfo textInfo) {
+ if (textInfo == null) return;
+ if (textView == null) return;
+ if (textInfo.getFontSize() > 0) {
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textInfo.getFontSize());
+ }
+ if (textInfo.getFontColor() != 1) {
+ textView.setTextColor(textInfo.getFontColor());
+ }
+ if (textInfo.getGravity() != -1) {
+ textView.setGravity(textInfo.getGravity());
+ }
+ textView.getPaint().setFakeBoldText(textInfo.isBold());
+ }
+
+ protected void showText(TextView textView, CharSequence text) {
+ if (textView == null) return;
+ if (isNull(text)) {
+ textView.setVisibility(View.GONE);
+ textView.setText("");
+ } else {
+ textView.setVisibility(View.VISIBLE);
+ textView.setText(text);
+ }
+ }
+
+ protected View createHorizontalSplitView(int color) {
+ View splitView = new View(getContext());
+ splitView.setBackgroundColor(color);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1);
+ splitView.setLayoutParams(lp);
+ return splitView;
+ }
+
+ protected View createVerticalSplitView(int color, int height) {
+ View splitView = new View(getContext());
+ splitView.setBackgroundColor(color);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(1, dip2px(height));
+ splitView.setLayoutParams(lp);
+ return splitView;
+ }
+
+ public static boolean isNull(String s) {
+ if (s == null || s.trim().isEmpty() || "null".equals(s) || "(null)".equals(s)) {
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean isNull(CharSequence c) {
+ String s = String.valueOf(c);
+ if (c == null || s.trim().isEmpty() || "null".equals(s) || "(null)".equals(s)) {
+ return true;
+ }
+ return false;
+ }
+
+ public Resources getResources() {
+ if (getContext() == null) return Resources.getSystem();
+ return getContext().getResources();
+ }
+
+ public int dip2px(float dpValue) {
+ final float scale = getContext().getResources().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+
+ public boolean isLightTheme() {
+ if (theme == DialogX.THEME.AUTO) {
+ return (getContext().getApplicationContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_NO;
+ }
+ return theme == DialogX.THEME.LIGHT;
+ }
+
+ public static FrameLayout getRootFrameLayout() {
+ if (rootFrameLayout == null) return null;
+ return rootFrameLayout.get();
+ }
+
+ public void tintColor(View view, int color) {
+ view.setBackgroundTintList(ColorStateList.valueOf(color));
+ }
+
+ protected void beforeShow() {
+ if (getContext() == null) {
+ error("DialogX 未初始化。\n请检查是否在启动对话框前进行初始化操作,使用以下代码进行初始化:\nDialogX.init(context);\n\n另外建议您前往查看 DialogX 的文档进行使用:https://github.com/kongzue/DialogX");
+ }
+ if (style.styleVer != DialogXStyle.styleVer) {
+ error("DialogX 所引用的 Style 不符合当前适用版本:" + DialogXStyle.styleVer + " 引入的 Style(" + style.getClass().getSimpleName() + ") 版本" + style.styleVer);
+ }
+ }
+
+ protected String getString(int titleResId) {
+ if (getContext() == null) {
+ error("DialogX 未初始化。\n请检查是否在启动对话框前进行初始化操作,使用以下代码进行初始化:\nDialogX.init(context);\n\n另外建议您前往查看 DialogX 的文档进行使用:https://github.com/kongzue/DialogX");
+ return null;
+ }
+ return getContext().getString(titleResId);
+ }
+
+ protected int getColor(int backgroundRes) {
+ if (getContext() == null) {
+ error("DialogX 未初始化。\n请检查是否在启动对话框前进行初始化操作,使用以下代码进行初始化:\nDialogX.init(context);\n\n另外建议您前往查看 DialogX 的文档进行使用:https://github.com/kongzue/DialogX");
+ return Color.BLACK;
+ }
+ return getResources().getColor(backgroundRes);
+ }
+
+ public enum BOOLEAN {
+ TRUE, FALSE
+ }
+
+ public abstract String dialogKey();
+
+ protected static void runOnMain(Runnable runnable) {
+ if (!DialogX.autoRunOnUIThread) runnable.run();
+ new Handler(Looper.getMainLooper()).post(runnable);
+ }
+
+ public Activity getActivity() {
+ return ownActivity == null ? null : ownActivity.get();
+ }
+
+ protected void cleanActivityContext() {
+ if (ownActivity != null) ownActivity.clear();
+ }
+
+ public static void recycleDialog(Activity activity) {
+ if (DialogX.implIMPLMode == DialogX.IMPL_MODE.WINDOW) {
+ if (runningDialogList != null) {
+ CopyOnWriteArrayList copyOnWriteList = new CopyOnWriteArrayList<>(runningDialogList);
+ for (BaseDialog baseDialog : copyOnWriteList) {
+ if (baseDialog.getActivity() == activity && baseDialog.dialogView != null) {
+ WindowUtil.dismiss(baseDialog.dialogView.get());
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/BaseOnDialogClickCallback.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/BaseOnDialogClickCallback.java
new file mode 100644
index 0000000..c39d368
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/BaseOnDialogClickCallback.java
@@ -0,0 +1,11 @@
+package com.kongzue.dialogx.interfaces;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/22 15:07
+ */
+public interface BaseOnDialogClickCallback {
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/BottomMenuListViewTouchEvent.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/BottomMenuListViewTouchEvent.java
new file mode 100644
index 0000000..3471e29
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/BottomMenuListViewTouchEvent.java
@@ -0,0 +1,17 @@
+package com.kongzue.dialogx.interfaces;
+
+import android.view.MotionEvent;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/11/18 15:01
+ */
+public abstract class BottomMenuListViewTouchEvent {
+
+ public void down(MotionEvent event){};
+ public void move(MotionEvent event){};
+ public void up(MotionEvent event){};
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/DialogConvertViewInterface.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/DialogConvertViewInterface.java
new file mode 100644
index 0000000..1ea5c70
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/DialogConvertViewInterface.java
@@ -0,0 +1,19 @@
+package com.kongzue.dialogx.interfaces;
+
+import android.view.View;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/6 15:52
+ */
+public interface DialogConvertViewInterface {
+
+ void init();
+
+ void refreshView();
+
+ void doDismiss(View v);
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/DialogLifecycleCallback.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/DialogLifecycleCallback.java
new file mode 100644
index 0000000..eaec9e3
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/DialogLifecycleCallback.java
@@ -0,0 +1,19 @@
+package com.kongzue.dialogx.interfaces;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/22 14:09
+ */
+public abstract class DialogLifecycleCallback {
+
+ public void onShow(T dialog){
+
+ }
+
+ public void onDismiss(T dialog){
+
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnBackPressedListener.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnBackPressedListener.java
new file mode 100644
index 0000000..997b615
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnBackPressedListener.java
@@ -0,0 +1,12 @@
+package com.kongzue.dialogx.interfaces;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/25 15:48
+ */
+public interface OnBackPressedListener {
+ boolean onBackPressed();
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnBindView.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnBindView.java
new file mode 100644
index 0000000..fda1a74
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnBindView.java
@@ -0,0 +1,93 @@
+package com.kongzue.dialogx.interfaces;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+import com.kongzue.dialogx.DialogX;
+
+import static com.kongzue.dialogx.DialogX.ERROR_INIT_TIPS;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/8 17:00
+ */
+public abstract class OnBindView {
+ int layoutResId;
+ View customView;
+
+ public OnBindView(int layoutResId) {
+ if (BaseDialog.getContext() == null) {
+ DialogX.error(ERROR_INIT_TIPS);
+ return;
+ }
+ this.layoutResId = layoutResId;
+ customView = LayoutInflater.from(BaseDialog.getContext()).inflate(layoutResId, new RelativeLayout(BaseDialog.getContext()), false);
+ }
+
+ public OnBindView(View customView) {
+ this.customView = customView;
+ }
+
+ public abstract void onBind(D dialog, View v);
+
+ public int getLayoutResId() {
+ return layoutResId;
+ }
+
+ public OnBindView setLayoutResId(int layoutResId) {
+ this.layoutResId = layoutResId;
+ return this;
+ }
+
+ public View getCustomView() {
+ return customView;
+ }
+
+ public OnBindView setCustomView(View customView) {
+ this.customView = customView;
+ return this;
+ }
+
+ public void clean() {
+ layoutResId = 0;
+ customView = null;
+ }
+
+ public OnBindView bindParent(ViewGroup parentView) {
+ if (customView == null) return this;
+ if (customView.getParent() != null) {
+ if (customView.getParent()==parentView){
+ return this;
+ }
+ ((ViewGroup) customView.getParent()).removeView(customView);
+ }
+ ViewGroup.LayoutParams lp = parentView.getLayoutParams();
+ if (lp == null) {
+ lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+ parentView.addView(customView, lp);
+ return this;
+ }
+
+ public OnBindView bindParent(ViewGroup parentView, BaseDialog dialog) {
+ if (customView == null) return this;
+ if (customView.getParent() != null) {
+ if (customView.getParent()==parentView){
+ return this;
+ }
+ ((ViewGroup) customView.getParent()).removeView(customView);
+ }
+ ViewGroup.LayoutParams lp = customView.getLayoutParams();
+ if (lp == null) {
+ lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+ parentView.addView(customView, lp);
+ onBind((D) dialog, customView);
+ return this;
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnDialogButtonClickListener.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnDialogButtonClickListener.java
new file mode 100644
index 0000000..09896c9
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnDialogButtonClickListener.java
@@ -0,0 +1,16 @@
+package com.kongzue.dialogx.interfaces;
+
+import android.view.View;
+
+/**
+ * Author: @Kongzue
+ * Github: https://github.com/kongzue/
+ * Homepage: http://kongzue.com/
+ * Mail: myzcxhh@live.cn
+ * CreateTime: 2019/3/29 18:44
+ */
+public interface OnDialogButtonClickListener extends BaseOnDialogClickCallback{
+
+ boolean onClick(D baseDialog, View v);
+
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnIconChangeCallBack.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnIconChangeCallBack.java
new file mode 100644
index 0000000..6dfd630
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnIconChangeCallBack.java
@@ -0,0 +1,28 @@
+package com.kongzue.dialogx.interfaces;
+
+import com.kongzue.dialogx.dialogs.BottomMenu;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/9 14:54
+ */
+public abstract class OnIconChangeCallBack {
+
+ private boolean autoTintIconInLightOrDarkMode;
+
+ public OnIconChangeCallBack() {
+ }
+
+ public OnIconChangeCallBack(boolean autoTintIconInLightOrDarkMode) {
+ this.autoTintIconInLightOrDarkMode = autoTintIconInLightOrDarkMode;
+ }
+
+ public abstract int getIcon(BottomMenu bottomMenu, int index, String menuText);
+
+ public boolean isAutoTintIconInLightOrDarkMode() {
+ return autoTintIconInLightOrDarkMode;
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnInputDialogButtonClickListener.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnInputDialogButtonClickListener.java
new file mode 100644
index 0000000..5567dc0
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnInputDialogButtonClickListener.java
@@ -0,0 +1,17 @@
+package com.kongzue.dialogx.interfaces;
+
+import android.view.View;
+
+import com.kongzue.dialogx.dialogs.MessageDialog;
+
+/**
+ * Author: @Kongzue
+ * Github: https://github.com/kongzue/
+ * Homepage: http://kongzue.com/
+ * Mail: myzcxhh@live.cn
+ * CreateTime: 2019/4/8 21:09
+ */
+public interface OnInputDialogButtonClickListener extends BaseOnDialogClickCallback{
+
+ boolean onClick(D baseDialog, View v, String inputStr);
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnMenuItemClickListener.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnMenuItemClickListener.java
new file mode 100644
index 0000000..2edb4a8
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnMenuItemClickListener.java
@@ -0,0 +1,12 @@
+package com.kongzue.dialogx.interfaces;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/10 6:26
+ */
+public interface OnMenuItemClickListener {
+ boolean onClick(D dialog, CharSequence text, int which);
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnMenuItemSelectListener.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnMenuItemSelectListener.java
new file mode 100644
index 0000000..855c1bf
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnMenuItemSelectListener.java
@@ -0,0 +1,37 @@
+package com.kongzue.dialogx.interfaces;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2021/4/11 19:18
+ */
+public abstract class OnMenuItemSelectListener implements OnMenuItemClickListener {
+
+ /**
+ * 警告:不建议重写此方法!
+ * 如果选择使用 OnMenuItemSelectListener 作为 BottomMenu 的回调,那么点击 Item 后,菜单默认不应该关闭,
+ * 若选择自行处理菜单点击 onClick,那么请务必 return true 作为返回值,
+ * 否则不会处理 onOneItemSelect 或 onMultiItemSelect 事件。
+ *
+ * @param dialog BottomMenu实例
+ * @param text 菜单文本
+ * @param index 菜单索引值
+ * @return return true:拦截自动关闭对话框;return false:点击后关闭对话框
+ */
+ @Deprecated
+ @Override
+ public boolean onClick(D dialog, CharSequence text, int index) {
+ return true;
+ }
+
+ public void onOneItemSelect(D dialog, CharSequence text, int which) {
+
+ }
+
+ public void onMultiItemSelect(D dialog, CharSequence[] text, int[] indexArray) {
+
+ }
+
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnSafeInsetsChangeListener.java b/DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnSafeInsetsChangeListener.java
new file mode 100644
index 0000000..e0fda15
--- /dev/null
+++ b/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);
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/style/MaterialStyle.java b/DialogX/src/main/java/com/kongzue/dialogx/style/MaterialStyle.java
new file mode 100644
index 0000000..f9aee1e
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/style/MaterialStyle.java
@@ -0,0 +1,225 @@
+package com.kongzue.dialogx.style;
+
+import android.content.Context;
+
+import com.kongzue.dialogx.R;
+import com.kongzue.dialogx.interfaces.DialogXStyle;
+import com.kongzue.dialogx.interfaces.ProgressViewInterface;
+import com.kongzue.dialogx.util.views.ProgressView;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/26 13:09
+ */
+public class MaterialStyle implements DialogXStyle {
+
+ public static MaterialStyle style() {
+ return new MaterialStyle();
+ }
+
+ @Override
+ public int layout(boolean light) {
+ return light ? R.layout.layout_dialogx_material : R.layout.layout_dialogx_material_dark;
+ }
+
+ @Override
+ public int enterAnimResId() {
+ return R.anim.anim_dialogx_default_enter;
+ }
+
+ @Override
+ public int exitAnimResId() {
+ return R.anim.anim_dialogx_default_exit;
+ }
+
+ @Override
+ public int[] verticalButtonOrder() {
+ return new int[]{BUTTON_OK, BUTTON_OTHER, BUTTON_CANCEL};
+ }
+
+ @Override
+ public int[] horizontalButtonOrder() {
+ return new int[]{BUTTON_OTHER, SPACE, BUTTON_CANCEL, BUTTON_OK};
+ }
+
+ @Override
+ public int splitWidthPx() {
+ return 1;
+ }
+
+ @Override
+ public int splitColorRes(boolean light) {
+ return 0;
+ }
+
+ @Override
+ public BlurBackgroundSetting messageDialogBlurSettings() {
+ return null;
+ }
+
+ @Override
+ public HorizontalButtonRes overrideHorizontalButtonRes() {
+ return new HorizontalButtonRes() {
+ @Override
+ public int overrideHorizontalOkButtonBackgroundRes(int visibleButtonCount, boolean light) {
+ return light ? R.drawable.button_dialogx_material_light : R.drawable.button_dialogx_material_night;
+ }
+
+ @Override
+ public int overrideHorizontalCancelButtonBackgroundRes(int visibleButtonCount, boolean light) {
+ return light ? R.drawable.button_dialogx_material_light : R.drawable.button_dialogx_material_night;
+ }
+
+ @Override
+ public int overrideHorizontalOtherButtonBackgroundRes(int visibleButtonCount, boolean light) {
+ return light ? R.drawable.button_dialogx_material_light : R.drawable.button_dialogx_material_night;
+ }
+ };
+ }
+
+ @Override
+ public VerticalButtonRes overrideVerticalButtonRes() {
+ return new VerticalButtonRes() {
+ @Override
+ public int overrideVerticalOkButtonBackgroundRes(int visibleButtonCount, boolean light) {
+ return light ? R.drawable.button_dialogx_material_light : R.drawable.button_dialogx_material_night;
+ }
+
+ @Override
+ public int overrideVerticalCancelButtonBackgroundRes(int visibleButtonCount, boolean light) {
+ return light ? R.drawable.button_dialogx_material_light : R.drawable.button_dialogx_material_night;
+ }
+
+ @Override
+ public int overrideVerticalOtherButtonBackgroundRes(int visibleButtonCount, boolean light) {
+ return light ? R.drawable.button_dialogx_material_light : R.drawable.button_dialogx_material_night;
+ }
+ };
+ }
+
+ @Override
+ public WaitTipRes overrideWaitTipRes() {
+ return new WaitTipRes() {
+ @Override
+ public int overrideWaitLayout(boolean light) {
+ return R.layout.layout_dialogx_wait;
+ }
+
+ @Override
+ public int overrideRadiusPx() {
+ return -1;
+ }
+
+ @Override
+ public boolean blurBackground() {
+ return false;
+ }
+
+ @Override
+ public int overrideBackgroundColorRes(boolean light) {
+ return 0;
+ }
+
+ @Override
+ public int overrideTextColorRes(boolean light) {
+ return light ? R.color.white : R.color.black;
+ }
+
+ @Override
+ public ProgressViewInterface overrideWaitView(Context context, boolean light) {
+ return new ProgressView(context);
+ }
+ };
+ }
+
+ @Override
+ public BottomDialogRes overrideBottomDialogRes() {
+ return new BottomDialogRes() {
+
+ @Override
+ public boolean touchSlide() {
+ return true;
+ }
+
+ @Override
+ public int overrideDialogLayout(boolean light) {
+ return light ? R.layout.layout_dialogx_bottom_material : R.layout.layout_dialogx_bottom_material_dark;
+ }
+
+ @Override
+ public int overrideMenuDividerDrawableRes(boolean light) {
+ return light ? R.drawable.rect_dialogx_material_menu_split_divider : R.drawable.rect_dialogx_material_menu_split_divider_night;
+ }
+
+ @Override
+ public int overrideMenuDividerHeight(boolean light) {
+ return 1;
+ }
+
+ @Override
+ public int overrideMenuTextColor(boolean light) {
+ return light ? R.color.black90 : R.color.white90;
+ }
+
+ @Override
+ public float overrideBottomDialogMaxHeight() {
+ return 0.6f;
+ }
+
+ @Override
+ public int overrideMenuItemLayout(boolean light, int index, int count, boolean isContentVisibility) {
+ return 0;
+ }
+
+ @Override
+ public int overrideSelectionMenuBackgroundColor(boolean light) {
+ return 0;
+ }
+
+ @Override
+ public boolean selectionImageTint(boolean light) {
+ return false;
+ }
+
+ @Override
+ public int overrideSelectionImage(boolean light, boolean isSelected) {
+ return isSelected ? R.mipmap.img_dialogx_bottom_menu_material_item_selection : R.mipmap.img_dialogx_bottom_menu_material_item_non_select;
+ }
+
+ @Override
+ public int overrideMultiSelectionImage(boolean light, boolean isSelected) {
+ return isSelected ? R.mipmap.img_dialogx_bottom_menu_material_item_multi_selection : R.mipmap.img_dialogx_bottom_menu_material_item_non_multi_select;
+ }
+
+ };
+ }
+
+ @Override
+ public PopTipSettings popTipSettings() {
+ return new PopTipSettings() {
+ @Override
+ public int layout(boolean light) {
+ return light ? R.layout.layout_dialogx_poptip_material : R.layout.layout_dialogx_poptip_material_dark;
+ }
+
+ @Override
+ public ALIGN align() {
+ return ALIGN.BOTTOM;
+ }
+
+ @Override
+ public int enterAnimResId(boolean light) {
+ return R.anim.anim_dialogx_default_enter;
+ }
+
+ @Override
+ public int exitAnimResId(boolean light) {
+ return R.anim.anim_dialogx_default_exit;
+ }
+ };
+ }
+
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/BottomDialogTouchEventInterceptor.java b/DialogX/src/main/java/com/kongzue/dialogx/util/BottomDialogTouchEventInterceptor.java
new file mode 100644
index 0000000..1ce5f56
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/BottomDialogTouchEventInterceptor.java
@@ -0,0 +1,145 @@
+package com.kongzue.dialogx.util;
+
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+
+import com.kongzue.dialogx.dialogs.BottomDialog;
+import com.kongzue.dialogx.interfaces.DialogConvertViewInterface;
+import com.kongzue.dialogx.util.views.BottomDialogScrollView;
+import com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/7 4:01
+ */
+public class BottomDialogTouchEventInterceptor {
+
+ /**
+ * 下边三个值用于判断触控过程,
+ * isBkgTouched:标记是否已按下
+ * bkgTouchDownY:记录起始触控位置
+ * scrolledY:记录 ScrollView 已滚动过的距离,下次触控事件将接着上次的位置继续滑动
+ * bkgOldY:记录按下时 bkg 的位置,用于区分松开手指时,bkg 移动的方向。
+ */
+ private boolean isBkgTouched = false;
+ private float bkgTouchDownY;
+ private float scrolledY;
+ private float bkgOldY;
+ /**
+ * 0:bkg接收触控事件,-1:scrollView进行滚动
+ * 此标记的意义在于,当从 [scrollView滚动] 与 [bkg接收触控事件] 状态切换时,
+ * 需要对bkgTouchDownY、scrolledY的值进行刷新,否则触控连续过程会出现闪跳。
+ */
+ private int oldMode;
+
+ public BottomDialogTouchEventInterceptor(BottomDialog me, BottomDialog.DialogImpl impl) {
+ refresh(me, impl);
+ }
+
+ public void refresh(final BottomDialog me, final BottomDialog.DialogImpl impl) {
+ if (me == null || impl == null || impl.bkg == null || impl.scrollView == null) {
+ return;
+ }
+ /**
+ * BottomDialog 触控事件说明:
+ * bkg 将拦截并接管所有触控操作。
+ * BottomDialog 的启动方式依据是内容布局高度是否大于可显示安全区域的高度。
+ * bkg 会在合适的时机,直接接管控制 ScrollView 的滚动。
+ * 因此,请确保内容布局的高度计算方式一定是按照内容高度计算,
+ * 即,请重写 onMeasure 方法:
+ * @Override
+ * protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ * int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
+ * super.onMeasure(widthMeasureSpec, expandSpec);
+ * }
+ */
+ if (me.isAllowInterceptTouch()) {
+ impl.bkg.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ //这里 return 什么实际上无关紧要,重点在于 MaxRelativeLayout.java(dispatchTouchEvent:184) 的事件分发会独立触发此处的额外滑动事件
+ 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 (impl.bkg.isChildScrollViewCanScroll()) {
+ if (aimY > 0) {
+ if (impl.scrollView.getScrollY() == 0) {
+ if (impl.scrollView instanceof BottomDialogScrollView) {
+ ((BottomDialogScrollView) impl.scrollView).lockScroll(true);
+ }
+ impl.bkg.setY(aimY);
+ } else {
+ bkgTouchDownY = event.getY();
+ }
+ } else {
+ if (impl.scrollView instanceof BottomDialogScrollView) {
+ ((BottomDialogScrollView) impl.scrollView).lockScroll(false);
+ }
+ impl.bkg.setY(0);
+ }
+ } else {
+ if (aimY > impl.bkgEnterAimY) {
+ impl.bkg.setY(aimY);
+ } else {
+ impl.bkg.setY(impl.bkgEnterAimY);
+ }
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ scrolledY = impl.scrollView.getScrollY();
+ 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 false;
+ }
+ });
+ } else {
+ impl.bkg.setOnTouchListener(null);
+ }
+ }
+
+ private int dip2px(float dpValue) {
+ final float scale = Resources.getSystem().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/FullScreenDialogTouchEventInterceptor.java b/DialogX/src/main/java/com/kongzue/dialogx/util/FullScreenDialogTouchEventInterceptor.java
new file mode 100644
index 0000000..0f982dd
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/IOSMenuArrayAdapter.java b/DialogX/src/main/java/com/kongzue/dialogx/util/IOSMenuArrayAdapter.java
new file mode 100644
index 0000000..1c38896
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/IOSMenuArrayAdapter.java
@@ -0,0 +1,19 @@
+package com.kongzue.dialogx.util;
+
+import android.content.Context;
+import android.widget.ArrayAdapter;
+
+import androidx.annotation.NonNull;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/10 19:56
+ */
+public class IOSMenuArrayAdapter extends ArrayAdapter {
+ public IOSMenuArrayAdapter(@NonNull Context context, int resource) {
+ super(context, resource);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/InputInfo.java b/DialogX/src/main/java/com/kongzue/dialogx/util/InputInfo.java
new file mode 100644
index 0000000..f2cd457
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/InputInfo.java
@@ -0,0 +1,62 @@
+package com.kongzue.dialogx.util;
+
+/**
+ * Author: @Kongzue
+ * Github: https://github.com/kongzue/
+ * Homepage: http://kongzue.com/
+ * Mail: myzcxhh@live.cn
+ * CreateTime: 2018/11/8 21:41
+ */
+public class InputInfo {
+
+ private int MAX_LENGTH = -1; //最大长度,-1不生效
+ private int inputType; //类型详见 android.text.InputType
+ private TextInfo textInfo; //默认字体样式
+ private boolean multipleLines; //支持多行
+ private boolean selectAllText; //默认选中所有文字(便于修改)
+
+ public int getMAX_LENGTH() {
+ return MAX_LENGTH;
+ }
+
+ public InputInfo setMAX_LENGTH(int MAX_LENGTH) {
+ this.MAX_LENGTH = MAX_LENGTH;
+ return this;
+ }
+
+ public int getInputType() {
+ return inputType;
+ }
+
+ public InputInfo setInputType(int inputType) {
+ this.inputType = inputType;
+ return this;
+ }
+
+ public TextInfo getTextInfo() {
+ return textInfo;
+ }
+
+ public InputInfo setTextInfo(TextInfo textInfo) {
+ this.textInfo = textInfo;
+ return this;
+ }
+
+ public boolean isMultipleLines() {
+ return multipleLines;
+ }
+
+ public InputInfo setMultipleLines(boolean multipleLines) {
+ this.multipleLines = multipleLines;
+ return this;
+ }
+
+ public boolean isSelectAllText() {
+ return selectAllText;
+ }
+
+ public InputInfo setSelectAllText(boolean selectAllText) {
+ this.selectAllText = selectAllText;
+ return this;
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/NormalMenuArrayAdapter.java b/DialogX/src/main/java/com/kongzue/dialogx/util/NormalMenuArrayAdapter.java
new file mode 100644
index 0000000..c7aa364
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/NormalMenuArrayAdapter.java
@@ -0,0 +1,213 @@
+package com.kongzue.dialogx.util;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Typeface;
+import android.graphics.drawable.StateListDrawable;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.SimpleAdapter;
+import android.widget.TextView;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.R;
+import com.kongzue.dialogx.dialogs.BottomMenu;
+
+import java.util.List;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/7 0:00
+ */
+public class NormalMenuArrayAdapter extends BaseAdapter {
+
+ private BottomMenu bottomMenu;
+ public List objects;
+ public Context context;
+
+ public NormalMenuArrayAdapter(BottomMenu bottomMenu, Context context, List objects) {
+ this.objects = objects;
+ this.context = context;
+ this.bottomMenu = bottomMenu;
+ }
+
+ class ViewHolder {
+ ImageView imgDialogxMenuIcon;
+ TextView txtDialogxMenuText;
+ ImageView imgDialogxMenuSelection;
+ }
+
+ @Override
+ public int getCount() {
+ return objects.size();
+ }
+
+ @Override
+ public CharSequence getItem(int position) {
+ return objects.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder viewHolder = null;
+ if (convertView == null) {
+ viewHolder = new ViewHolder();
+ LayoutInflater mInflater = LayoutInflater.from(context);
+
+ int resourceId = R.layout.item_dialogx_material_bottom_menu_normal_text;
+ if (bottomMenu.getStyle().overrideBottomDialogRes() != null) {
+ resourceId = bottomMenu.getStyle().overrideBottomDialogRes().overrideMenuItemLayout(bottomMenu.isLightTheme(), position, getCount(), false);
+ if (resourceId == 0) {
+ resourceId = R.layout.item_dialogx_material_bottom_menu_normal_text;
+ } else {
+ if (bottomMenu.getDialogImpl().txtDialogTitle.getVisibility() == View.VISIBLE ||
+ bottomMenu.getDialogImpl().txtDialogTip.getVisibility() == View.VISIBLE ||
+ bottomMenu.getCustomView() != null) {
+ if (position == 0) {
+ resourceId = bottomMenu.getStyle().overrideBottomDialogRes().overrideMenuItemLayout(bottomMenu.isLightTheme(), position, getCount(), true);
+ }
+ }
+ }
+ }
+ convertView = mInflater.inflate(resourceId, null);
+
+ viewHolder.imgDialogxMenuIcon = convertView.findViewById(R.id.img_dialogx_menu_icon);
+ viewHolder.txtDialogxMenuText = convertView.findViewById(R.id.txt_dialogx_menu_text);
+ viewHolder.imgDialogxMenuSelection = convertView.findViewById(R.id.img_dialogx_menu_selection);
+
+ convertView.setTag(viewHolder);
+ } else {
+ viewHolder = (ViewHolder) convertView.getTag();
+ }
+ if (bottomMenu.getSelectMode() == BottomMenu.SELECT_MODE.SINGLE) {
+ if (viewHolder.imgDialogxMenuSelection != null) {
+ if (bottomMenu.getSelection() == position) {
+ viewHolder.imgDialogxMenuSelection.setVisibility(View.VISIBLE);
+ int overrideSelectionImageResId = bottomMenu.getStyle().overrideBottomDialogRes().overrideSelectionImage(bottomMenu.isLightTheme(), true);
+ if (overrideSelectionImageResId != 0) {
+ viewHolder.imgDialogxMenuSelection.setImageResource(overrideSelectionImageResId);
+ }
+ } else {
+ int overrideSelectionImageResId = bottomMenu.getStyle().overrideBottomDialogRes().overrideSelectionImage(bottomMenu.isLightTheme(), false);
+ if (overrideSelectionImageResId != 0) {
+ viewHolder.imgDialogxMenuSelection.setVisibility(View.VISIBLE);
+ viewHolder.imgDialogxMenuSelection.setImageResource(overrideSelectionImageResId);
+ } else {
+ viewHolder.imgDialogxMenuSelection.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+ } else if (bottomMenu.getSelectMode() == BottomMenu.SELECT_MODE.MULTIPLE) {
+ if (viewHolder.imgDialogxMenuSelection != null) {
+ if (bottomMenu.getSelectionList().contains(position)) {
+ viewHolder.imgDialogxMenuSelection.setVisibility(View.VISIBLE);
+ int overrideSelectionImageResId = bottomMenu.getStyle().overrideBottomDialogRes().overrideMultiSelectionImage(bottomMenu.isLightTheme(), true);
+ if (overrideSelectionImageResId != 0) {
+ viewHolder.imgDialogxMenuSelection.setImageResource(overrideSelectionImageResId);
+ }
+ } else {
+ int overrideSelectionImageResId = bottomMenu.getStyle().overrideBottomDialogRes().overrideMultiSelectionImage(bottomMenu.isLightTheme(), false);
+ if (overrideSelectionImageResId != 0) {
+ viewHolder.imgDialogxMenuSelection.setVisibility(View.VISIBLE);
+ viewHolder.imgDialogxMenuSelection.setImageResource(overrideSelectionImageResId);
+ } else {
+ viewHolder.imgDialogxMenuSelection.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+ } else {
+ viewHolder.imgDialogxMenuSelection.setVisibility(View.GONE);
+ }
+ int overrideSelectionBackgroundColorRes = 0;
+ if (bottomMenu.getStyle().overrideBottomDialogRes() != null) {
+ overrideSelectionBackgroundColorRes = bottomMenu.getStyle().overrideBottomDialogRes().overrideSelectionMenuBackgroundColor(bottomMenu.isLightTheme());
+ }
+ if (bottomMenu.getSelection() == position) {
+ if (overrideSelectionBackgroundColorRes != 0) {
+ convertView.setBackgroundTintList(ColorStateList.valueOf(context.getResources().getColor(overrideSelectionBackgroundColorRes)));
+ final View finalRootView = convertView;
+ convertView.post(new Runnable() {
+ @Override
+ public void run() {
+ finalRootView.setPressed(true);
+ }
+ });
+ }
+ } else {
+ convertView.setBackgroundTintList(null);
+ }
+ CharSequence text = objects.get(position);
+
+ int textColor = bottomMenu.isLightTheme() ? R.color.black90 : R.color.white90;
+ if (bottomMenu.getStyle().overrideBottomDialogRes() != null) {
+ if (bottomMenu.getStyle().overrideBottomDialogRes().overrideMenuTextColor(bottomMenu.isLightTheme()) != 0) {
+ textColor = bottomMenu.getStyle().overrideBottomDialogRes().overrideMenuTextColor(bottomMenu.isLightTheme());
+ }
+ }
+
+ if (null != text) {
+ viewHolder.txtDialogxMenuText.setText(text);
+ viewHolder.txtDialogxMenuText.setTextColor(context.getResources().getColor(textColor));
+ if (DialogX.menuTextInfo != null) {
+ useTextInfo(viewHolder.txtDialogxMenuText, DialogX.menuTextInfo);
+ }
+ if (viewHolder.imgDialogxMenuSelection != null) {
+ if (bottomMenu.getStyle().overrideBottomDialogRes() != null && bottomMenu.getStyle().overrideBottomDialogRes().selectionImageTint(bottomMenu.isLightTheme())) {
+ viewHolder.imgDialogxMenuSelection.setImageTintList(ColorStateList.valueOf(context.getResources().getColor(textColor)));
+ } else {
+ viewHolder.imgDialogxMenuSelection.setImageTintList(null);
+ }
+ }
+
+ if (bottomMenu.getOnIconChangeCallBack() != null) {
+ int resId = bottomMenu.getOnIconChangeCallBack().getIcon(bottomMenu, position, text.toString());
+ boolean autoTintIconInLightOrDarkMode = bottomMenu.getOnIconChangeCallBack().isAutoTintIconInLightOrDarkMode();
+
+ if (resId != 0) {
+ viewHolder.imgDialogxMenuIcon.setVisibility(View.VISIBLE);
+ viewHolder.imgDialogxMenuIcon.setImageResource(resId);
+
+ if (autoTintIconInLightOrDarkMode) {
+ viewHolder.imgDialogxMenuIcon.setImageTintList(ColorStateList.valueOf(context.getResources().getColor(textColor)));
+ }
+ } else {
+ viewHolder.imgDialogxMenuIcon.setVisibility(View.GONE);
+ }
+ } else {
+ viewHolder.imgDialogxMenuIcon.setVisibility(View.GONE);
+ }
+ }
+
+ return convertView;
+ }
+
+ protected void useTextInfo(TextView textView, TextInfo textInfo) {
+ if (textInfo == null) return;
+ if (textView == null) return;
+ if (textInfo.getFontSize() > 0) {
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textInfo.getFontSize());
+ }
+ if (textInfo.getFontColor() != 1) {
+ textView.setTextColor(textInfo.getFontColor());
+ }
+ if (textInfo.getGravity() != -1) {
+ textView.setGravity(textInfo.getGravity());
+ }
+ Typeface font = Typeface.create(Typeface.SANS_SERIF, textInfo.isBold() ? Typeface.BOLD : Typeface.NORMAL);
+ textView.setTypeface(font);
+ }
+}
\ No newline at end of file
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/TextInfo.java b/DialogX/src/main/java/com/kongzue/dialogx/util/TextInfo.java
new file mode 100644
index 0000000..96cd131
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/TextInfo.java
@@ -0,0 +1,62 @@
+package com.kongzue.dialogx.util;
+
+/**
+ * Author: @Kongzue
+ * Github: https://github.com/kongzue/
+ * Homepage: http://kongzue.com/
+ * Mail: myzcxhh@live.cn
+ * CreateTime: 2018/11/10 22:01
+ */
+public class TextInfo {
+
+ private int fontSize = -1; //字号大小,值为-1时使用默认样式,单位:dp
+ private int gravity = -1; //对齐方式,值为-1时使用默认样式,取值可使用Gravity.CENTER等对齐方式
+ private int fontColor = 1; //文字颜色,值为1时使用默认样式,取值可以用Color.rgb(r,g,b)等方式获取
+ private boolean bold = false; //是否粗体
+
+ public int getFontSize() {
+ return fontSize;
+ }
+
+ public TextInfo setFontSize(int fontSize) {
+ this.fontSize = fontSize;
+ return this;
+ }
+
+ public int getGravity() {
+ return gravity;
+ }
+
+ public TextInfo setGravity(int gravity) {
+ this.gravity = gravity;
+ return this;
+ }
+
+ public int getFontColor() {
+ return fontColor;
+ }
+
+ public TextInfo setFontColor(int fontColor) {
+ this.fontColor = fontColor;
+ return this;
+ }
+
+ public boolean isBold() {
+ return bold;
+ }
+
+ public TextInfo setBold(boolean bold) {
+ this.bold = bold;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "TextInfo{" +
+ "fontSize=" + fontSize +
+ ", gravity=" + gravity +
+ ", fontColor=" + fontColor +
+ ", bold=" + bold +
+ '}';
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/WindowUtil.java b/DialogX/src/main/java/com/kongzue/dialogx/util/WindowUtil.java
new file mode 100644
index 0000000..24b8312
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/WindowUtil.java
@@ -0,0 +1,57 @@
+package com.kongzue.dialogx.util;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.os.Build;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import com.kongzue.dialogx.R;
+import com.kongzue.dialogx.interfaces.BaseDialog;
+
+import static android.view.WindowManager.LayoutParams.*;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2021/4/29 16:02
+ */
+public class WindowUtil {
+
+ public static void show(Activity activity, View dialogView, boolean touchEnable) {
+ WindowManager manager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+
+ layoutParams.gravity = Gravity.CENTER_VERTICAL;
+ layoutParams.format = PixelFormat.TRANSPARENT;
+ layoutParams.type = TYPE_APPLICATION_ATTACHED_DIALOG;
+ layoutParams.flags = FLAG_FULLSCREEN |
+ FLAG_TRANSLUCENT_STATUS |
+ FLAG_TRANSLUCENT_NAVIGATION |
+ FLAG_LAYOUT_IN_SCREEN
+ ;
+ if (!touchEnable) {
+ layoutParams.flags = layoutParams.flags | FLAG_NOT_FOCUSABLE;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ }
+
+ manager.addView(dialogView, layoutParams);
+ }
+
+ public static void dismiss(View dialogView) {
+ BaseDialog baseDialog = (BaseDialog) dialogView.getTag();
+ if (baseDialog != null && baseDialog.getActivity() != null) {
+ WindowManager manager = (WindowManager) baseDialog.getActivity().getSystemService(Context.WINDOW_SERVICE);
+ manager.removeViewImmediate(dialogView);
+ }
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/views/ActivityScreenShotImageView.java b/DialogX/src/main/java/com/kongzue/dialogx/util/views/ActivityScreenShotImageView.java
new file mode 100644
index 0000000..5b1f65d
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/views/BlurView.java b/DialogX/src/main/java/com/kongzue/dialogx/util/views/BlurView.java
new file mode 100644
index 0000000..993fa13
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/views/BlurView.java
@@ -0,0 +1,455 @@
+package com.kongzue.dialogx.util.views;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewTreeObserver;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
+import androidx.renderscript.Allocation;
+import androidx.renderscript.Element;
+import androidx.renderscript.RenderScript;
+import androidx.renderscript.ScriptIntrinsicBlur;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.R;
+import com.kongzue.dialogx.interfaces.BaseDialog;
+
+public class BlurView extends View {
+ private float mDownsampleFactor = 4;
+ private int mOverlayColor = Color.WHITE;
+ private float mBlurRadius = 35;
+
+ private float mRadius = 0;
+ private Path mBoundPath = null;
+
+ 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();
+ // 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);
+ }
+
+ public BlurView(Context context) {
+ super(context);
+
+ init(context, null);
+ }
+
+ public BlurView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ init(context, attrs);
+ }
+
+ public BlurView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ init(context, attrs);
+ }
+
+ private boolean isInit = false;
+
+ private void init(Context context, AttributeSet attrs) {
+ if (!isInit) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RealtimeBlurView);
+ mBlurRadius = a.getDimension(
+ R.styleable.RealtimeBlurView_realtimeBlurRadius,
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 35, context.getResources().getDisplayMetrics())
+ );
+ mDownsampleFactor = a.getFloat(R.styleable.RealtimeBlurView_realtimeDownsampleFactor, 4);
+ mOverlayColor = a.getColor(R.styleable.RealtimeBlurView_realtimeOverlayColor, 0x00ffffff);
+
+ //ready rounded corner
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+ mRectF = new RectF();
+
+ mRadius = a.getDimension(R.styleable.RealtimeBlurView_radius, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, context.getResources().getDisplayMetrics()));
+ a.recycle();
+
+ isInit = true;
+ }
+ }
+
+ 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() {
+ log("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) {
+ 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;
+ oldBmp = null;
+ 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();
+ if (BaseDialog.getRootFrameLayout() != null && BaseDialog.getRootFrameLayout().getChildCount() >= 1) {
+ mDecorView = BaseDialog.getRootFrameLayout().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
+ public void draw(Canvas canvas) {
+ if (!useBlur) {
+ Paint cutPaint = new Paint();
+ cutPaint.setAntiAlias(true);
+ cutPaint.setColor(mOverlayColor);
+ mRectF.right = getWidth();
+ mRectF.bottom = getHeight();
+ canvas.drawRoundRect(mRectF, mRadius, mRadius, cutPaint);
+ } else {
+ if (mIsRendering) {
+ // Quit here, don't draw views above me
+ //throw STOP_EXCEPTION;
+ } else if (RENDERING_COUNT > 0) {
+ // Doesn't support blurview overlap on another blurview
+ } else {
+ if (mRadius != 0) {
+ Rect rect = new Rect();
+ getLocalVisibleRect(rect);
+ rect.right = rect.left + getWidth();
+ rect.bottom = rect.top + getHeight();
+ mBoundPath = caculateRoundRectPath(rect);
+ canvas.clipPath(mBoundPath);
+ }
+ super.draw(canvas);
+ }
+ }
+ }
+
+ private Path caculateRoundRectPath(Rect r) {
+ Path path = new Path();
+ float radius = mRadius;
+ float elevation = 0;
+ path.addRoundRect(new RectF(r.left + elevation, r.top + elevation, r.right - elevation, r.bottom - elevation), radius, radius, Path.Direction.CW);
+ return path;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ drawBlurredBitmap(canvas, mBlurredBitmap, mOverlayColor);
+ }
+
+ /**
+ * Custom draw the blurred bitmap and color to define your own shape
+ *
+ * @param canvas
+ * @param blurredBitmap
+ * @param overlayColor
+ */
+ protected void drawBlurredBitmap(Canvas canvas, Bitmap blurredBitmap, int overlayColor) {
+ 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((supportRenderScript && useBlur) ? overlayColor : removeAlphaColor(overlayColor));
+ }
+
+ private static boolean supportRenderScript = false;
+ private boolean useBlur = true;
+
+ public boolean isUseBlur() {
+ return useBlur;
+ }
+
+ public BlurView setUseBlur(boolean useBlur) {
+ this.useBlur = useBlur;
+ invalidate();
+ return this;
+ }
+
+ private static int removeAlphaColor(@ColorInt 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);
+ }
+
+ static {
+ /**
+ * 之所以需要启动一个新线程检测RenderScript是否可用的原因是不清楚Android什么时候对loadClass做了变更,
+ * 会直接抛出NoClassDefFoundError无法拦截,在主线程检测会导致程序直接闪退,因此改为异步检测。
+ * 检测后会给定(boolean)supportRenderScript用于判断时光支持
+ */
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ BlurView.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;
+ }
+
+ public static void log(Object o) {
+ if (isDebug()) Log.i(">>>", o.toString());
+ }
+
+ public static void error(Object o) {
+ if (isDebug()) Log.e(">>>", o.toString());
+ }
+}
\ No newline at end of file
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/views/BottomDialogListView.java b/DialogX/src/main/java/com/kongzue/dialogx/util/views/BottomDialogListView.java
new file mode 100644
index 0000000..c4ce2a5
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/views/BottomDialogListView.java
@@ -0,0 +1,115 @@
+package com.kongzue.dialogx.util.views;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.ScrollView;
+
+import androidx.annotation.RequiresApi;
+
+import com.kongzue.dialogx.dialogs.BottomDialog;
+import com.kongzue.dialogx.interfaces.BottomMenuListViewTouchEvent;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/10/6 23:42
+ */
+public class BottomDialogListView extends ListView {
+
+ private BottomMenuListViewTouchEvent bottomMenuListViewTouchEvent;
+
+ public BottomDialogListView(Context context) {
+ super(context);
+ }
+
+ public BottomDialogListView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public BottomDialogListView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ private BottomDialog.DialogImpl dialogImpl;
+
+ public BottomDialogListView(BottomDialog.DialogImpl dialog, Context context) {
+ super(context);
+ dialogImpl = dialog;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
+ super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dip2px(55)*size+size, MeasureSpec.EXACTLY));
+
+ //super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(expandSpec, MeasureSpec.AT_MOST));
+ }
+
+ private int dip2px(float dpValue) {
+ final float scale = Resources.getSystem().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+
+ private int mPosition;
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ final int actionMasked = ev.getActionMasked() & MotionEvent.ACTION_MASK;
+
+ if (actionMasked == MotionEvent.ACTION_DOWN) {
+ if (bottomMenuListViewTouchEvent != null) {
+ bottomMenuListViewTouchEvent.down(ev);
+ }
+ mPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
+ return super.dispatchTouchEvent(ev);
+ }
+
+ if (actionMasked == MotionEvent.ACTION_MOVE) {
+ if (bottomMenuListViewTouchEvent != null) {
+ bottomMenuListViewTouchEvent.move(ev);
+ }
+ return true;
+ }
+ if (actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL) {
+ if (bottomMenuListViewTouchEvent != null) {
+ bottomMenuListViewTouchEvent.up(ev);
+ }
+ if (pointToPosition((int) ev.getX(), (int) ev.getY()) == mPosition) {
+ super.dispatchTouchEvent(ev);
+ } else {
+ setPressed(false);
+ invalidate();
+ }
+ }
+
+ return super.dispatchTouchEvent(ev);
+ }
+
+ public BottomMenuListViewTouchEvent getBottomMenuListViewTouchEvent() {
+ return bottomMenuListViewTouchEvent;
+ }
+
+ private int size =1;
+
+ @Override
+ public void setAdapter(ListAdapter adapter) {
+ size = adapter.getCount();
+ super.setAdapter(adapter);
+ }
+
+ public BottomDialogListView setBottomMenuListViewTouchEvent(BottomMenuListViewTouchEvent bottomMenuListViewTouchEvent) {
+ this.bottomMenuListViewTouchEvent = bottomMenuListViewTouchEvent;
+ return this;
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/views/BottomDialogScrollView.java b/DialogX/src/main/java/com/kongzue/dialogx/util/views/BottomDialogScrollView.java
new file mode 100644
index 0000000..c684407
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/views/BottomDialogScrollView.java
@@ -0,0 +1,55 @@
+package com.kongzue.dialogx.util.views;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.widget.ScrollView;
+
+import com.kongzue.dialogx.dialogs.BottomDialog;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/11/17 15:29
+ */
+public class BottomDialogScrollView extends ScrollView {
+
+ public BottomDialogScrollView(Context context) {
+ super(context);
+ }
+
+ public BottomDialogScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public BottomDialogScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public BottomDialogScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ boolean lockScroll;
+
+ public void lockScroll(boolean lockScroll) {
+ this.lockScroll = lockScroll;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (lockScroll) {
+ return false;
+ }
+ return super.onTouchEvent(ev);
+ }
+
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ return super.dispatchTouchEvent(ev);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/views/DialogXBaseRelativeLayout.java b/DialogX/src/main/java/com/kongzue/dialogx/util/views/DialogXBaseRelativeLayout.java
new file mode 100644
index 0000000..1be6476
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/views/DialogXBaseRelativeLayout.java
@@ -0,0 +1,244 @@
+package com.kongzue.dialogx.util.views;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.RelativeLayout;
+
+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;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/22 13:53
+ */
+public class DialogXBaseRelativeLayout extends RelativeLayout {
+
+ private OnSafeInsetsChangeListener onSafeInsetsChangeListener;
+ private BaseDialog parentDialog;
+ private boolean autoUnsafePlacePadding = true;
+ private boolean focusable = true;
+
+ private OnLifecycleCallBack onLifecycleCallBack;
+ private OnBackPressedListener onBackPressedListener;
+
+ public DialogXBaseRelativeLayout(Context context) {
+ super(context);
+ init(null);
+ }
+
+ public DialogXBaseRelativeLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs);
+ }
+
+ public DialogXBaseRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs);
+ }
+
+ public DialogXBaseRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(attrs);
+ }
+
+ private boolean isInited = false;
+
+ private void init(AttributeSet attrs) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ setForceDarkAllowed(false);
+ }
+ if (!isInited ) {
+ if (attrs != null) {
+ TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.DialogXBaseRelativeLayout);
+ focusable = a.getBoolean(R.styleable.DialogXBaseRelativeLayout_baseFocusable, true);
+ a.recycle();
+ }
+ if (focusable) {
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ requestFocus();
+ }
+ }
+ }
+
+ @Override
+ protected boolean fitSystemWindows(Rect insets) {
+ paddingView(insets.left, insets.top, insets.right, insets.bottom);
+ return super.fitSystemWindows(insets);
+ }
+
+ @Override
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ paddingView(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
+ }
+ return super.dispatchApplyWindowInsets(insets);
+ }
+
+ public void paddingView(WindowInsets insets) {
+ if (insets == null) return;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ paddingView(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
+ }
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (isAttachedToWindow() && event.getAction() == KeyEvent.ACTION_UP && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ if (onBackPressedListener != null) {
+ onBackPressedListener.onBackPressed();
+ }
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ final ViewParent parent = getParent();
+
+ if (parent instanceof View)ViewCompat.setFitsSystemWindows(this, ViewCompat.getFitsSystemWindows((View) parent));
+ ViewCompat.requestApplyInsets(this);
+
+ if (BaseDialog.getContext() == null) return;
+ if (!isInEditMode()) {
+ ((Activity) BaseDialog.getContext()).getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(decorViewLayoutListener);
+ }
+
+ if (onLifecycleCallBack != null) {
+ onLifecycleCallBack.onShow();
+ }
+ }
+
+ private ViewTreeObserver.OnGlobalLayoutListener decorViewLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ paddingView(getRootWindowInsets());
+ } else {
+ if (BaseDialog.getContext() == null) return;
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ ((Activity) BaseDialog.getContext()).getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
+ Rect rect = new Rect();
+ ((Activity) BaseDialog.getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
+ paddingView(rect.left, rect.top, displayMetrics.widthPixels - rect.right, displayMetrics.heightPixels - rect.bottom);
+ }
+ }
+ };
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if (decorViewLayoutListener != null && ((Activity) BaseDialog.getContext()) != null) {
+ ((Activity) BaseDialog.getContext()).getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(decorViewLayoutListener);
+ }
+ if (onLifecycleCallBack != null) {
+ onLifecycleCallBack.onDismiss();
+ }
+ super.onDetachedFromWindow();
+ }
+
+ @Override
+ public boolean performClick() {
+ return super.performClick();
+ }
+
+ public DialogXBaseRelativeLayout setOnLifecycleCallBack(OnLifecycleCallBack onLifecycleCallBack) {
+ this.onLifecycleCallBack = onLifecycleCallBack;
+ return this;
+ }
+
+ public float getSafeHeight() {
+ return getMeasuredHeight() - unsafePlace.bottom - unsafePlace.top;
+ }
+
+ public abstract static class OnLifecycleCallBack {
+ public void onShow() {
+ }
+
+ public abstract void onDismiss();
+ }
+
+ protected Rect unsafePlace = new Rect();
+
+ 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();
+ if (bkgLp.getRules()[ALIGN_PARENT_BOTTOM] == RelativeLayout.TRUE && isAutoUnsafePlacePadding()) {
+ bkgView.setPadding(0, 0, 0, bottom);
+ setPadding(left, top, right, 0);
+ return;
+ }
+ }
+ if (isAutoUnsafePlacePadding()) setPadding(left, top, right, bottom);
+ }
+
+ public DialogXBaseRelativeLayout setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
+ this.onBackPressedListener = onBackPressedListener;
+ return this;
+ }
+
+ public OnSafeInsetsChangeListener getOnSafeInsetsChangeListener() {
+ return onSafeInsetsChangeListener;
+ }
+
+ public DialogXBaseRelativeLayout setOnSafeInsetsChangeListener(OnSafeInsetsChangeListener onSafeInsetsChangeListener) {
+ this.onSafeInsetsChangeListener = onSafeInsetsChangeListener;
+ return this;
+ }
+
+ public boolean isAutoUnsafePlacePadding() {
+ return autoUnsafePlacePadding;
+ }
+
+ public DialogXBaseRelativeLayout setAutoUnsafePlacePadding(boolean autoUnsafePlacePadding) {
+ this.autoUnsafePlacePadding = autoUnsafePlacePadding;
+ return this;
+ }
+
+ public BaseDialog getParentDialog() {
+ return parentDialog;
+ }
+
+ public DialogXBaseRelativeLayout setParentDialog(BaseDialog parentDialog) {
+ this.parentDialog = parentDialog;
+ return this;
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ getParentDialog().onUIModeChange(newConfig);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/views/MaxRelativeLayout.java b/DialogX/src/main/java/com/kongzue/dialogx/util/views/MaxRelativeLayout.java
new file mode 100644
index 0000000..ecefd1a
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/views/MaxRelativeLayout.java
@@ -0,0 +1,224 @@
+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;
+import android.widget.RelativeLayout;
+import android.widget.ScrollView;
+
+import com.kongzue.dialogx.R;
+
+import static android.view.View.MeasureSpec.EXACTLY;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2019/9/24 17:34
+ */
+public class MaxRelativeLayout extends RelativeLayout {
+
+ private int maxWidth;
+ private int maxHeight;
+ private int minWidth;
+ private int minHeight;
+ private boolean lockWidth;
+ private boolean interceptTouch = true;
+
+ public MaxRelativeLayout(Context context) {
+ super(context);
+ init(context, null);
+ }
+
+ public MaxRelativeLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs);
+ }
+
+ public MaxRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ 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();
+ }
+ minWidth = getMinimumWidth();
+ minHeight = getMinimumHeight();
+
+ 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;
+
+ public MaxRelativeLayout setMaxHeight(int maxHeight) {
+ this.maxHeight = maxHeight;
+ return this;
+ }
+
+ public MaxRelativeLayout setMaxWidth(int maxWidth) {
+ if (maxWidth > 0 && this.maxWidth != 0) this.maxWidth = maxWidth;
+ return this;
+ }
+
+ private int preWidth = -1;
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+
+ if (preWidth == -1 && widthSize != 0) {
+ preWidth = widthSize;
+ }
+ if (lockWidth) {
+ maxWidth = Math.min(widthSize, preWidth);
+ }
+ if (maxHeight > 0) {
+ heightSize = Math.min(heightSize, maxHeight);
+ }
+ if (maxWidth > 0) {
+ widthSize = Math.min(widthSize, maxWidth);
+ }
+ View blurView = findViewWithTag("blurView");
+ View contentView = findViewWithoutTag("blurView");
+ if (contentView != null) {
+ int widthTemp = contentView.getMeasuredWidth() == 0 ? getMeasuredWidth() : contentView.getMeasuredWidth();
+ int heightTemp = contentView.getMeasuredHeight() == 0 ? getMeasuredHeight() : contentView.getMeasuredHeight();
+ if (widthTemp < minWidth) widthTemp = minWidth;
+ if (heightTemp < minHeight) heightTemp = minHeight;
+ if (blurView != null) {
+ if (heightMode == EXACTLY){
+ heightTemp = heightSize;
+ }
+ if (widthMode == EXACTLY){
+ widthTemp = widthSize;
+ }
+ LayoutParams lp = (LayoutParams) blurView.getLayoutParams();
+ lp.width = widthTemp;
+ lp.height = heightTemp;
+ blurView.setLayoutParams(lp);
+ }
+ } else {
+ if (blurView != null) {
+ LayoutParams lp = (LayoutParams) blurView.getLayoutParams();
+ lp.width = getMeasuredWidth();
+ lp.height = getMeasuredHeight();
+ blurView.setLayoutParams(lp);
+ }
+ }
+
+ int maxHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
+ int maxWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
+ super.onMeasure(maxWidthMeasureSpec, maxHeightMeasureSpec);
+
+ childScrollView = findViewById(R.id.scrollView);
+ }
+
+ private View findViewWithoutTag(String tag) {
+ for (int i = 0; i < getChildCount(); i++) {
+ if (!tag.equals(getChildAt(i).getTag())) {
+ return getChildAt(i);
+ }
+ }
+ return null;
+ }
+
+ public boolean isChildScrollViewCanScroll() {
+ if (childScrollView == null) return false;
+ if (!childScrollView.isEnabled()) {
+ return false;
+ }
+ View child = childScrollView.getChildAt(0);
+ if (child != null) {
+ int childHeight = child.getHeight();
+ return childScrollView.getHeight() < childHeight;
+ }
+ return false;
+ }
+
+ public int dip2px(float dpValue) {
+ final float scale = getResources().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+
+ public boolean isLockWidth() {
+ return lockWidth;
+ }
+
+ public MaxRelativeLayout setLockWidth(boolean lockWidth) {
+ 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);
+ }
+
+ private OnTouchListener onTouchListener;
+
+ @Override
+ public void setOnTouchListener(OnTouchListener l) {
+ onTouchListener = l;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (onTouchListener != null) {
+ onTouchListener.onTouch(this, ev);
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/views/NoArticulatedProgressView.java b/DialogX/src/main/java/com/kongzue/dialogx/util/views/NoArticulatedProgressView.java
new file mode 100644
index 0000000..0f767f6
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/views/NoArticulatedProgressView.java
@@ -0,0 +1,452 @@
+package com.kongzue.dialogx.util.views;
+
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.HapticFeedbackConstants;
+import android.view.View;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+
+import androidx.annotation.Nullable;
+
+import com.kongzue.dialogx.R;
+import com.kongzue.dialogx.interfaces.ProgressViewInterface;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2021/3/14 20:58
+ */
+public class NoArticulatedProgressView extends View implements ProgressViewInterface {
+ public static final int STATUS_LOADING = 0;
+ public static final int STATUS_SUCCESS = 1;
+ public static final int STATUS_WARNING = 2;
+ public static final int STATUS_ERROR = 3;
+ public static final int STATUS_PROGRESSING = 4;
+
+ private int status = STATUS_LOADING;
+
+ private int width = dip2px(2);
+ private int color = Color.WHITE;
+
+ public NoArticulatedProgressView(Context context) {
+ super(context);
+ init(null);
+ }
+
+ public NoArticulatedProgressView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs);
+ }
+
+ public NoArticulatedProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs);
+ }
+
+ public NoArticulatedProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(attrs);
+ }
+
+ private ValueAnimator rotateAnimator;
+ private ValueAnimator followAnimator;
+
+ private float currentRotateDegrees;
+ private float followRotateDegrees;
+
+ //跟随点度数做正弦值变化,halfSweepAMinValue为最低相较目标点度数差值,halfSweepAMaxValue为最大相较目标点度数差值
+ private float halfSweepAMaxValue = 180;
+ private float halfSweepAMinValue = 80;
+ //正弦函数的半径
+ private float halfSweepA;
+
+ Paint mPaint = new Paint();
+
+ private boolean isInited = false;
+
+ private void init(AttributeSet attrs) {
+ synchronized (NoArticulatedProgressView.class) {
+ if (isInited) {
+ return;
+ }
+ isInited = true;
+ if (attrs != null) {
+ TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ProgressView);
+ width = a.getDimensionPixelSize(R.styleable.ProgressView_progressStrokeWidth, dip2px(2));
+ color = a.getDimensionPixelSize(R.styleable.ProgressView_progressStrokeColor, color);
+
+ a.recycle();
+ }
+
+ mPaint.setAntiAlias(true);
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setStrokeWidth(width);
+ mPaint.setStrokeCap(Paint.Cap.ROUND);
+ mPaint.setColor(color);
+
+ if (!isInEditMode()) {
+ halfSweepA = (halfSweepAMaxValue - halfSweepAMinValue) / 2;
+
+ rotateAnimator = ValueAnimator.ofFloat(0, 365);
+ rotateAnimator.setDuration(1000);
+ rotateAnimator.setInterpolator(new LinearInterpolator());
+ rotateAnimator.setRepeatCount(-1);
+ rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ currentRotateDegrees = (float) animation.getAnimatedValue();
+ invalidate();
+ }
+ });
+
+ followAnimator = ValueAnimator.ofFloat(0, 365);
+ followAnimator.setDuration(1500);
+ followAnimator.setInterpolator(new LinearInterpolator());
+ followAnimator.setRepeatCount(-1);
+ followAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ followRotateDegrees = (float) animation.getAnimatedValue();
+ }
+ });
+
+ followAnimator.start();
+ rotateAnimator.start();
+ }
+ }
+ }
+
+ //旋转圆的中心坐标
+ private float mCenterX;
+ private float mCenterY;
+ //半径
+ private float mRadius = 100;
+ private RectF oval;
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ mCenterX = w * 1f / 2;
+ mCenterY = h * 1f / 2;
+ mRadius = Math.min(getWidth(), getHeight()) / 2 - width / 2;
+ oval = new RectF(mCenterX - mRadius, mCenterY - mRadius, mCenterX + mRadius, mCenterY + mRadius);
+ }
+
+ protected float oldAnimAngle;
+ private int successStep = 0;
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (isInEditMode()) {
+ canvas.drawArc(oval, 0, 365, false, mPaint);
+ return;
+ }
+ if (noShowLoading) {
+ canvas.drawArc(oval, 0, 365, false, mPaint);
+ successStep = 2;
+ drawDoneMark(status, canvas);
+ return;
+ }
+
+ float sweepAngle = (float) (halfSweepA * Math.sin(Math.toRadians(followRotateDegrees))) + halfSweepA + halfSweepAMinValue / 2;
+ switch (status) {
+ case STATUS_LOADING:
+ canvas.drawArc(oval, currentRotateDegrees, -sweepAngle, false, mPaint);
+ break;
+ case STATUS_SUCCESS:
+ case STATUS_WARNING:
+ case STATUS_ERROR:
+ canvas.drawArc(oval, 0, 360, false, mPaint);
+ drawDoneMark(status, canvas);
+ break;
+ case STATUS_PROGRESSING:
+ canvas.drawArc(oval, -90, currentRotateDegrees, false, mPaint);
+ if (waitProgressingRunnable != null) {
+ waitProgressingRunnable.run();
+ waitProgressingRunnable = null;
+ }
+ break;
+ }
+ }
+
+ private void drawDoneMark(int status, Canvas canvas) {
+ if (rotateAnimator.getInterpolator() != interpolator) {
+ rotateAnimator.setInterpolator(interpolator);
+ }
+ if (tickShowRunnable != null) {
+ tickShowRunnable.run();
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ tickShowRunnable = null;
+ }
+ switch (status) {
+ case STATUS_SUCCESS:
+ showSuccessTick(canvas);
+ break;
+ case STATUS_WARNING:
+ showWarningTick(canvas);
+ break;
+ case STATUS_ERROR:
+ showErrorTick(canvas);
+ break;
+ }
+ }
+
+ private int line1X = 0;
+ private int line1Y = 0;
+ private int line2X = 0;
+ private int line2Y = 0;
+
+ private int tickStep = 0;
+
+ //绘制对号
+ private void showSuccessTick(Canvas canvas) {
+ int tickLeftPoint = (int) (mCenterX - mRadius * 1 / 2);
+ int tickTurnLeftPoint = (int) (mCenterX - mRadius / 10);
+ int tickRightPoint = (int) (mRadius * 0.99f);
+ int speed = 2;
+ switch (tickStep) {
+ case 0:
+ if (tickLeftPoint + line1X < tickTurnLeftPoint) {
+ line1X = line1X + speed;
+ line1Y = line1Y + speed;
+ } else {
+ line2X = line1X;
+ line2Y = line1Y;
+ tickStep = 1;
+ }
+ break;
+ case 1:
+ if (line2X < tickRightPoint) {
+ line2X = line2X + 4;
+ line2Y = line2Y - 5;
+ }
+ break;
+ }
+ canvas.drawLine(tickLeftPoint, mCenterY, tickLeftPoint + line1X, mCenterY + line1Y, mPaint);
+ canvas.drawLine(tickLeftPoint + line1X, mCenterY + line1Y, tickLeftPoint + line2X, mCenterY + line2Y, mPaint);
+
+ postInvalidateDelayed(1);
+ }
+
+ //绘制感叹号
+ private void showWarningTick(Canvas canvas) {
+ int tickLeftPoint = (int) mCenterX;
+ int line1StartY = (int) (mCenterY - mRadius * 1 / 2);
+ int line1EndY = (int) (mCenterY + mRadius * 1 / 8);
+ int line2StartY = (int) (mCenterY + mRadius * 3 / 7);
+ int speed = 4;
+ switch (tickStep) {
+ case 0:
+ if (line1Y < line1EndY - line1StartY) {
+ line1Y = line1Y + speed;
+ } else {
+ line1Y = line1EndY - line1StartY;
+ tickStep = 1;
+ }
+ break;
+ case 1:
+ if (line2Y != line2StartY) {
+ canvas.drawLine(tickLeftPoint, line2StartY, tickLeftPoint, line2StartY + 1, mPaint);
+ }
+ break;
+ }
+ canvas.drawLine(tickLeftPoint, line1StartY, tickLeftPoint, line1StartY + line1Y, mPaint);
+ postInvalidateDelayed(tickStep == 1 ? 100 : 1);
+ }
+
+ //绘制错误符号
+ private void showErrorTick(Canvas canvas) {
+ int tickLeftPoint = (int) (mCenterX - mRadius * 4 / 10);
+ int tickRightPoint = (int) (mCenterX + mRadius * 4 / 10);
+ int tickTopPoint = (int) (mCenterY - mRadius * 4 / 10);
+ int speed = 4;
+
+ switch (tickStep) {
+ case 0:
+ if (tickRightPoint - line1X > tickLeftPoint) {
+ line1X = line1X + speed;
+ line1Y = line1Y + speed;
+ } else {
+ tickStep = 1;
+ canvas.drawLine(tickRightPoint, tickTopPoint, tickRightPoint - line1X, tickTopPoint + line1Y, mPaint);
+ postInvalidateDelayed(150);
+ return;
+ }
+ break;
+ case 1:
+ if (tickLeftPoint + line2X < tickRightPoint) {
+ line2X = line2X + speed;
+ line2Y = line2Y + speed;
+ }
+ canvas.drawLine(tickLeftPoint, tickTopPoint, tickLeftPoint + line2X, tickTopPoint + line2Y, mPaint);
+ break;
+ }
+ canvas.drawLine(tickRightPoint, tickTopPoint, tickRightPoint - line1X, tickTopPoint + line1Y, mPaint);
+ postInvalidateDelayed(1);
+ }
+
+ private TimeInterpolator interpolator;
+ private Runnable waitProgressingRunnable;
+
+ public void success() {
+ if (status == STATUS_PROGRESSING) {
+ progress(1f);
+ waitProgressingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ tickStep = 0;
+ successStep = 2;
+ interpolator = new AccelerateDecelerateInterpolator();
+ status = STATUS_SUCCESS;
+ }
+ };
+ return;
+ }
+ tickStep = 0;
+ interpolator = new AccelerateDecelerateInterpolator();
+ status = STATUS_SUCCESS;
+ invalidate();
+ }
+
+ public void warning() {
+ if (status == STATUS_PROGRESSING) {
+ progress(1f);
+ waitProgressingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ tickStep = 0;
+ successStep = 2;
+ interpolator = new DecelerateInterpolator(2);
+ status = STATUS_WARNING;
+ }
+ };
+ return;
+ }
+ tickStep = 0;
+ interpolator = new DecelerateInterpolator(2);
+ status = STATUS_WARNING;
+ invalidate();
+ }
+
+ public void error() {
+ if (status == STATUS_PROGRESSING) {
+ progress(1f);
+ waitProgressingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ tickStep = 0;
+ successStep = 2;
+ interpolator = new DecelerateInterpolator(2);
+ status = STATUS_ERROR;
+ }
+ };
+ return;
+ }
+ tickStep = 0;
+ interpolator = new DecelerateInterpolator(2);
+ status = STATUS_ERROR;
+ invalidate();
+ }
+
+ public void progress(float progress) {
+ if (rotateAnimator != null) rotateAnimator.cancel();
+ if (followAnimator != null) followAnimator.cancel();
+ if (status != STATUS_PROGRESSING) {
+ currentRotateDegrees = 0;
+ }
+ rotateAnimator = ValueAnimator.ofFloat(currentRotateDegrees, 365 * progress);
+ rotateAnimator.setDuration(1000);
+ rotateAnimator.setInterpolator(new DecelerateInterpolator(2));
+ rotateAnimator.setRepeatCount(0);
+ rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ currentRotateDegrees = (float) animation.getAnimatedValue();
+ invalidate();
+ }
+ });
+ rotateAnimator.start();
+ status = STATUS_PROGRESSING;
+ }
+
+ private Runnable tickShowRunnable;
+
+ public NoArticulatedProgressView whenShowTick(Runnable runnable) {
+ tickShowRunnable = runnable;
+ return this;
+ }
+
+ public void loading() {
+ noShowLoading = false;
+ oldAnimAngle = 0;
+ successStep = 0;
+ line1X = 0;
+ line1Y = 0;
+ line2X = 0;
+ line2Y = 0;
+ status = STATUS_LOADING;
+ if (rotateAnimator != null) rotateAnimator.cancel();
+ if (followAnimator != null) followAnimator.cancel();
+ isInited = false;
+ init(null);
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if (rotateAnimator != null) {
+ rotateAnimator.cancel();
+ }
+ if (followAnimator != null) {
+ followAnimator.cancel();
+ }
+ super.onDetachedFromWindow();
+ }
+
+ public int getStrokeWidth() {
+ return width;
+ }
+
+ public NoArticulatedProgressView setStrokeWidth(int width) {
+ this.width = width;
+ if (mPaint != null) mPaint.setStrokeWidth(width);
+ return this;
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ public NoArticulatedProgressView setColor(int color) {
+ this.color = color;
+ if (mPaint != null) mPaint.setColor(color);
+ return this;
+ }
+
+ private boolean noShowLoading;
+
+ public void noLoading() {
+ noShowLoading = true;
+ }
+
+ private int dip2px(float dpValue) {
+ final float scale = Resources.getSystem().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/views/ProgressView.java b/DialogX/src/main/java/com/kongzue/dialogx/util/views/ProgressView.java
new file mode 100644
index 0000000..5c88a0a
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/views/ProgressView.java
@@ -0,0 +1,475 @@
+package com.kongzue.dialogx.util.views;
+
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.HapticFeedbackConstants;
+import android.view.View;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+
+import androidx.annotation.Nullable;
+
+import com.kongzue.dialogx.DialogX;
+import com.kongzue.dialogx.R;
+import com.kongzue.dialogx.interfaces.ProgressViewInterface;
+
+/**
+ * @author: Kongzue
+ * @github: https://github.com/kongzue/
+ * @homepage: http://kongzue.com/
+ * @mail: myzcxhh@live.cn
+ * @createTime: 2020/9/27 16:16
+ * @license: Apache License 2.0
+ */
+public class ProgressView extends View implements ProgressViewInterface {
+
+ public static final int STATUS_LOADING = 0;
+ public static final int STATUS_SUCCESS = 1;
+ public static final int STATUS_WARNING = 2;
+ public static final int STATUS_ERROR = 3;
+ public static final int STATUS_PROGRESSING = 4;
+
+ private int status = STATUS_LOADING;
+
+ private int width = dip2px(2);
+ private int color = Color.WHITE;
+
+ public ProgressView(Context context) {
+ super(context);
+ init(null);
+ }
+
+ public ProgressView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs);
+ }
+
+ public ProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs);
+ }
+
+ public ProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(attrs);
+ }
+
+ private ValueAnimator rotateAnimator;
+ private ValueAnimator followAnimator;
+
+ private float currentRotateDegrees;
+ private float followRotateDegrees;
+
+ //跟随点度数做正弦值变化,halfSweepAMinValue为最低相较目标点度数差值,halfSweepAMaxValue为最大相较目标点度数差值
+ private float halfSweepAMaxValue = 180;
+ private float halfSweepAMinValue = 80;
+ //正弦函数的半径
+ private float halfSweepA;
+
+ Paint mPaint = new Paint();
+
+ private boolean isInited = false;
+
+ private void init(AttributeSet attrs) {
+ synchronized (ProgressView.class) {
+ if (isInited) {
+ return;
+ }
+ isInited = true;
+ if (attrs != null) {
+ TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ProgressView);
+ width = a.getDimensionPixelSize(R.styleable.ProgressView_progressStrokeWidth, dip2px(2));
+ color = a.getDimensionPixelSize(R.styleable.ProgressView_progressStrokeColor, color);
+
+ a.recycle();
+ }
+
+ mPaint.setAntiAlias(true);
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setStrokeWidth(width);
+ mPaint.setStrokeCap(Paint.Cap.ROUND);
+ mPaint.setColor(color);
+
+ if (!isInEditMode()) {
+ halfSweepA = (halfSweepAMaxValue - halfSweepAMinValue) / 2;
+
+ rotateAnimator = ValueAnimator.ofFloat(0, 365);
+ rotateAnimator.setDuration(1000);
+ rotateAnimator.setInterpolator(new LinearInterpolator());
+ rotateAnimator.setRepeatCount(-1);
+ rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ currentRotateDegrees = (float) animation.getAnimatedValue();
+ invalidate();
+ }
+ });
+
+ followAnimator = ValueAnimator.ofFloat(0, 365);
+ followAnimator.setDuration(1500);
+ followAnimator.setInterpolator(new LinearInterpolator());
+ followAnimator.setRepeatCount(-1);
+ followAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ followRotateDegrees = (float) animation.getAnimatedValue();
+ }
+ });
+
+ followAnimator.start();
+ rotateAnimator.start();
+ }
+ }
+ }
+
+ //旋转圆的中心坐标
+ private float mCenterX;
+ private float mCenterY;
+ //半径
+ private float mRadius = 100;
+ private RectF oval;
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ mCenterX = w * 1f / 2;
+ mCenterY = h * 1f / 2;
+ mRadius = Math.min(getWidth(), getHeight()) / 2 - width / 2;
+ oval = new RectF(mCenterX - mRadius, mCenterY - mRadius, mCenterX + mRadius, mCenterY + mRadius);
+ }
+
+ protected float oldAnimAngle;
+ private int successStep = 0;
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (isInEditMode()) {
+ canvas.drawArc(oval, 0, 365, false, mPaint);
+ return;
+ }
+ if (noShowLoading) {
+ canvas.drawArc(oval, 0, 365, false, mPaint);
+ successStep = 2;
+ drawDoneMark(status, canvas);
+ return;
+ }
+
+ float sweepAngle = (float) (halfSweepA * Math.sin(Math.toRadians(followRotateDegrees))) + halfSweepA + halfSweepAMinValue / 2;
+ switch (status) {
+ case STATUS_LOADING:
+ canvas.drawArc(oval, currentRotateDegrees, -sweepAngle, false, mPaint);
+ break;
+ case STATUS_SUCCESS:
+ case STATUS_WARNING:
+ case STATUS_ERROR:
+ switch (successStep) {
+ case 0:
+ canvas.drawArc(oval, currentRotateDegrees, -sweepAngle, false, mPaint);
+ if ((currentRotateDegrees - sweepAngle) > 270) {
+ successStep = 1;
+ }
+ break;
+ case 1:
+ float aimAngle = currentRotateDegrees > 270 ? currentRotateDegrees - 270 : 90 + currentRotateDegrees;
+ canvas.drawArc(oval, 270, aimAngle, false, mPaint);
+ if (oldAnimAngle > aimAngle && oldAnimAngle > 300) {
+ successStep = 2;
+ canvas.drawArc(oval, 0, 360, false, mPaint);
+ break;
+ }
+ oldAnimAngle = aimAngle;
+ break;
+ case 2:
+ canvas.drawArc(oval, 0, 360, false, mPaint);
+ drawDoneMark(status, canvas);
+ break;
+ }
+ break;
+ case STATUS_PROGRESSING:
+ canvas.drawArc(oval, -90, currentRotateDegrees, false, mPaint);
+ if (currentRotateDegrees == 365 && waitProgressingRunnable != null) {
+ waitProgressingRunnable.run();
+ waitProgressingRunnable = null;
+ }
+ break;
+ }
+ }
+
+ private void drawDoneMark(int status, Canvas canvas) {
+ if (rotateAnimator.getInterpolator() != interpolator) {
+ rotateAnimator.setInterpolator(interpolator);
+ }
+ if (tickShowRunnable != null) {
+ tickShowRunnable.run();
+ if (DialogX.useHaptic) performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ tickShowRunnable = null;
+ }
+ switch (status) {
+ case STATUS_SUCCESS:
+ showSuccessTick(canvas);
+ break;
+ case STATUS_WARNING:
+ showWarningTick(canvas);
+ break;
+ case STATUS_ERROR:
+ showErrorTick(canvas);
+ break;
+ }
+ }
+
+ private int line1X = 0;
+ private int line1Y = 0;
+ private int line2X = 0;
+ private int line2Y = 0;
+
+ private int tickStep = 0;
+
+ //绘制对号
+ private void showSuccessTick(Canvas canvas) {
+ int tickLeftPoint = (int) (mCenterX - mRadius * 1 / 2);
+ int tickTurnLeftPoint = (int) (mCenterX - mRadius / 10);
+ int tickRightPoint = (int) (mRadius * 0.99f);
+ int speed = 2;
+ switch (tickStep) {
+ case 0:
+ if (tickLeftPoint + line1X < tickTurnLeftPoint) {
+ line1X = line1X + speed;
+ line1Y = line1Y + speed;
+ } else {
+ line2X = line1X;
+ line2Y = line1Y;
+ tickStep = 1;
+ }
+ break;
+ case 1:
+ if (line2X < tickRightPoint) {
+ line2X = line2X + 4;
+ line2Y = line2Y - 5;
+ }
+ break;
+ }
+ canvas.drawLine(tickLeftPoint, mCenterY, tickLeftPoint + line1X, mCenterY + line1Y, mPaint);
+ canvas.drawLine(tickLeftPoint + line1X, mCenterY + line1Y, tickLeftPoint + line2X, mCenterY + line2Y, mPaint);
+
+ postInvalidateDelayed(1);
+ }
+
+ //绘制感叹号
+ private void showWarningTick(Canvas canvas) {
+ int tickLeftPoint = (int) mCenterX;
+ int line1StartY = (int) (mCenterY - mRadius * 1 / 2);
+ int line1EndY = (int) (mCenterY + mRadius * 1 / 8);
+ int line2StartY = (int) (mCenterY + mRadius * 3 / 7);
+ int speed = 4;
+ switch (tickStep) {
+ case 0:
+ if (line1Y < line1EndY - line1StartY) {
+ line1Y = line1Y + speed;
+ } else {
+ line1Y = line1EndY - line1StartY;
+ tickStep = 1;
+ }
+ break;
+ case 1:
+ if (line2Y != line2StartY) {
+ canvas.drawLine(tickLeftPoint, line2StartY, tickLeftPoint, line2StartY + 1, mPaint);
+ }
+ break;
+ }
+ canvas.drawLine(tickLeftPoint, line1StartY, tickLeftPoint, line1StartY + line1Y, mPaint);
+ postInvalidateDelayed(tickStep == 1 ? 100 : 1);
+ }
+
+ //绘制错误符号
+ private void showErrorTick(Canvas canvas) {
+ int tickLeftPoint = (int) (mCenterX - mRadius * 4 / 10);
+ int tickRightPoint = (int) (mCenterX + mRadius * 4 / 10);
+ int tickTopPoint = (int) (mCenterY - mRadius * 4 / 10);
+ int speed = 4;
+
+ switch (tickStep) {
+ case 0:
+ if (tickRightPoint - line1X > tickLeftPoint) {
+ line1X = line1X + speed;
+ line1Y = line1Y + speed;
+ } else {
+ tickStep = 1;
+ canvas.drawLine(tickRightPoint, tickTopPoint, tickRightPoint - line1X, tickTopPoint + line1Y, mPaint);
+ postInvalidateDelayed(150);
+ return;
+ }
+ break;
+ case 1:
+ if (tickLeftPoint + line2X < tickRightPoint) {
+ line2X = line2X + speed;
+ line2Y = line2Y + speed;
+ }
+ canvas.drawLine(tickLeftPoint, tickTopPoint, tickLeftPoint + line2X, tickTopPoint + line2Y, mPaint);
+ break;
+ }
+ canvas.drawLine(tickRightPoint, tickTopPoint, tickRightPoint - line1X, tickTopPoint + line1Y, mPaint);
+ postInvalidateDelayed(1);
+ }
+
+ private TimeInterpolator interpolator;
+ private Runnable waitProgressingRunnable;
+
+ public void success() {
+ if (status == STATUS_PROGRESSING) {
+ progress(1f);
+ waitProgressingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ tickStep = 0;
+ successStep = 2;
+ interpolator = new AccelerateDecelerateInterpolator();
+ status = STATUS_SUCCESS;
+ }
+ };
+ return;
+ }
+ tickStep = 0;
+ interpolator = new AccelerateDecelerateInterpolator();
+ status = STATUS_SUCCESS;
+ invalidate();
+ }
+
+ public void warning() {
+ if (status == STATUS_PROGRESSING) {
+ progress(1f);
+ waitProgressingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ tickStep = 0;
+ successStep = 2;
+ interpolator = new DecelerateInterpolator(2);
+ status = STATUS_WARNING;
+ }
+ };
+ return;
+ }
+ tickStep = 0;
+ interpolator = new DecelerateInterpolator(2);
+ status = STATUS_WARNING;
+ invalidate();
+ }
+
+ public void error() {
+ if (status == STATUS_PROGRESSING) {
+ progress(1f);
+ waitProgressingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ tickStep = 0;
+ successStep = 2;
+ interpolator = new DecelerateInterpolator(2);
+ status = STATUS_ERROR;
+ }
+ };
+ return;
+ }
+ tickStep = 0;
+ interpolator = new DecelerateInterpolator(2);
+ status = STATUS_ERROR;
+ invalidate();
+ }
+
+ public void progress(float progress) {
+ if (rotateAnimator != null) rotateAnimator.cancel();
+ if (followAnimator != null) followAnimator.cancel();
+ if (status != STATUS_PROGRESSING) {
+ currentRotateDegrees = 0;
+ }
+ rotateAnimator = ValueAnimator.ofFloat(currentRotateDegrees, 365 * progress);
+ rotateAnimator.setDuration(1000);
+ rotateAnimator.setInterpolator(new DecelerateInterpolator(2));
+ rotateAnimator.setRepeatCount(0);
+ rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ currentRotateDegrees = (float) animation.getAnimatedValue();
+ invalidate();
+ }
+ });
+ rotateAnimator.start();
+ status = STATUS_PROGRESSING;
+ }
+
+ private Runnable tickShowRunnable;
+
+ public ProgressView whenShowTick(Runnable runnable) {
+ tickShowRunnable = runnable;
+ return this;
+ }
+
+ public void loading() {
+ noShowLoading = false;
+ oldAnimAngle = 0;
+ successStep = 0;
+ line1X = 0;
+ line1Y = 0;
+ line2X = 0;
+ line2Y = 0;
+ status = STATUS_LOADING;
+ if (rotateAnimator != null) rotateAnimator.cancel();
+ if (followAnimator != null) followAnimator.cancel();
+ isInited = false;
+ init(null);
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if (rotateAnimator != null) {
+ rotateAnimator.cancel();
+ }
+ if (followAnimator != null) {
+ followAnimator.cancel();
+ }
+ super.onDetachedFromWindow();
+ }
+
+ public int getStrokeWidth() {
+ return width;
+ }
+
+ public ProgressView setStrokeWidth(int width) {
+ this.width = width;
+ if (mPaint != null) mPaint.setStrokeWidth(width);
+ return this;
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ public ProgressView setColor(int color) {
+ this.color = color;
+ if (mPaint != null) mPaint.setColor(color);
+ return this;
+ }
+
+ private boolean noShowLoading;
+
+ public void noLoading() {
+ noShowLoading = true;
+ }
+
+ private int dip2px(float dpValue) {
+ final float scale = Resources.getSystem().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+}
diff --git a/DialogX/src/main/java/com/kongzue/dialogx/util/views/RoundView.java b/DialogX/src/main/java/com/kongzue/dialogx/util/views/RoundView.java
new file mode 100644
index 0000000..c457993
--- /dev/null
+++ b/DialogX/src/main/java/com/kongzue/dialogx/util/views/RoundView.java
@@ -0,0 +1,56 @@
+package com.kongzue.dialogx.util.views;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+
+public class RoundView extends RelativeLayout {
+
+ private float mRadius = 0;
+ private Path mBoundPath = null;
+
+ public RoundView(Context context) {
+ this(context, null);
+ }
+
+ public RoundView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RoundView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setWillNotDraw(false);
+ mRadius = 50;
+ }
+
+ public void setRadius(float radius) {
+ if (mRadius == radius)
+ return;
+ this.mRadius = radius;
+ postInvalidate();
+ }
+
+ public float getRadius() {
+ return mRadius;
+ }
+
+ public void draw(Canvas canvas) {
+ Rect rect = new Rect();
+ getLocalVisibleRect(rect);
+ mBoundPath = caculateRoundRectPath(rect);
+ canvas.clipPath(mBoundPath);
+ super.draw(canvas);
+ }
+
+ private Path caculateRoundRectPath(Rect r) {
+ Path path = new Path();
+ float radius = getRadius();
+ float elevation = 0;
+ path.addRoundRect(new RectF(r.left + elevation, r.top + elevation, r.right - elevation, r.bottom - elevation), radius, radius, Path.Direction.CW);
+ return path;
+ }
+}
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_bottom_enter.xml b/DialogX/src/main/res/anim/anim_dialogx_bottom_enter.xml
new file mode 100644
index 0000000..815d566
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_bottom_enter.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_bottom_exit.xml b/DialogX/src/main/res/anim/anim_dialogx_bottom_exit.xml
new file mode 100644
index 0000000..d60af3f
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_bottom_exit.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_default_alpha_enter.xml b/DialogX/src/main/res/anim/anim_dialogx_default_alpha_enter.xml
new file mode 100644
index 0000000..f42dab9
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_default_alpha_enter.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_default_enter.xml b/DialogX/src/main/res/anim/anim_dialogx_default_enter.xml
new file mode 100644
index 0000000..2fb1104
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_default_enter.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_default_exit.xml b/DialogX/src/main/res/anim/anim_dialogx_default_exit.xml
new file mode 100644
index 0000000..1709be3
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_default_exit.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_left_enter.xml b/DialogX/src/main/res/anim/anim_dialogx_left_enter.xml
new file mode 100644
index 0000000..d3b1c6a
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_left_enter.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_left_exit.xml b/DialogX/src/main/res/anim/anim_dialogx_left_exit.xml
new file mode 100644
index 0000000..60fe2ab
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_left_exit.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_right_enter.xml b/DialogX/src/main/res/anim/anim_dialogx_right_enter.xml
new file mode 100644
index 0000000..3746a76
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_right_enter.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_right_exit.xml b/DialogX/src/main/res/anim/anim_dialogx_right_exit.xml
new file mode 100644
index 0000000..be93c12
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_right_exit.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_top_enter.xml b/DialogX/src/main/res/anim/anim_dialogx_top_enter.xml
new file mode 100644
index 0000000..95efebb
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_top_enter.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/anim/anim_dialogx_top_exit.xml b/DialogX/src/main/res/anim/anim_dialogx_top_exit.xml
new file mode 100644
index 0000000..771dbfa
--- /dev/null
+++ b/DialogX/src/main/res/anim/anim_dialogx_top_exit.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/button_dialogx_material_light.xml b/DialogX/src/main/res/drawable/button_dialogx_material_light.xml
new file mode 100644
index 0000000..65e5908
--- /dev/null
+++ b/DialogX/src/main/res/drawable/button_dialogx_material_light.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/button_dialogx_material_night.xml b/DialogX/src/main/res/drawable/button_dialogx_material_night.xml
new file mode 100644
index 0000000..e2f8fb7
--- /dev/null
+++ b/DialogX/src/main/res/drawable/button_dialogx_material_night.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_bkg_light.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_bkg_light.xml
new file mode 100644
index 0000000..505db92
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_bkg_light.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_bkg_night.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_bkg_night.xml
new file mode 100644
index 0000000..a90496c
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_bkg_night.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_bottom_bkg_light.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_bottom_bkg_light.xml
new file mode 100644
index 0000000..e500950
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_bottom_bkg_light.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_bottom_bkg_night.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_bottom_bkg_night.xml
new file mode 100644
index 0000000..edc0eaf
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_bottom_bkg_night.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_button_light_forword.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_button_light_forword.xml
new file mode 100644
index 0000000..261c420
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_button_light_forword.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_button_night_forword.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_button_night_forword.xml
new file mode 100644
index 0000000..518437f
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_button_night_forword.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_dialogtap.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_dialogtap.xml
new file mode 100644
index 0000000..07c0254
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_dialogtap.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_dialogtap_night.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_dialogtap_night.xml
new file mode 100644
index 0000000..d41f3a9
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_dialogtap_night.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_menu_split_divider.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_menu_split_divider.xml
new file mode 100644
index 0000000..aa97988
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_menu_split_divider.xml
@@ -0,0 +1,12 @@
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_menu_split_divider_night.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_menu_split_divider_night.xml
new file mode 100644
index 0000000..29b7e21
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_menu_split_divider_night.xml
@@ -0,0 +1,12 @@
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_poptip_bkg.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_poptip_bkg.xml
new file mode 100644
index 0000000..db95930
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_poptip_bkg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/DialogX/src/main/res/drawable/rect_dialogx_material_poptip_bkg_night.xml b/DialogX/src/main/res/drawable/rect_dialogx_material_poptip_bkg_night.xml
new file mode 100644
index 0000000..e367970
--- /dev/null
+++ b/DialogX/src/main/res/drawable/rect_dialogx_material_poptip_bkg_night.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/DialogX/src/main/res/layout/item_dialogx_material_bottom_menu_normal_text.xml b/DialogX/src/main/res/layout/item_dialogx_material_bottom_menu_normal_text.xml
new file mode 100644
index 0000000..70a7bb9
--- /dev/null
+++ b/DialogX/src/main/res/layout/item_dialogx_material_bottom_menu_normal_text.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/layout/layout_dialogx_bottom_material.xml b/DialogX/src/main/res/layout/layout_dialogx_bottom_material.xml
new file mode 100644
index 0000000..3649d43
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_bottom_material.xml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/layout/layout_dialogx_bottom_material_dark.xml b/DialogX/src/main/res/layout/layout_dialogx_bottom_material_dark.xml
new file mode 100644
index 0000000..59311e6
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_bottom_material_dark.xml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/layout/layout_dialogx_custom.xml b/DialogX/src/main/res/layout/layout_dialogx_custom.xml
new file mode 100644
index 0000000..1ab3f6b
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_custom.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/layout/layout_dialogx_fullscreen.xml b/DialogX/src/main/res/layout/layout_dialogx_fullscreen.xml
new file mode 100644
index 0000000..02ed5f4
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_fullscreen.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DialogX/src/main/res/layout/layout_dialogx_fullscreen_dark.xml b/DialogX/src/main/res/layout/layout_dialogx_fullscreen_dark.xml
new file mode 100644
index 0000000..4632192
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_fullscreen_dark.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DialogX/src/main/res/layout/layout_dialogx_material.xml b/DialogX/src/main/res/layout/layout_dialogx_material.xml
new file mode 100644
index 0000000..941364b
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_material.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/layout/layout_dialogx_material_dark.xml b/DialogX/src/main/res/layout/layout_dialogx_material_dark.xml
new file mode 100644
index 0000000..f3674c7
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_material_dark.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/layout/layout_dialogx_poptip_material.xml b/DialogX/src/main/res/layout/layout_dialogx_poptip_material.xml
new file mode 100644
index 0000000..42fcdab
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_poptip_material.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/layout/layout_dialogx_poptip_material_dark.xml b/DialogX/src/main/res/layout/layout_dialogx_poptip_material_dark.xml
new file mode 100644
index 0000000..d2619a8
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_poptip_material_dark.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/layout/layout_dialogx_wait.xml b/DialogX/src/main/res/layout/layout_dialogx_wait.xml
new file mode 100644
index 0000000..7b4319d
--- /dev/null
+++ b/DialogX/src/main/res/layout/layout_dialogx_wait.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_multi_selection.png b/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_multi_selection.png
new file mode 100644
index 0000000000000000000000000000000000000000..feebea110acf506ae78f5c5cf0b0ac13378a37ba
GIT binary patch
literal 2648
zcmbVO3se(V8jchN6x$$G3DvWc6ju}{lbHmP$$~%kFOoJ{5j1+%|4*^g2mDOf2M7RwzS%F|!G=C2gtlti6*xW#!epolk*N?=4x>qGg-nfM(7;auta&J_
zI!C7;um#>yB!wL3RwIbl>y>)tQpRILP#nh*8HQjO3=l9|?&63t*u}p5h(SlQq{r^&
z?2HTI83_wh!lg)n(ta15?jWs;9S9Q$7*a;K5mYMUUFri;WDw^r@i_X7QzSw=XeaIB
zSb#-?Sa%`AF>E386zbseZw!FY8jV34Pt@Xc22HSBMk#P(ARtdfv*vO)jpWcQQ{o}%
zj8Y);W!@XNTI-<+j`5fo#_=dorbm(?t(H#=4#m%~yC}xXPIzn&ts^)(MS{sN8H~zc
z3^ntKL)Egx1er=Lll4Q53}v^L2cak|Q@|){#^h=Rrbd4Y1yw^49PvNF6sfi{9wz~O
zwmS(MjksMl2^5T^TFW>X4=@bW$@^3ojp|Gn%MmV;&eWwyfZI~Lol=t)n!+$84l5`c
zR3xrQg7HKP3gfCIT%nZ7WQm~G`5=M)I)*Ialgsb#uXBna0mrXaF#^StXxai>FjW$a
zS`-9~ql6Nc;|iJ8svv2SA|A0#^Vq>rBOH&j@~SAnsFYh|BraFLGL^y#D`^D{s}xis
zY_$+cawTQKRaPrs(EYj$b{1r>eBg-W(!~QahaKuG3pGLV<(?uT`8?CWpZ?GGC&c5K
zED!AW7Se$9caq<4hGndrm+;W(HW0gKsW0Sd`dOm%_tigJHv44-)jzEs|4;P;!66F?
zmyHG;6p`@$AbhXsPYv?lS?gPStS>!+gJ#E1gIyN91p74Y0@NPRg_X;9T@naF;Y?k+
zxvb-ddZXb*BIbD5d982h9ly@NMXb#8bN
zec>fhLVeck&r+e#@Ik^5u|NZbriJ^?Ex2!1YaHXgijI(EMhX{-w`?lgy5dO9xs6Kk
zM?KpD;pnu+melX7i7T6JnnK&`>TDm=_R`jiJB1zT8`tU2IX;PAt@oW;a(2Xb!e;VP
z^cR2h9nLs_%i|{clJZuV3bwcwH0i+lYn?ZRglTwmoG&2U5&lMX$q3E*s2wrGM`&(I
z3~0wVUtCmU%-9i{pTST724Q1N{jVy4Q2sL9xu5xY&m|{*_xsY7Spd_|P6961{&=l?w&LSDQX|ibSG=;z05y?si>$?U6v7Z(Y~e
z?9cthdG~H#iM9Ag2VPlHt6z&jzLv$W=MdwsPC6$3J`>Z$&oZgelM8p$w(X?rZhv^B
zWmR$57a2XfHq2Uw9o+3V&%fRizip*hV!8i^Q!_NK=-z743i?EM*NdgtvYHvhx)-u-
z85gRa+tYJrYIavo?2_6<-NeXf^F)8gxDeIlmX=+a+v_7m*)Oc^?wa1}YqHx8UTUSt`mJtnSP=1i~E=G1;>
z!56*5ChRj#E|b2wXULMHwWpeX+>P}L>bCn63Rkr?AA2k6_2<~x5j$!(+{n*wcuikD
z+Oe;A`Gl*3W@VOdUo}g=ZbkEge~ro2BNg-Or_Z@3*DTz3Lw-DFQ}&9G@)~Q=^{MiC
z#*Dy}fA?-&=BzonsqIQ{L{o8reea>3dDhnWy$>EX9!fhA^H#UK#ZwuZx9HfRl|DaD6!Bi}y=e*drZj5v{?Qr%D5J%~
z@XEd`;yq#Vy!_`^PFbF+_ggN$E&NNG-;%#p=oyl}EE^FwN;+BLqV&64cCQhR_($>h
zxqef9Vn)uMzy4`)TEYIWj%}Ya39p*V?l>FRFgf9FjxF@&f~wso+S_WBqs~P(*xO&)
z_NwvIPi7ZfTRQ3Rly7gXKYjJ?uv@$CR<+FxzrW|5n-lJZNGDRKRb2;M-~8>=$@Sfl
z5d}?Sw(2_rQILaqeG`{Gx7iZGBdJt?`!5({Rcyx
B(Z~P*
literal 0
HcmV?d00001
diff --git a/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_non_multi_select.png b/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_non_multi_select.png
new file mode 100644
index 0000000000000000000000000000000000000000..2b23ee614fed9a0687c512b3b32e11ac2646093d
GIT binary patch
literal 2481
zcmc&$32f6=7^vd*A>4
z|Nr^DEG#T|Ej6WY3W6Z1cAK>bUM2nL)B&CYKdg4bOXq-Xs)`_8GV~(}sae+>K{{-d
zoyA(QV*)QKK7$}BE?@}z0uYTLqq4&RK`a9r>H;3wZ^3RiG-9YMS+FTa2k8jpf>PNw
zCkQ6ZDR7E&%0y1WvPYw%!aOAK0Zl-|KCfTp!xk*Y%fqq$n845&L@TpkWA%V&v7->p
zRe}ID8nSSaVvVSYGf-I!%W&fF>(`RA&@iO1Wmi
zpwiY9e1Qb5UyYXu7K{iB0fI7+dP*^%Bqnfy@}M^sToMW31wP={REVV#*g&bGDQc=X)Uyfjxj`Uk
zO3+wn;{FbM?k>=&&iWUs6Kq@JHqVtDpf3Mw2v&Qxr~_ofONn3{P?+NHb58
ztx$&|$?n++D20^INP;H(D_9bFw-WRTFlX5(cmNUbdoVOnNj_Kc
zDnS?+s$*g*91h;@S2e*e0=w0M!L$vsEb&Ip3;->damvKFaHGVUahK$FL2sIkCebap
z0BvlWZ&k!{y}A1QR-a3X2s!?aDoBvbB+)oaaU#yJtQ!|hk_%^OO5|Lk+a;Q)Hn!J;
zGW^s8@1v}`DhV=*5@ZrgG^`X$;cfs=g3-j`0?Bfs(Uir~B&!=b<`Lc|tFU{s_L#^db@S3GkoFZrG~Pe6EhFo8S(X3*n?NzMmLpgp6?R3EzN5t(vw}QN>T=tY-Cz8
zKi##Wr>oD-p4Oe|c=DR8(YEeOhb$#_7A~pDX@54SW9aln>d<=h_#X2;h1>8sQ(60P
ze!=F9rpAnXWFC^-DXD#Wawl|s$!~jXDfMUVeOGAXPwtDPefvS=NPV}8d#6@?IA)wL
zyIskbN2B`<*T#H@&aK~3^kC*yNBOkANh{cKhZY|n8Lg~E`qW(<>^XCP%{nydZLB+2
zcd+7UGA1vL*tQ%wKEnQzT9vu7IdaRE&kvOwBh&Gtl-)FF?v`sZd2ry3MUfo~2Xync
zj8E|`yP08Jwyl;cXu4E0p!)RSkFNBd+<(ZgHOG_g4x>u84_nkPZ{oa7!=^3nE_R*V
z5lo#i;nMhERmA@zad=nP$rrj7m8XlD_U3!TJ2q*@hy|lBzii>w|9qnzS_O0c&rZpY
zGuyU~eWUuDRg)amqa0ns!{ya`|M)XAeR_WLJ*s2V!&8X8A)0pg$lmwM7Ve*M6+O;@ZL8lfbZ^b!PlT)cA}6-Aym!-5RobwBhb13x>~msP&VBpdDNJd>$?%dp
zpG5}ZN4{7_-2C`@uj+osc4sNY-l=c;`$uQgc8N6pbl!HorFYuZ3u5t=K?e-ns+DKP
zA5Q7v-B5QiZ^IIMbmZ1FwYq&YH~+SAP&Ok}=C)YsIxjD&9COl_GLvNLiF21v?UoxR
zE`O^@u#5E`XJbY4J0~imp+TwVFaN$^``xPLt5XLfIY?66LAy@=(jj`O=2q16eJ}k_
Ol|8S(x;>}l-M;`B#7e3F
literal 0
HcmV?d00001
diff --git a/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_non_select.png b/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_non_select.png
new file mode 100644
index 0000000000000000000000000000000000000000..005c8784aaadba2a931829c4f1eb0dfe2ad7e682
GIT binary patch
literal 2647
zcmbVO3s4hx9^NDbI0Y{j1q8KAcoiYZCWJr&fgnLZi69`aVj(0836N||0t9?CQLn`+
z7*w=?h!_jwqbP_JtqN+iK@@x*DyS&IyO~0*ilU-&8(!0Pyv|*BW_SO)`~AP~_nzGx
zy*$i%hQka10IVazxiRQnXgV#;(W~rnSsZ%%n=Cv@0RS^?OeY4Y*kca>W<%n*L}el`
zk|jVSWWEqdhsi353`GM#K#)qt7i7aqFdfbmOWDMyKeiG
z*uv#;g2HS8Q%DR71Orqolt2P2`JhUYBUP|eY~naC3tgLDQ;6U=M48Pd2Ac%IL|!x)
zg2-Xehs+=esB|CDmr15Fyy;A)7f6GseiX=$LiHw587w-)qS3&~gNUlhg&C|E?vhC@
z^odOrDU~u7g_572PtNxyBl1iNmC0mMAR2{6BcTYAqCl$Tt4LCX^ArOYRtV%`nNo~M
zK@%fC9m!R)iKwL$E=Xk4v{J=nn9zVxRD2nQN`_1>jRS>(X`C!qo--~k6j0zCSOQCx
z3KUD7#>zy95>bed|3W?e`F8?nXnDM8jgQ(QkxWY{l%aX383WGbNNb`O{76I
zh(x85sD5!&I*abjf|#C=9}9vepgcq<&M5dOl>R#$S~5bulKcPLskfqgUC@y)GqIFeIAb$Ayp{(QUM&nWfM_{$zrjPB@pt3FyEI(g6MQA
zDFa3?d>>yXi4W140v}%nod(gT_Hz+It|_fk`-T7K{wTQ^Z7Y7xU*<72o2edH;bH}v
zse;LNh=o^Au5!fScnPrh0#j+Ti2_qjVIgtywfHYbV1hPZ1f!&XlIRJT0?AP3^W|`G
zCK|2(rIskD{S;FlPPjt(qnG2~e$%s4aC8uumeUgmeVCqMuoN9!a&$sfvx$p>I`BEY3>|iT~oj#ndWplYW?-2`;GN>)_*9a>k7lKN0R6pktX!bk&
z2F)I~40*o&7tag&z8l5I&Ln0fbPW&Yb;bR<;oqlLt?IhwegEdmJYCNaBl4MHdm1Ow
zT(ADtst7}!N5DO{y@nKHyg80{%x0+-*ER3zN!9Z_{r8^2lmiU4ci%#l`Ki5yyT;f%
zo>oBM`Yg=nZ7WNR*}1NgCM!cvGQLDp?YdYM74+TEN*s0>Cleq%hz(0Wv_NYsbC_M!
z&AL4+^B}Ig>`_f+QHkr5rP#YXOMUiGymffe$mTJ%MPKqT*y{Q7hwTAcH<=wc@9%Aa
z$ACyof7>;Sp;_&jwZ<=B4fua^X|?;hrJoqw`%*QXskolDls0DPp0)qV)wFzwc(@(g
z_{F{psko5WmYv<$)%A5)p?{`DE9M0*(Xn!O^9%jy1^(Ky`BiU!@t@}zvFwvA$UDyl
zZ29n@AvLK?!mVxAKe@TP{f>GoHfrI5*Lbfbmb$vo%`1AU-P7o9;O>Rz#(*Wnudd%L
z(jOY?hP^l?Yd0(h^x1Dxa>8(U?BMHwQWs0-t{wfI9JOJ8<=e{<_DiAyozD$|YEgoO
zvIx-C%^X^^I#px%5z9;ap-uJ=wbim}`a0yLP0^Eq8=t0~S_~Cd>^jR#mA}LnT@m>t
z7?Sb);ilRv=VF4?q6d<-N1?5I=^b8GF&aas)$OtsIPhL+`iV%;{qoA5CAj^;O|n(^H9qEzb%rQ!7j4%!=5|?D!r;>CE+xwBpg)2=txzvdf0x+X@&al^dCDd>KdLx0;ITyy6yL6NtzVfJ79Y-j#
zPAaud%8T7LSS#Ijrj-5ao*ru4TtlkTH!0J%Y$+v?7wvvHVr@D4K4pE-@vu~PLbvnN
zq;Sx&x!-spp{1hA-O))C89g-P;C>E$ZoEy+515l)BlX!<`V&I=%1dXDkQ|%k$j+Wc
zxT4yu%gx(ukJLWDpYuKSVAIuq9*tyl^uDk67;chp!s7SEAKM{6S5np#8h_(S((v7S
zXe*;(&bq>#p<}MnpQ=wMb2A?*9dxVPC^uvuu4kE@k;Hn&XBU4u7rXyNHml_R+9!=z
zXl+hKh6UVZ?2lh%x2E=fu;aIHTH@w}VmGkY%@
zPu|gYU3|N%rD{X%^&aSDZ+#^dBi7zUMiUQza9aM;J|E?)Wt5j5@y-JQw*3bkJ&so1
zZb>R$Q~B(uaWHLZ#yd}!yp)SB>!sbu{nsN{9AT?j6J5mpW+8%kghuO=m0J
z&Cg{_L;kvD=I9B}S-QABgH8vu+Ygt9h1JV9-I|5(@$gvj{#r?GpuXhlalwnhwDv>T
z0_MEqx&&wTp4Vno?HMBW(w;oOXa310F*x7p3kU1K2%*L9q149MfaOtMmB;;5Xwa1R(
ZwuNKeD7ShqqJMrsMCfvE{o=F@{{aME1YiIF
literal 0
HcmV?d00001
diff --git a/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_selection.png b/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_selection.png
new file mode 100644
index 0000000000000000000000000000000000000000..fd1d9d604231c95051f1094f865571f05d0dcda5
GIT binary patch
literal 2960
zcmV;B3vcv^P)q-KMl0i*$>W<5|db($H{08+CasF^y=3~2x<*aIzn
z9b?P^=Fr>lFa3W|Rs*XU+wk9GHC_2v!5S-NulEcY*Bw~P!N3s+yP*A!-zu<&UP4%n
z@+h#JS=_<6JQFCRGV=NX($WtD`yzZ4*lS2Vu?poj;9k1&%OTYfCAJ=bBzib77uXMY
zYg9|(nVtlG4lE^=TjRx)!#P?&F4P0*aXN5xIn6075gp1Pl4SE
zHslFl89i=cj5W++4bSi_SIaBY$~{%LU+XM&&Rk#o+>D3
zAp7tDY3n{HD}XH{m3Qm*ZG9PC`E8_(scbFX1L08UpK*4Nl=*UBMn`@T$)C$M96(xn
zBEq#%3Jc$*$2FyaFh~gp&KReld@f2)H+llUf;xTD=(nzL|5Dvyih6U9g?V9rrdI6DGxG>eHoV*EW{(D8P{!C
z%e}z6jXJC(6}N*cREh)A)~iuYF=|nY(#E>VAqyF7!Zmc{)FKrZ1Ej4Tl*Fh&={pi*
zy~W8wc8)?yN7}KK#siWW3T+3r5=KsJ154uzSqX$aVhxh_5
zwDnfBf6DijYf0r~AJKHr;{b8@8G_$*pghEX*oy`7a*T4*@|>?*vqj(h@m`eefbEd}
zzjJbU4tNgf|3APhtYE&pSX$lZ=$5>ORS56$%2f7=xlf4&WU=9L$ys1OLMjh?mG==i
zPZM{=E9?&(>m%Rj`4W_S`d74Nc%UTe45dEIR$7%o2Qu5(Y@-9kSfpkcg2nMP{P&fiHXODMoN9sl?x4
zT2~6^Qx@RO5(a4vVjOGtxypL4&4r7@_o#>AYR^sbO8
zp@94qc(dna_MvDKdZKDoyi~eW!unyN^2~JqD~~QulgeAH`q~w_Ko4e&d^5AVT9;=_&1(@xs0xu-idZV68%H}FgBbOP<)o57gQnwd={==yZ7nUIj>c_?yW$R?
zVI|Safb(*h)-%WAtzrYDt*4@VJGa6f`*X3lJ-)qUhrVyx87iO@&I~?0UZDFi*0%->
zF2ZSa!`O$(cihRVAFjeQgYV{y55B!Dg03-3qc}PGzP;q79I?
zK8mt)PGt*8<;8cTN)17vV8FvWriq4Uk0tog29n
zvs@+W0%i{LDLA6%x08y+%>Jr+{$=YWQhBYfJ$^v4rRARbPfF8{D;4kYT#($4Hq=W;x$
zEH*1Ru5Vy1f6t{CK0rr)pGRW>#Q7;L&8^6}KM!(zo{q7tU6c#VjU5G{a4{WenX7gV
z-m_Wj0c5Vv56urqOV35PJg1`PNhQ0nvz9~`0bj6^kBIJDq~d~$>?KjR3=a;4P|l+(
zR}`BeExi)qtQ;XvkV@F)QKBwn?34DEj)d}hQV9#WOZ4&FkO$=|x^i|gKob4QhS-Wh
za_%RUJ%YNdt+%87d-3`fVFeut+XW`-ym0cu9F~#FQ4Jt5u-6ulX34U{S;>;sywpPg
zsoQ3P23}h(T{O(@rd07m?PwSiB1y%kj9d0BQmx3y{_-$F)lI6kD@
zqJ(>#Y${i{7S9tnnN+;7`!+zbRC|B(fEyPfwP`px_+#^D@g_@ZK^q|1EV<8YP(Za{t;)+$mlxyRZ8Y3YRsUoU;x%D}F|x!SjU$2nhHmMi5ebmbzS0`7STApWSS
zBCe#>I$3YrH}Ou_7FW`MXev7(*+~A2H%X<^I9pGJ`$LbM+gc44V@v?1ngAdd>!jtJu%d45wMeu3QM}aCZsI`&g88)c{vN4A&%2J
zG6b)Og=t-_W6-DNO2RcRBD60YknHSW35$M_F^(!F<4EDzY~7F)6=xNSQwNBtnFyvNtp8Sy;PKN{0D1?{ZL0VE{(49vW=OdF4oury60
zNIsJ-T_M@3
z{wUX((lBN9zs!2xVF~K=sap;pu9hsdxJw#oEo)FtD |