diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 106519c..dcdbf2b 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -11,6 +11,7 @@ diff --git a/.idea/modules.xml b/.idea/modules.xml index c9f6d5e..ba83cda 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,8 +2,9 @@ - - + + + \ No newline at end of file diff --git a/DialogX/.gitignore b/DialogX/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/DialogX/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/DialogX/build.gradle b/DialogX/build.gradle new file mode 100644 index 0000000..30ea1b9 --- /dev/null +++ b/DialogX/build.gradle @@ -0,0 +1,90 @@ +apply plugin: 'com.android.library' +apply plugin: 'android-maven' + +def siteUrl = 'https://github.com/kongzue/DialogX' //项目在github主页地址 +def gitUrl = 'https://github.com/kongzue/DialogX.git' //Git仓库的地址 + +group = "com.kongzue.dialogx" + +android { + compileSdkVersion 30 + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 30 + versionCode 10 + versionName "1.0" + + consumerProguardFiles "consumer-rules.pro" + + renderscriptTargetApi 21 + renderscriptSupportModeEnabled true // Enable RS support + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +//install { +// repositories.mavenInstaller { +// // This generates POM.xml with proper parameters +// pom { +// project { +// packaging 'aar' +// name 'dialogx' +// url siteUrl +// licenses { +// license { +// name 'The Apache Software License, Version 2.0' +// url 'http://www.apache.org/licenses/LICENSE-2.0.txt' +// } +// } +// developers { +// developer { +// id 'myzchh'//设置自己ID +// name 'myzchh'//设置自己名字 +// email 'myzcxhh@live.cn'//设置自己邮箱 +// } +// } +// scm { +// connection gitUrl +// developerConnection gitUrl +// url siteUrl +// } +// } +// } +// } +//} +task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' +} + +artifacts { + archives sourcesJar +} + +//Properties properties = new Properties() +//properties.load(project.rootProject.file('local.properties').newDataInputStream()) +//bintray { +// user = properties.getProperty("bintray.user") +// key = properties.getProperty("bintray.apikey") +// configurations = ['archives'] +// pkg { +// repo = "maven" +// name = "dialogX" //项目在JCenter的名字 +// websiteUrl = siteUrl +// vcsUrl = gitUrl +// licenses = ["Apache-2.0"] +// publish = true +// } +//} +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation 'androidx.appcompat:appcompat:1.2.0+' + api files('libs\\DialogXInterface.jar') +} \ No newline at end of file diff --git a/DialogX/consumer-rules.pro b/DialogX/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/DialogX/proguard-rules.pro b/DialogX/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/DialogX/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/DialogX/src/main/AndroidManifest.xml b/DialogX/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1977b08 --- /dev/null +++ b/DialogX/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/DialogX/src/main/java/com/kongzue/dialogx/DialogX.java b/DialogX/src/main/java/com/kongzue/dialogx/DialogX.java new file mode 100644 index 0000000..f079471 --- /dev/null +++ b/DialogX/src/main/java/com/kongzue/dialogx/DialogX.java @@ -0,0 +1,131 @@ +package com.kongzue.dialogx; + +import android.content.Context; +import android.util.Log; + +import com.kongzue.dialogx.interfaces.BaseDialog; +import com.kongzue.dialogx.interfaces.DialogLifecycleCallback; +import com.kongzue.dialogx.interfaces.DialogXStyle; +import com.kongzue.dialogx.style.MaterialStyle; +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/21 17:07 + */ +public class DialogX { + + public static final String ERROR_INIT_TIPS = "DialogX.init: 初始化异常,context 为 null 或未初始化,详情请查看 https://github.com/kongzue/DialogX/wiki"; + + //开启日志 + public static boolean DEBUGMODE = true; + + //全局主题风格 + public static DialogXStyle globalStyle = MaterialStyle.style(); + + //全局对话框明暗风格 + public static DialogX.THEME globalTheme = DialogX.THEME.LIGHT; + + //TipDialog 和 WaitDialog 明暗风格,不设置则默认根据 globalTheme 定义 + public static DialogX.THEME tipTheme; + + //DialogX 实现模式(实验性功能) + public static IMPL_MODE implIMPLMode = IMPL_MODE.VIEW; + + //对话框最大宽度(像素) + public static int dialogMaxWidth; + + //是否允许 InputDialog 自动弹出键盘 + public static boolean autoShowInputKeyboard = true; + + //同时只显示一个 PopTip + public static boolean onlyOnePopTip = false; + + //默认按钮文字样式 + public static TextInfo buttonTextInfo; + + //默认确定按钮文字样式 + public static TextInfo okButtonTextInfo; + + //默认标题文字样式 + public static TextInfo titleTextInfo; + + //默认内容文字样式 + public static TextInfo messageTextInfo; + + //默认 WaitDialog 和 TipDialog 文字样式 + public static TextInfo tipTextInfo; + + //默认输入框文字样式 + public static InputInfo inputInfo; + + //默认底部菜单、对话框的标题文字样式 + public static TextInfo menuTitleInfo; + + //默认底部菜单文本样式 + public static TextInfo menuTextInfo; + + //默认对话框背景颜色(值为 ColorInt,为-1不生效) + public static int backgroundColor = -1; + + //默认 TipDialog 和 WaitDialog 背景颜色(值为 ColorInt,为-1不生效) + public static int tipBackgroundColor = -1; + + /** + * 重写 TipDialog 和 WaitDialog 进度动画颜色, + * 注意此属性为覆盖性质,即设置此值将替换提示框原本的进度动画的颜色,包括亮暗色切换的颜色变化也将被替代 + * (值为 ColorInt,为-1不生效) + */ + public static int tipProgressColor = -1; + + //默认对话框默认是否可以点击外围遮罩区域或返回键关闭,此开关不影响提示框(TipDialog)以及等待框(TipDialog) + public static boolean cancelable = true; + + //默认提示框及等待框(WaitDialog、TipDialog)默认是否可以关闭 + public static boolean cancelableTipDialog = false; + + //默认取消按钮文本文字,影响 BottomDialog + public static String cancelButtonText; + + //默认 PopTip 文本样式 + public static TextInfo popTextInfo; + + //默认启动对话框动画时长 + public static long enterAnimDuration = -1; + + //默认关闭对话框动画时长 + public static long exitAnimDuration = -1; + + //全局 Dialog 生命周期监听器 + public static DialogLifecycleCallback dialogLifeCycleListener; + + //是否自动在主线程执行 + public static boolean autoRunOnUIThread = true; + + //使用振动反馈 + public static boolean useHaptic = true; + + public enum THEME { + LIGHT, DARK, AUTO + } + + public enum IMPL_MODE { + VIEW, WINDOW + } + + public static void init(Context context) { + if (context == null) { + error(ERROR_INIT_TIPS); + return; + } + BaseDialog.init(context); + } + + public static void error(Object o) { + if (DEBUGMODE) Log.e(">>>", o.toString()); + } +} diff --git a/DialogX/src/main/java/com/kongzue/dialogx/dialogs/BottomDialog.java b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/BottomDialog.java new file mode 100644 index 0000000..1bdc856 --- /dev/null +++ b/DialogX/src/main/java/com/kongzue/dialogx/dialogs/BottomDialog.java @@ -0,0 +1,952 @@ +package com.kongzue.dialogx.dialogs; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.app.Activity; +import android.content.res.Configuration; +import android.os.Handler; +import android.os.Looper; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +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.ScrollView; +import android.widget.TextView; + +import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; +import androidx.core.view.ViewCompat; + +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.util.BottomDialogTouchEventInterceptor; +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 static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK; + +/** + * @author: Kongzue + * @github: https://github.com/kongzue/ + * @homepage: http://kongzue.com/ + * @mail: myzcxhh@live.cn + * @createTime: 2020/10/6 15:17 + */ +public class BottomDialog extends BaseDialog { + + public static int overrideEnterDuration = -1; + public static int overrideExitDuration = -1; + public static BOOLEAN overrideCancelable; + protected OnBindView onBindView; + protected CharSequence title; + protected CharSequence message; + protected CharSequence cancelText; + protected CharSequence okText; + protected CharSequence otherText; + protected boolean allowInterceptTouch = true; + protected int maskColor = -1; + protected OnDialogButtonClickListener cancelButtonClickListener; + protected OnDialogButtonClickListener okButtonClickListener; + protected OnDialogButtonClickListener otherButtonClickListener; + protected BOOLEAN privateCancelable; + + protected TextInfo titleTextInfo; + protected TextInfo messageTextInfo; + protected TextInfo cancelTextInfo = new TextInfo().setBold(true); + protected TextInfo okTextInfo = new TextInfo().setBold(true); + protected TextInfo otherTextInfo = new TextInfo().setBold(true); + + /** + * 此值用于,当禁用滑动时(style.overrideBottomDialogRes.touchSlide = false时)的最大显示高度。 + * 0:不限制,最大显示到屏幕可用高度。 + */ + protected float bottomDialogMaxHeight = 0.6f; + + protected DialogLifecycleCallback dialogLifecycleCallback; + + protected BottomDialog me = this; + + protected BottomDialog() { + super(); + } + + @Override + public String dialogKey() { + return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")"; + } + + private View dialogView; + + public static BottomDialog build() { + return new BottomDialog(); + } + + public BottomDialog(CharSequence title, CharSequence message) { + this.title = title; + this.message = message; + } + + public BottomDialog(int titleResId, int messageResId) { + this.title = getString(titleResId); + this.message = getString(messageResId); + } + + public static BottomDialog show(CharSequence title, CharSequence message) { + BottomDialog bottomDialog = new BottomDialog(title, message); + bottomDialog.show(); + return bottomDialog; + } + + public static BottomDialog show(int titleResId, int messageResId) { + BottomDialog bottomDialog = new BottomDialog(titleResId, messageResId); + bottomDialog.show(); + return bottomDialog; + } + + public BottomDialog(CharSequence title, CharSequence message, OnBindView onBindView) { + this.title = title; + this.message = message; + this.onBindView = onBindView; + } + + public BottomDialog(int titleResId, int messageResId, OnBindView onBindView) { + this.title = getString(titleResId); + this.message = getString(messageResId); + this.onBindView = onBindView; + } + + public static BottomDialog show(CharSequence title, CharSequence message, OnBindView onBindView) { + BottomDialog bottomDialog = new BottomDialog(title, message, onBindView); + bottomDialog.show(); + return bottomDialog; + } + + public static BottomDialog show(int titleResId, int messageResId, OnBindView onBindView) { + BottomDialog bottomDialog = new BottomDialog(titleResId, messageResId, onBindView); + bottomDialog.show(); + return bottomDialog; + } + + public BottomDialog(CharSequence title, OnBindView onBindView) { + this.title = title; + this.onBindView = onBindView; + } + + public BottomDialog(int titleResId, OnBindView onBindView) { + this.title = getString(titleResId); + this.onBindView = onBindView; + } + + public static BottomDialog show(CharSequence title, OnBindView onBindView) { + BottomDialog bottomDialog = new BottomDialog(title, onBindView); + bottomDialog.show(); + return bottomDialog; + } + + public static BottomDialog show(int titleResId, OnBindView onBindView) { + BottomDialog bottomDialog = new BottomDialog(titleResId, onBindView); + bottomDialog.show(); + return bottomDialog; + } + + public BottomDialog(OnBindView onBindView) { + this.onBindView = onBindView; + } + + public static BottomDialog show(OnBindView 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 0000000..feebea1 Binary files /dev/null and b/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_multi_selection.png differ 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 0000000..2b23ee6 Binary files /dev/null and b/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_non_multi_select.png differ 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 0000000..005c878 Binary files /dev/null and b/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_non_select.png differ 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 0000000..fd1d9d6 Binary files /dev/null and b/DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_selection.png differ diff --git a/DialogX/src/main/res/values/attrs.xml b/DialogX/src/main/res/values/attrs.xml new file mode 100644 index 0000000..f5aa743 --- /dev/null +++ b/DialogX/src/main/res/values/attrs.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DialogX/src/main/res/values/colors.xml b/DialogX/src/main/res/values/colors.xml new file mode 100644 index 0000000..dd3c440 --- /dev/null +++ b/DialogX/src/main/res/values/colors.xml @@ -0,0 +1,40 @@ + + + #2196F3 + + #353535 + #000 + #E6000000 + #CC000000 + #BF000000 + #B3000000 + #99000000 + #80000000 + #66000000 + #4D000000 + #40000000 + #33000000 + #1A000000 + #00000000 + + #fff + #E6ffffff + #CCffffff + #BFffffff + #B3ffffff + #99ffffff + #80ffffff + #66ffffff + #4Dffffff + #40ffffff + #33ffffff + #1Affffff + + #2196F3 + + #343434 + #F5F6F7 + #232323 + + #86B3D6 + \ No newline at end of file diff --git a/DialogX/src/main/res/values/styles.xml b/DialogX/src/main/res/values/styles.xml new file mode 100644 index 0000000..a70d270 --- /dev/null +++ b/DialogX/src/main/res/values/styles.xml @@ -0,0 +1,6 @@ + + +