对话框优化

pull/5/head
fengyuecanzhu 4 years ago
parent 1a32d43d1c
commit 5b11f21f85
  1. 1
      .idea/gradle.xml
  2. 5
      .idea/modules.xml
  3. 1
      DialogX/.gitignore
  4. 90
      DialogX/build.gradle
  5. 0
      DialogX/consumer-rules.pro
  6. 21
      DialogX/proguard-rules.pro
  7. 4
      DialogX/src/main/AndroidManifest.xml
  8. 131
      DialogX/src/main/java/com/kongzue/dialogx/DialogX.java
  9. 952
      DialogX/src/main/java/com/kongzue/dialogx/dialogs/BottomDialog.java
  10. 1065
      DialogX/src/main/java/com/kongzue/dialogx/dialogs/BottomMenu.java
  11. 477
      DialogX/src/main/java/com/kongzue/dialogx/dialogs/CustomDialog.java
  12. 407
      DialogX/src/main/java/com/kongzue/dialogx/dialogs/FullScreenDialog.java
  13. 550
      DialogX/src/main/java/com/kongzue/dialogx/dialogs/InputDialog.java
  14. 1038
      DialogX/src/main/java/com/kongzue/dialogx/dialogs/MessageDialog.java
  15. 851
      DialogX/src/main/java/com/kongzue/dialogx/dialogs/PopTip.java
  16. 162
      DialogX/src/main/java/com/kongzue/dialogx/dialogs/TipDialog.java
  17. 750
      DialogX/src/main/java/com/kongzue/dialogx/dialogs/WaitDialog.java
  18. 87
      DialogX/src/main/java/com/kongzue/dialogx/impl/ActivityLifecycleImpl.java
  19. 30
      DialogX/src/main/java/com/kongzue/dialogx/impl/AnimatorListenerEndCallBack.java
  20. 365
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/BaseDialog.java
  21. 11
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/BaseOnDialogClickCallback.java
  22. 17
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/BottomMenuListViewTouchEvent.java
  23. 19
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/DialogConvertViewInterface.java
  24. 19
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/DialogLifecycleCallback.java
  25. 12
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnBackPressedListener.java
  26. 93
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnBindView.java
  27. 16
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnDialogButtonClickListener.java
  28. 28
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnIconChangeCallBack.java
  29. 17
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnInputDialogButtonClickListener.java
  30. 12
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnMenuItemClickListener.java
  31. 37
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnMenuItemSelectListener.java
  32. 15
      DialogX/src/main/java/com/kongzue/dialogx/interfaces/OnSafeInsetsChangeListener.java
  33. 225
      DialogX/src/main/java/com/kongzue/dialogx/style/MaterialStyle.java
  34. 145
      DialogX/src/main/java/com/kongzue/dialogx/util/BottomDialogTouchEventInterceptor.java
  35. 96
      DialogX/src/main/java/com/kongzue/dialogx/util/FullScreenDialogTouchEventInterceptor.java
  36. 19
      DialogX/src/main/java/com/kongzue/dialogx/util/IOSMenuArrayAdapter.java
  37. 62
      DialogX/src/main/java/com/kongzue/dialogx/util/InputInfo.java
  38. 213
      DialogX/src/main/java/com/kongzue/dialogx/util/NormalMenuArrayAdapter.java
  39. 62
      DialogX/src/main/java/com/kongzue/dialogx/util/TextInfo.java
  40. 57
      DialogX/src/main/java/com/kongzue/dialogx/util/WindowUtil.java
  41. 124
      DialogX/src/main/java/com/kongzue/dialogx/util/views/ActivityScreenShotImageView.java
  42. 455
      DialogX/src/main/java/com/kongzue/dialogx/util/views/BlurView.java
  43. 115
      DialogX/src/main/java/com/kongzue/dialogx/util/views/BottomDialogListView.java
  44. 55
      DialogX/src/main/java/com/kongzue/dialogx/util/views/BottomDialogScrollView.java
  45. 244
      DialogX/src/main/java/com/kongzue/dialogx/util/views/DialogXBaseRelativeLayout.java
  46. 224
      DialogX/src/main/java/com/kongzue/dialogx/util/views/MaxRelativeLayout.java
  47. 452
      DialogX/src/main/java/com/kongzue/dialogx/util/views/NoArticulatedProgressView.java
  48. 475
      DialogX/src/main/java/com/kongzue/dialogx/util/views/ProgressView.java
  49. 56
      DialogX/src/main/java/com/kongzue/dialogx/util/views/RoundView.java
  50. 11
      DialogX/src/main/res/anim/anim_dialogx_bottom_enter.xml
  51. 11
      DialogX/src/main/res/anim/anim_dialogx_bottom_exit.xml
  52. 8
      DialogX/src/main/res/anim/anim_dialogx_default_alpha_enter.xml
  53. 17
      DialogX/src/main/res/anim/anim_dialogx_default_enter.xml
  54. 9
      DialogX/src/main/res/anim/anim_dialogx_default_exit.xml
  55. 11
      DialogX/src/main/res/anim/anim_dialogx_left_enter.xml
  56. 11
      DialogX/src/main/res/anim/anim_dialogx_left_exit.xml
  57. 11
      DialogX/src/main/res/anim/anim_dialogx_right_enter.xml
  58. 11
      DialogX/src/main/res/anim/anim_dialogx_right_exit.xml
  59. 11
      DialogX/src/main/res/anim/anim_dialogx_top_enter.xml
  60. 11
      DialogX/src/main/res/anim/anim_dialogx_top_exit.xml
  61. 7
      DialogX/src/main/res/drawable/button_dialogx_material_light.xml
  62. 7
      DialogX/src/main/res/drawable/button_dialogx_material_night.xml
  63. 6
      DialogX/src/main/res/drawable/rect_dialogx_material_bkg_light.xml
  64. 6
      DialogX/src/main/res/drawable/rect_dialogx_material_bkg_night.xml
  65. 11
      DialogX/src/main/res/drawable/rect_dialogx_material_bottom_bkg_light.xml
  66. 11
      DialogX/src/main/res/drawable/rect_dialogx_material_bottom_bkg_night.xml
  67. 6
      DialogX/src/main/res/drawable/rect_dialogx_material_button_light_forword.xml
  68. 6
      DialogX/src/main/res/drawable/rect_dialogx_material_button_night_forword.xml
  69. 6
      DialogX/src/main/res/drawable/rect_dialogx_material_dialogtap.xml
  70. 6
      DialogX/src/main/res/drawable/rect_dialogx_material_dialogtap_night.xml
  71. 12
      DialogX/src/main/res/drawable/rect_dialogx_material_menu_split_divider.xml
  72. 12
      DialogX/src/main/res/drawable/rect_dialogx_material_menu_split_divider_night.xml
  73. 10
      DialogX/src/main/res/drawable/rect_dialogx_material_poptip_bkg.xml
  74. 10
      DialogX/src/main/res/drawable/rect_dialogx_material_poptip_bkg_night.xml
  75. 43
      DialogX/src/main/res/layout/item_dialogx_material_bottom_menu_normal_text.xml
  76. 161
      DialogX/src/main/res/layout/layout_dialogx_bottom_material.xml
  77. 161
      DialogX/src/main/res/layout/layout_dialogx_bottom_material_dark.xml
  78. 17
      DialogX/src/main/res/layout/layout_dialogx_custom.xml
  79. 47
      DialogX/src/main/res/layout/layout_dialogx_fullscreen.xml
  80. 47
      DialogX/src/main/res/layout/layout_dialogx_fullscreen_dark.xml
  81. 160
      DialogX/src/main/res/layout/layout_dialogx_material.xml
  82. 160
      DialogX/src/main/res/layout/layout_dialogx_material_dark.xml
  83. 72
      DialogX/src/main/res/layout/layout_dialogx_poptip_material.xml
  84. 72
      DialogX/src/main/res/layout/layout_dialogx_poptip_material_dark.xml
  85. 60
      DialogX/src/main/res/layout/layout_dialogx_wait.xml
  86. BIN
      DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_multi_selection.png
  87. BIN
      DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_non_multi_select.png
  88. BIN
      DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_non_select.png
  89. BIN
      DialogX/src/main/res/mipmap-xxhdpi/img_dialogx_bottom_menu_material_item_selection.png
  90. 28
      DialogX/src/main/res/values/attrs.xml
  91. 40
      DialogX/src/main/res/values/colors.xml
  92. 6
      DialogX/src/main/res/values/styles.xml
  93. 7
      app/build.gradle
  94. 11
      app/src/main/java/xyz/fycz/myreader/application/App.java
  95. 15
      app/src/main/java/xyz/fycz/myreader/model/storage/WebDavHelp.kt
  96. 14
      app/src/main/java/xyz/fycz/myreader/ui/activity/AdSettingActivity.java
  97. 25
      app/src/main/java/xyz/fycz/myreader/ui/activity/MoreSettingActivity.java
  98. 62
      app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java
  99. 31
      app/src/main/java/xyz/fycz/myreader/ui/activity/ReplaceRuleActivity.java
  100. 43
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseAdapter.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -11,6 +11,7 @@
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/DialogX" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>

@ -2,8 +2,9 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/FYReader-master.iml" filepath="$PROJECT_DIR$/.idea/modules/FYReader-master.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/FYReader-master.app.iml" filepath="$PROJECT_DIR$/.idea/modules/app/FYReader-master.app.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/FYReader.iml" filepath="$PROJECT_DIR$/.idea/modules/FYReader.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/DialogX/FYReader.DialogX.iml" filepath="$PROJECT_DIR$/.idea/modules/DialogX/FYReader.DialogX.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/FYReader.app.iml" filepath="$PROJECT_DIR$/.idea/modules/app/FYReader.app.iml" />
</modules>
</component>
</project>

@ -0,0 +1 @@
/build

@ -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')
}

@ -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

@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kongzue.dialogx">
</manifest>

@ -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<BaseDialog> 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());
}
}

@ -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<BottomDialog> 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<BottomDialog> cancelButtonClickListener;
protected OnDialogButtonClickListener<BottomDialog> okButtonClickListener;
protected OnDialogButtonClickListener<BottomDialog> 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<BottomDialog> 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<BottomDialog> onBindView) {
this.title = title;
this.message = message;
this.onBindView = onBindView;
}
public BottomDialog(int titleResId, int messageResId, OnBindView<BottomDialog> onBindView) {
this.title = getString(titleResId);
this.message = getString(messageResId);
this.onBindView = onBindView;
}
public static BottomDialog show(CharSequence title, CharSequence message, OnBindView<BottomDialog> onBindView) {
BottomDialog bottomDialog = new BottomDialog(title, message, onBindView);
bottomDialog.show();
return bottomDialog;
}
public static BottomDialog show(int titleResId, int messageResId, OnBindView<BottomDialog> onBindView) {
BottomDialog bottomDialog = new BottomDialog(titleResId, messageResId, onBindView);
bottomDialog.show();
return bottomDialog;
}
public BottomDialog(CharSequence title, OnBindView<BottomDialog> onBindView) {
this.title = title;
this.onBindView = onBindView;
}
public BottomDialog(int titleResId, OnBindView<BottomDialog> onBindView) {
this.title = getString(titleResId);
this.onBindView = onBindView;
}
public static BottomDialog show(CharSequence title, OnBindView<BottomDialog> onBindView) {
BottomDialog bottomDialog = new BottomDialog(title, onBindView);
bottomDialog.show();
return bottomDialog;
}
public static BottomDialog show(int titleResId, OnBindView<BottomDialog> onBindView) {
BottomDialog bottomDialog = new BottomDialog(titleResId, onBindView);
bottomDialog.show();
return bottomDialog;
}
public BottomDialog(OnBindView<BottomDialog> onBindView) {
this.onBindView = onBindView;
}
public static BottomDialog show(OnBindView<BottomDialog> 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会以内容高度启动
* <p>
* 记录这个值的目的是当用户向下滑动时判断情况该回到这个位置还是关闭对话框
* 并阻止当内容高度已经完全显示时的继续向上滑动操作
*/
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<BottomDialog> getDialogLifecycleCallback() {
return dialogLifecycleCallback == null ? new DialogLifecycleCallback<BottomDialog>() {
} : dialogLifecycleCallback;
}
public BottomDialog setDialogLifecycleCallback(DialogLifecycleCallback<BottomDialog> 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<BottomDialog> cancelButtonClickListener) {
this.cancelButtonClickListener = cancelButtonClickListener;
return this;
}
public BottomDialog setCancelButton(CharSequence cancelText, OnDialogButtonClickListener<BottomDialog> cancelButtonClickListener) {
this.cancelText = cancelText;
this.cancelButtonClickListener = cancelButtonClickListener;
refreshUI();
return this;
}
public BottomDialog setCancelButton(int cancelTextResId, OnDialogButtonClickListener<BottomDialog> cancelButtonClickListener) {
this.cancelText = getString(cancelTextResId);
this.cancelButtonClickListener = cancelButtonClickListener;
refreshUI();
return this;
}
public BottomDialog setCustomView(OnBindView<BottomDialog> 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<BottomDialog> getCancelButtonClickListener() {
return cancelButtonClickListener;
}
public BottomDialog setCancelButtonClickListener(OnDialogButtonClickListener<BottomDialog> 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<BottomDialog> OkButtonClickListener) {
this.okButtonClickListener = OkButtonClickListener;
return this;
}
public BottomDialog setOkButton(CharSequence OkText, OnDialogButtonClickListener<BottomDialog> OkButtonClickListener) {
this.okText = OkText;
this.okButtonClickListener = OkButtonClickListener;
refreshUI();
return this;
}
public BottomDialog setOkButton(int OkTextResId, OnDialogButtonClickListener<BottomDialog> 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<BottomDialog> OtherButtonClickListener) {
this.otherButtonClickListener = OtherButtonClickListener;
return this;
}
public BottomDialog setOtherButton(CharSequence OtherText, OnDialogButtonClickListener<BottomDialog> OtherButtonClickListener) {
this.otherText = OtherText;
this.otherButtonClickListener = OtherButtonClickListener;
refreshUI();
return this;
}
public BottomDialog setOtherButton(int OtherTextResId, OnDialogButtonClickListener<BottomDialog> 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);
}
}

@ -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<CustomDialog> onBindView;
protected DialogLifecycleCallback<CustomDialog> 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<CustomDialog> onBindView) {
this.onBindView = onBindView;
}
public static CustomDialog show(OnBindView<CustomDialog> onBindView) {
CustomDialog customDialog = new CustomDialog(onBindView);
customDialog.show();
return customDialog;
}
public static CustomDialog show(OnBindView<CustomDialog> 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<CustomDialog> getDialogLifecycleCallback() {
return dialogLifecycleCallback == null ? new DialogLifecycleCallback<CustomDialog>() {
} : dialogLifecycleCallback;
}
public CustomDialog setDialogLifecycleCallback(DialogLifecycleCallback<CustomDialog> 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<CustomDialog> 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);
}
}

@ -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<FullScreenDialog> onBindView;
protected BOOLEAN privateCancelable;
protected DialogLifecycleCallback<FullScreenDialog> dialogLifecycleCallback;
protected FullScreenDialog me = this;
protected FullScreenDialog() {
super();
}
private View dialogView;
public static FullScreenDialog build() {
return new FullScreenDialog();
}
public FullScreenDialog(OnBindView<FullScreenDialog> onBindView) {
this.onBindView = onBindView;
}
public static FullScreenDialog show(OnBindView<FullScreenDialog> onBindView) {
FullScreenDialog fullScreenDialog = new FullScreenDialog(onBindView);
fullScreenDialog.show();
return fullScreenDialog;
}
public void show() {
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<FullScreenDialog> getDialogLifecycleCallback() {
return dialogLifecycleCallback == null ? new DialogLifecycleCallback<FullScreenDialog>() {
} : dialogLifecycleCallback;
}
public FullScreenDialog setDialogLifecycleCallback(DialogLifecycleCallback<FullScreenDialog> 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<FullScreenDialog> onBindView) {
this.onBindView = onBindView;
refreshUI();
return this;
}
public View getCustomView() {
if (onBindView == null) return null;
return onBindView.getCustomView();
}
public FullScreenDialog removeCustomView() {
this.onBindView.clean();
refreshUI();
return this;
}
public int getBackgroundColor() {
return backgroundColor;
}
public FullScreenDialog setBackgroundColor(@ColorInt int backgroundColor) {
this.backgroundColor = backgroundColor;
refreshUI();
return this;
}
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);
}
}

@ -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<InputDialog> okButtonClickListener) {
this.okButtonClickListener = okButtonClickListener;
return this;
}
public InputDialog setOkButton(CharSequence okText, OnInputDialogButtonClickListener<InputDialog> okButtonClickListener) {
this.okText = okText;
this.okButtonClickListener = okButtonClickListener;
refreshUI();
return this;
}
public InputDialog setOkButton(int okTextResId, OnInputDialogButtonClickListener<InputDialog> 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<InputDialog> cancelButtonClickListener) {
this.cancelButtonClickListener = cancelButtonClickListener;
return this;
}
public InputDialog setCancelButton(CharSequence cancelText, OnInputDialogButtonClickListener<InputDialog> cancelButtonClickListener) {
this.cancelText = cancelText;
this.cancelButtonClickListener = cancelButtonClickListener;
refreshUI();
return this;
}
public InputDialog setCancelButton(int cancelTextResId, OnInputDialogButtonClickListener<InputDialog> 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<InputDialog> otherButtonClickListener) {
this.otherButtonClickListener = otherButtonClickListener;
return this;
}
public InputDialog setOtherButton(CharSequence otherText, OnInputDialogButtonClickListener<InputDialog> otherButtonClickListener) {
this.otherText = otherText;
this.otherButtonClickListener = otherButtonClickListener;
refreshUI();
return this;
}
public InputDialog setOtherButton(int otherTextResId, OnInputDialogButtonClickListener<InputDialog> otherButtonClickListener) {
this.otherText = getString(otherTextResId);
this.otherButtonClickListener = otherButtonClickListener;
refreshUI();
return this;
}
public OnInputDialogButtonClickListener<InputDialog> getInputOkButtonClickListener() {
return (OnInputDialogButtonClickListener<InputDialog>) okButtonClickListener;
}
public InputDialog setOkButtonClickListener(OnInputDialogButtonClickListener<InputDialog> okButtonClickListener) {
this.okButtonClickListener = okButtonClickListener;
return this;
}
public OnInputDialogButtonClickListener getInputCancelButtonClickListener() {
return (OnInputDialogButtonClickListener<InputDialog>) cancelButtonClickListener;
}
public InputDialog setCancelButtonClickListener(OnInputDialogButtonClickListener<InputDialog> cancelButtonClickListener) {
this.cancelButtonClickListener = cancelButtonClickListener;
return this;
}
public OnInputDialogButtonClickListener getInputOtherButtonClickListener() {
return (OnInputDialogButtonClickListener<InputDialog>) otherButtonClickListener;
}
public InputDialog setOtherButtonClickListener(OnInputDialogButtonClickListener<InputDialog> 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<MessageDialog> 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);
}
}

@ -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<PopTip> popTipList;
protected OnBindView<PopTip> onBindView;
protected DialogLifecycleCallback<PopTip> 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<PopTip> onButtonClickListener;
protected OnDialogButtonClickListener<PopTip> 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<PopTip> 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<PopTip> onBindView) {
this.message = message;
this.onBindView = onBindView;
}
public PopTip(int messageResId, OnBindView<PopTip> onBindView) {
this.message = getString(messageResId);
this.onBindView = onBindView;
}
public PopTip(int iconResId, CharSequence message, OnBindView<PopTip> onBindView) {
this.iconResId = iconResId;
this.message = message;
this.onBindView = onBindView;
}
public PopTip(int iconResId, CharSequence message, CharSequence buttonText, OnBindView<PopTip> onBindView) {
this.iconResId = iconResId;
this.message = message;
this.buttonText = buttonText;
this.onBindView = onBindView;
}
public PopTip(int iconResId, int messageResId, int buttonTextResId, OnBindView<PopTip> onBindView) {
this.iconResId = iconResId;
this.message = getString(messageResId);
this.buttonText = getString(buttonTextResId);
this.onBindView = onBindView;
}
public PopTip(CharSequence message, CharSequence buttonText, OnBindView<PopTip> onBindView) {
this.message = message;
this.buttonText = buttonText;
this.onBindView = onBindView;
}
public PopTip(int messageResId, int buttonTextResId, OnBindView<PopTip> onBindView) {
this.message = getString(messageResId);
this.buttonText = getString(buttonTextResId);
this.onBindView = onBindView;
}
public static PopTip show(OnBindView<PopTip> 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<PopTip> onBindView) {
PopTip popTip = new PopTip(message, onBindView);
popTip.show();
return popTip;
}
public static PopTip show(int messageResId, OnBindView<PopTip> 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<PopTip> 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<PopTip> onBindView) {
PopTip popTip = new PopTip(iconResId, message, buttonText, onBindView);
popTip.show();
return popTip;
}
public static PopTip show(int iconResId, int messageResId, int buttonTextResId, OnBindView<PopTip> onBindView) {
PopTip popTip = new PopTip(iconResId, messageResId, buttonTextResId, onBindView);
popTip.show();
return popTip;
}
public static PopTip show(CharSequence message, CharSequence buttonText, OnBindView<PopTip> onBindView) {
PopTip popTip = new PopTip(message, buttonText, onBindView);
popTip.show();
return popTip;
}
public static PopTip show(int messageResId, int buttonTextResId, OnBindView<PopTip> 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<PopTip> getDialogLifecycleCallback() {
return dialogLifecycleCallback == null ? new DialogLifecycleCallback<PopTip>() {
} : dialogLifecycleCallback;
}
public PopTip setDialogLifecycleCallback(DialogLifecycleCallback<PopTip> 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<PopTip> 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<PopTip> onButtonClickListener) {
this.buttonText = buttonText;
this.onButtonClickListener = onButtonClickListener;
refreshUI();
return this;
}
public PopTip setButton(int buttonTextResId, OnDialogButtonClickListener<PopTip> onButtonClickListener) {
this.buttonText = getString(buttonTextResId);
this.onButtonClickListener = onButtonClickListener;
refreshUI();
return this;
}
public PopTip setButton(OnDialogButtonClickListener<PopTip> 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<PopTip> getOnButtonClickListener() {
return onButtonClickListener;
}
public PopTip setOnButtonClickListener(OnDialogButtonClickListener<PopTip> onButtonClickListener) {
this.onButtonClickListener = onButtonClickListener;
return this;
}
public boolean isAutoTintIconInLightOrDarkMode() {
return autoTintIconInLightOrDarkMode;
}
public PopTip setAutoTintIconInLightOrDarkMode(boolean autoTintIconInLightOrDarkMode) {
this.autoTintIconInLightOrDarkMode = autoTintIconInLightOrDarkMode;
refreshUI();
return this;
}
public OnDialogButtonClickListener<PopTip> getOnPopTipClickListener() {
return onPopTipClickListener;
}
public PopTip setOnPopTipClickListener(OnDialogButtonClickListener<PopTip> 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);
}
}

@ -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()) + ")";
}
}

@ -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<WaitDialog> onBindView;
public enum TYPE {
NONE,
SUCCESS,
WARNING,
ERROR
}
protected static WeakReference<WaitDialog> 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<WaitDialog> 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<WaitDialog> getDialogLifecycleCallback() {
return dialogLifecycleCallback == null ? new DialogLifecycleCallback<WaitDialog>() {
} : dialogLifecycleCallback;
}
public WaitDialog setDialogLifecycleCallback(DialogLifecycleCallback<WaitDialog> dialogLifecycleCallback) {
this.dialogLifecycleCallback = dialogLifecycleCallback;
if (isShow) dialogLifecycleCallback.onShow(me.get());
return this;
}
public DialogImpl getDialogImpl() {
return dialogImpl;
}
public WaitDialog setCustomView(OnBindView<WaitDialog> 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();
}
}

@ -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);
}
}

@ -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) {
}
}

@ -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<FrameLayout> rootFrameLayout;
private static WeakReference<Activity> contextWeakReference;
protected WeakReference<Activity> ownActivity;
private static List<BaseDialog> runningDialogList;
private WeakReference<View> 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<BaseDialog> copyOnWriteList = new CopyOnWriteArrayList<>(runningDialogList);
for (BaseDialog baseDialog : copyOnWriteList) {
if (baseDialog.getActivity() == activity && baseDialog.dialogView != null) {
WindowUtil.dismiss(baseDialog.dialogView.get());
}
}
}
}
}
}

@ -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 {
}

@ -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){};
}

@ -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);
}

@ -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<T extends BaseDialog> {
public void onShow(T dialog){
}
public void onDismiss(T dialog){
}
}

@ -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();
}

@ -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<D> {
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<D> setLayoutResId(int layoutResId) {
this.layoutResId = layoutResId;
return this;
}
public View getCustomView() {
return customView;
}
public OnBindView<D> setCustomView(View customView) {
this.customView = customView;
return this;
}
public void clean() {
layoutResId = 0;
customView = null;
}
public OnBindView<D> 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<D> 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;
}
}

@ -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<D extends BaseDialog> extends BaseOnDialogClickCallback{
boolean onClick(D baseDialog, View v);
}

@ -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;
}
}

@ -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<D extends BaseDialog> extends BaseOnDialogClickCallback{
boolean onClick(D baseDialog, View v, String inputStr);
}

@ -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<D> {
boolean onClick(D dialog, CharSequence text, int which);
}

@ -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<D> implements OnMenuItemClickListener<D> {
/**
* 警告不建议重写此方法
* 如果选择使用 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) {
}
}

@ -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);
}

@ -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;
}
};
}
}

@ -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;
/**
* 0bkg接收触控事件-1scrollView进行滚动
* 此标记的意义在于当从 [scrollView滚动] [bkg接收触控事件] 状态切换时
* 需要对bkgTouchDownYscrolledY的值进行刷新否则触控连续过程会出现闪跳
*/
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);
}
}

@ -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);
}
}

@ -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<CharSequence> {
public IOSMenuArrayAdapter(@NonNull Context context, int resource) {
super(context, resource);
}
}

@ -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;
}
}

@ -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<CharSequence> objects;
public Context context;
public NormalMenuArrayAdapter(BottomMenu bottomMenu, Context context, List<CharSequence> 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);
}
}

@ -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 +
'}';
}
}

@ -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);
}
}
}

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

@ -0,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());
}
}

@ -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;
}
}

@ -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);
}
}

@ -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);
}
}

@ -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);
}
}

@ -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);
}
}

@ -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);
}
}

@ -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;
}
}

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromYDelta="100%p"
android:toYDelta="0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromYDelta="0"
android:toYDelta="100%p"/>
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0"/>
</set>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="300"
android:fromXScale="0.9"
android:fromYScale="0.9"
android:pivotX="50%"
android:pivotY="60%"
android:toXScale="1.0"
android:toYScale="1.0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="-100%p"
android:toXDelta="0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0"
android:toXDelta="-100%p"/>
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0"/>
</set>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="100%p"
android:toXDelta="0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0"
android:toXDelta="100%p"/>
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0"/>
</set>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromYDelta="-100%p"
android:toYDelta="0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromYDelta="0"
android:toYDelta="-100%p"/>
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0"/>
</set>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="@color/black10">
<item android:drawable="@drawable/rect_dialogx_material_button_light_forword"/>
</ripple>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="@color/white10">
<item android:drawable="@drawable/rect_dialogx_material_button_night_forword"/>
</ripple>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<corners android:radius="10dp" />
</shape>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/dialogxMaterialDarkDialogBkgColor"/>
<corners android:radius="10dp" />
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!--left to right-->
<solid
android:color="@color/white"/>
<corners
android:topRightRadius="10dp"
android:topLeftRadius="10dp"/>
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!--left to right-->
<solid
android:color="@color/dialogxMaterialDarkDialogBkgColor"/>
<corners
android:topRightRadius="10dp"
android:topLeftRadius="10dp"/>
</shape>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<corners android:radius="3dp" />
</shape>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/dialogxMaterialDarkDialogBkgColor"/>
<corners android:radius="3dp" />
</shape>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/black10"/>
<corners android:radius="99dp" />
</shape>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white10"/>
<corners android:radius="99dp" />
</shape>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:left="15dp"
android:right="15dp">
<shape android:shape="rectangle" >
<solid android:color="@color/black10" />
</shape>
</item>
</layer-list>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:left="25dp"
android:right="25dp">
<shape android:shape="rectangle" >
<solid android:color="@color/white10" />
</shape>
</item>
</layer-list>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!--left to right-->
<solid
android:color="@color/white"/>
<corners
android:radius="5dp"/>
</shape>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!--left to right-->
<solid
android:color="@color/dialogxMaterialDarkDialogBkgColor"/>
<corners
android:radius="5dp"/>
</shape>

@ -0,0 +1,43 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp">
<ImageView
android:id="@+id/img_dialogx_menu_icon"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginLeft="-5dp"
android:layout_marginRight="10dp"
android:padding="5dp" />
<ImageView
android:id="@+id/img_dialogx_menu_selection"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_centerVertical="true"
android:layout_marginLeft="-5dp"
android:layout_marginRight="10dp"
android:padding="5dp"
android:src="@mipmap/img_dialogx_bottom_menu_material_item_selection" />
<TextView
android:id="@+id/txt_dialogx_menu_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="left|center_vertical"
android:maxLines="1"
android:text=""
android:textColor="@color/black90"
android:textSize="16dp" />
</LinearLayout>
</RelativeLayout>

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/box_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black20"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/box_bkg"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.kongzue.dialogx.util.views.MaxRelativeLayout
android:id="@+id/bkg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/rect_dialogx_material_bottom_bkg_light"
android:clickable="true"
android:focusableInTouchMode="true">
<ImageView
android:id="@+id/img_tab"
android:layout_width="30dp"
android:layout_height="4dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:src="@drawable/rect_dialogx_material_dialogtap" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="15dp">
<TextView
android:id="@+id/txt_dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingBottom="10dp"
android:text="Title"
android:textColor="@color/black"
android:textSize="21dp" />
<com.kongzue.dialogx.util.views.BottomDialogScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:overScrollMode="never"
android:scrollbarSize="7dp"
android:scrollbars="vertical">
<LinearLayout
android:id="@+id/box_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/txt_dialog_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:paddingBottom="5dp"
android:text="This is content text."
android:textColor="@color/black70"
android:textSize="16dp" />
<RelativeLayout
android:id="@+id/box_custom"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:id="@+id/box_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</com.kongzue.dialogx.util.views.BottomDialogScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="right|center_vertical"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<TextView
android:id="@+id/btn_selectOther"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@drawable/button_dialogx_material_light"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="Other"
android:textColor="@color/colorAccent"
android:textSize="15dp"
android:visibility="gone" />
<Space
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/btn_selectNegative"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@drawable/button_dialogx_material_light"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:tag="cancel"
android:text="Cancel"
android:textColor="@color/colorAccent"
android:textSize="15dp" />
<TextView
android:id="@+id/btn_selectPositive"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@drawable/button_dialogx_material_light"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="OK"
android:textColor="@color/colorAccent"
android:textSize="15dp" />
</LinearLayout>
</LinearLayout>
</com.kongzue.dialogx.util.views.MaxRelativeLayout>
</RelativeLayout>
</com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/box_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black40"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/box_bkg"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.kongzue.dialogx.util.views.MaxRelativeLayout
android:id="@+id/bkg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/rect_dialogx_material_bottom_bkg_night"
android:clickable="true"
android:focusableInTouchMode="true">
<ImageView
android:id="@+id/img_tab"
android:layout_width="30dp"
android:layout_height="4dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:layout_marginBottom="1dp"
android:src="@drawable/rect_dialogx_material_dialogtap_night" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="15dp">
<TextView
android:id="@+id/txt_dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingBottom="10dp"
android:text="Title"
android:textColor="@color/white"
android:textSize="21dp" />
<com.kongzue.dialogx.util.views.BottomDialogScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:overScrollMode="never"
android:scrollbarSize="7dp"
android:scrollbars="vertical">
<LinearLayout
android:id="@+id/box_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/txt_dialog_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:paddingBottom="5dp"
android:text="This is content text."
android:textColor="@color/white60"
android:textSize="16dp" />
<RelativeLayout
android:id="@+id/box_custom"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:id="@+id/box_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</com.kongzue.dialogx.util.views.BottomDialogScrollView>
<LinearLayout
android:id="@+id/box_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="right|center_vertical"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@drawable/button_dialogx_material_night"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="Other"
android:textColor="@color/colorAccent"
android:textSize="15dp"
android:visibility="gone" />
<Space
android:id="@+id/space_other_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@drawable/button_dialogx_material_night"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:tag="cancel"
android:text="Cancel"
android:textColor="@color/colorAccent"
android:textSize="15dp" />
<TextView
android:id="@+id/btn_selectPositive"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@drawable/button_dialogx_material_night"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="OK"
android:textColor="@color/colorAccent"
android:textSize="15dp" />
</LinearLayout>
</LinearLayout>
</com.kongzue.dialogx.util.views.MaxRelativeLayout>
</RelativeLayout>
</com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/box_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/box_custom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:clickable="true">
</RelativeLayout>
</com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>

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

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

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/box_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black20"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.kongzue.dialogx.util.views.MaxRelativeLayout
android:id="@+id/bkg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:background="@drawable/rect_dialogx_material_bkg_light"
android:elevation="27dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:orientation="vertical">
<TextView
android:id="@+id/txt_dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:paddingTop="15dp"
android:paddingRight="20dp"
android:paddingBottom="15dp"
android:text="Title"
android:textColor="@color/black"
android:textSize="21dp" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/txt_dialog_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="This is content text."
android:textColor="@color/black70"
android:textSize="16dp" />
<RelativeLayout
android:id="@+id/box_custom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<EditText
android:id="@+id/txt_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp"
android:layout_marginRight="20dp"
android:inputType="text"
android:maxLines="1"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:scrollbars="vertical"
android:text=""
android:textColor="@color/black90"
android:textSize="18dp"
android:theme="@style/DialogXCompatThemeLight" />
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="@+id/box_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="5dp"
android:gravity="right|center_vertical"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingRight="10dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/btn_selectOther"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="@drawable/button_dialogx_material_light"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="Other"
android:textColor="@color/colorAccent"
android:textSize="15dp"
android:visibility="gone" />
<Space
android:id="@+id/space_other_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/btn_selectNegative"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="@drawable/button_dialogx_material_light"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="Cancel"
android:textColor="@color/colorAccent"
android:textSize="15dp" />
<TextView
android:id="@+id/btn_selectPositive"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="@drawable/button_dialogx_material_light"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="OK"
android:textColor="@color/colorAccent"
android:textSize="15dp" />
</LinearLayout>
</LinearLayout>
</com.kongzue.dialogx.util.views.MaxRelativeLayout>
</RelativeLayout>
</com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/box_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black40"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.kongzue.dialogx.util.views.MaxRelativeLayout
android:id="@+id/bkg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:background="@drawable/rect_dialogx_material_bkg_night"
android:elevation="27dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:orientation="vertical">
<TextView
android:id="@+id/txt_dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:paddingTop="15dp"
android:paddingRight="20dp"
android:paddingBottom="15dp"
android:text="Title"
android:textColor="@color/white"
android:textSize="21dp" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/txt_dialog_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="This is content text."
android:textColor="@color/white60"
android:textSize="16dp" />
<RelativeLayout
android:id="@+id/box_custom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<EditText
android:id="@+id/txt_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp"
android:layout_marginRight="20dp"
android:inputType="text"
android:maxLines="1"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:scrollbars="vertical"
android:text=""
android:textColor="@color/white"
android:textSize="18dp"
android:theme="@style/DialogXCompatThemeDark" />
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="@+id/box_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="5dp"
android:gravity="right|center_vertical"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingRight="10dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/btn_selectOther"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="@drawable/button_dialogx_material_night"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="Other"
android:textColor="@color/colorAccent"
android:textSize="15dp"
android:visibility="gone" />
<Space
android:id="@+id/space_other_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/btn_selectNegative"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="@drawable/button_dialogx_material_night"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="Cancel"
android:textColor="@color/colorAccent"
android:textSize="15dp" />
<TextView
android:id="@+id/btn_selectPositive"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="@drawable/button_dialogx_material_night"
android:clickable="true"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="OK"
android:textColor="@color/colorAccent"
android:textSize="15dp" />
</LinearLayout>
</LinearLayout>
</com.kongzue.dialogx.util.views.MaxRelativeLayout>
</RelativeLayout>
</com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/box_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:baseFocusable="false">
<LinearLayout
android:id="@+id/box_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:layout_marginBottom="100dp"
android:background="@drawable/rect_dialogx_material_poptip_bkg"
android:elevation="20dp"
android:gravity="center_vertical"
android:minHeight="50dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/img_dialogx_pop_icon"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="-5dp"
android:visibility="gone" />
<TextView
android:id="@+id/txt_dialogx_pop_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="10dp"
android:gravity="left|center_vertical"
android:text="Sure?"
android:textColor="@color/black"
android:textSize="14dp" />
<RelativeLayout
android:id="@+id/box_custom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<TextView
android:id="@+id/txt_dialogx_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="-15dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:background="@drawable/button_dialogx_material_light"
android:gravity="left|center_vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"
android:text="Dismiss"
android:textColor="@color/dialogxColorBlue"
android:textSize="14dp"
android:visibility="gone" />
</LinearLayout>
</com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/box_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:baseFocusable="false">
<LinearLayout
android:id="@+id/box_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:layout_marginBottom="100dp"
android:background="@drawable/rect_dialogx_material_poptip_bkg_night"
android:elevation="10dp"
android:gravity="center_vertical"
android:minHeight="50dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/img_dialogx_pop_icon"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="-5dp"
android:visibility="gone" />
<TextView
android:id="@+id/txt_dialogx_pop_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="10dp"
android:gravity="left|center_vertical"
android:text="Sure?"
android:textColor="@color/white"
android:textSize="14dp" />
<RelativeLayout
android:id="@+id/box_custom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<TextView
android:id="@+id/txt_dialogx_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="-15dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:background="@drawable/button_dialogx_material_night"
android:gravity="left|center_vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"
android:text="Dismiss"
android:textColor="@color/dialogxPopButtonBlueDark"
android:textSize="14dp"
android:visibility="gone" />
</LinearLayout>
</com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/box_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black40"
android:orientation="vertical">
<com.kongzue.dialogx.util.views.MaxRelativeLayout
android:id="@+id/bkg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:minWidth="125dp"
android:minHeight="125dp">
<com.kongzue.dialogx.util.views.BlurView
android:id="@+id/blurView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tag="blurView" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:paddingTop="1.5dp"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/box_progress"
android:layout_width="65dp"
android:layout_height="65dp"/>
<RelativeLayout
android:id="@+id/box_customView"
android:layout_width="65dp"
android:layout_height="65dp"
android:visibility="gone" />
<TextView
android:id="@+id/txt_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:layout_marginRight="15dp"
android:gravity="center"
android:maxLines="3"
android:text="Please Wait"
android:textColor="@color/white"
android:textSize="14dp" />
</LinearLayout>
</com.kongzue.dialogx.util.views.MaxRelativeLayout>
</com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MaxRelativeLayout">
<attr name="maxLayoutWidth" format="dimension"/>
<attr name="maxLayoutHeight" format="dimension"/>
<attr name="lockWidth" format="boolean"/>
<attr name="interceptTouch" format="boolean"/>
</declare-styleable>
<declare-styleable name="RealtimeBlurView">
<attr name="realtimeBlurRadius" format="dimension"/>
<attr name="realtimeDownsampleFactor" format="float"/>
<attr name="realtimeOverlayColor" format="color"/>
<attr name="radius" format="dimension"/>
</declare-styleable>
<declare-styleable name="ProgressView">
<attr name="progressStrokeWidth" format="dimension"/>
<attr name="progressStrokeColor" format="color"/>
</declare-styleable>
<declare-styleable name="DialogXBaseRelativeLayout">
<attr name="baseFocusable" format="boolean"/>
</declare-styleable>
</resources>

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorAccent">#2196F3</color>
<color name="dark">#353535</color>
<color name="black">#000</color>
<color name="black90">#E6000000</color>
<color name="black80">#CC000000</color>
<color name="black75">#BF000000</color>
<color name="black70">#B3000000</color>
<color name="black60">#99000000</color>
<color name="black50">#80000000</color>
<color name="black40">#66000000</color>
<color name="black30">#4D000000</color>
<color name="black25">#40000000</color>
<color name="black20">#33000000</color>
<color name="black10">#1A000000</color>
<color name="empty">#00000000</color>
<color name="white">#fff</color>
<color name="white90">#E6ffffff</color>
<color name="white80">#CCffffff</color>
<color name="white75">#BFffffff</color>
<color name="white70">#B3ffffff</color>
<color name="white60">#99ffffff</color>
<color name="white50">#80ffffff</color>
<color name="white40">#66ffffff</color>
<color name="white30">#4Dffffff</color>
<color name="white25">#40ffffff</color>
<color name="white20">#33ffffff</color>
<color name="white10">#1Affffff</color>
<color name="dialogxColorBlue">#2196F3</color>
<color name="dialogxMaterialDarkDialogBkgColor">#343434</color>
<color name="dialogxWaitBkgLight">#F5F6F7</color>
<color name="dialogxWaitBkgDark">#232323</color>
<color name="dialogxPopButtonBlueDark">#86B3D6</color>
</resources>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DialogXCompatThemeLight" parent="Theme.AppCompat.Light.NoActionBar"/>
<style name="DialogXCompatThemeDark" parent="Theme.AppCompat.NoActionBar"/>
</resources>

@ -99,7 +99,11 @@ android {
}
productFlavors {
}
packagingOptions {
// pickFirsts:使apk
pickFirst 'lib/*/libRSSupport.so'
pickFirst 'lib/*/librsjni.so'
}
}
@ -112,6 +116,7 @@ repositories {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation project(path: ':DialogX')
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

@ -25,6 +25,7 @@ import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import com.kongzue.dialogx.DialogX;
import com.liulishuo.filedownloader.FileDownloader;
import com.liulishuo.filedownloader.connection.FileDownloadUrlConnection;
@ -97,8 +98,10 @@ public class App extends Application {
mFixedThreadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());//初始化线程池
initNightTheme();
// LLog.init(APPCONST.LOG_DIR);
initDialogX();
}
private void firstInit() {
SharedPreUtils sru = SharedPreUtils.getInstance();
if (!sru.getBoolean("firstInit")) {
@ -107,14 +110,22 @@ public class App extends Application {
}
}
private void initDialogX() {
DialogX.init(this);
DialogX.DEBUGMODE = debug;
}
public void initNightTheme() {
if (isNightFS()) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
DialogX.globalTheme = DialogX.THEME.AUTO;
} else {
if (isNightTheme()) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
DialogX.globalTheme = DialogX.THEME.DARK;
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
DialogX.globalTheme = DialogX.THEME.LIGHT;
}
}
}

@ -3,11 +3,14 @@ package xyz.fycz.myreader.model.storage
import android.content.Context
import android.os.Handler
import android.os.Looper
import com.kongzue.dialogx.dialogs.BottomMenu
import com.kongzue.dialogx.interfaces.OnMenuItemClickListener
import io.reactivex.Single
import io.reactivex.SingleOnSubscribe
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.jetbrains.anko.selector
import xyz.fycz.myreader.R
import xyz.fycz.myreader.base.observer.MySingleObserver
import xyz.fycz.myreader.common.APPCONST
import xyz.fycz.myreader.util.SharedPreUtils
@ -68,11 +71,21 @@ object WebDavHelp {
fun showRestoreDialog(context: Context, names: ArrayList<String>, callBack: Restore.CallBack?): Boolean {
return if (names.isNotEmpty()) {
context.selector(title = "选择恢复文件", items = names) { _, index ->
/*context.selector(title = "选择恢复文件", items = names) { _, index ->
if (index in 0 until 30.coerceAtLeast(names.size)) {
restoreWebDav(names[index], callBack)
}
}*/
BottomMenu.build().setTitle("选择恢复文件")
.setMenuStringList(names)
.setOnMenuItemClickListener { dialog, text, which ->
if (which in 0 until 30.coerceAtLeast(names.size)) {
restoreWebDav(names[which], callBack)
}
false
}
.setCancelButton(R.string.cancel)
.show()
true
} else {
false

@ -5,6 +5,8 @@ import android.view.View;
import androidx.appcompat.widget.Toolbar;
import com.kongzue.dialogx.dialogs.BottomMenu;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import xyz.fycz.myreader.R;
@ -116,14 +118,22 @@ public class AdSettingActivity extends BaseActivity {
checked = i;
}
}
MyAlertDialog.build(AdSettingActivity.this)
/*MyAlertDialog.build(AdSettingActivity.this)
.setTitle(getString(R.string.splash_ad_times))
.setSingleChoiceItems(adTimes, checked, (dialog, which) -> {
curAdTimes = ints[which];
spu.putInt("curAdTimes", curAdTimes);
binding.tvSplashCurAdTimes.setText(getString(R.string.splash_cur_ad_times, adTimes[which], curAdCount + "次"));
dialog.dismiss();
}).setNegativeButton("取消", null).show();
}).setNegativeButton("取消", null).show();*/
BottomMenu.show(getString(R.string.splash_ad_times), adTimes)
.setSelection(checked)
.setOnMenuItemClickListener((dialog, text, which) -> {
curAdTimes = ints[which];
spu.putInt("curAdTimes", curAdTimes);
binding.tvSplashCurAdTimes.setText(getString(R.string.splash_cur_ad_times, adTimes[which], curAdCount + "次"));
return false;
}).setCancelButton(R.string.cancel);
}
@Override

@ -17,6 +17,8 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.FragmentTransaction;
import com.kongzue.dialogx.dialogs.BottomMenu;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
@ -280,7 +282,7 @@ public class MoreSettingActivity extends BaseActivity {
);
binding.llBookSort.setOnClickListener(v -> {
MyAlertDialog.build(this)
/*MyAlertDialog.build(this)
.setTitle(getString(R.string.book_sort))
.setSingleChoiceItems(R.array.book_sort, sortStyle, (dialog, which) -> {
sortStyle = which;
@ -298,7 +300,26 @@ public class MoreSettingActivity extends BaseActivity {
binding.tvBookSort.setText(getString(R.string.book_name_sort));
}
dialog.dismiss();
}).setNegativeButton("取消", null).show();
}).setNegativeButton("取消", null).show();*/
BottomMenu.show(getString(R.string.book_sort), getResources().getStringArray(R.array.book_sort))
.setSelection(sortStyle)
.setOnMenuItemClickListener((dialog, text, which) -> {
sortStyle = which;
mSetting.setSortStyle(sortStyle);
SysManager.saveSetting(mSetting);
if (sortStyle == 0) {
binding.tvBookSort.setText(getString(R.string.manual_sort));
if (!SharedPreUtils.getInstance().getBoolean("manualSortTip")) {
DialogCreator.createTipDialog(this, "可在书架编辑状态下长按移动书籍进行排序!");
SharedPreUtils.getInstance().putBoolean("manualSortTip", true);
}
} else if (sortStyle == 1) {
binding.tvBookSort.setText(getString(R.string.time_sort));
} else if (sortStyle == 2) {
binding.tvBookSort.setText(getString(R.string.book_name_sort));
}
return false;
}).setCancelButton(R.string.cancel);
});
binding.rlPrivateBookcase.setOnClickListener(v -> {

@ -39,6 +39,10 @@ import androidx.core.content.ContextCompat;
import com.gyf.immersionbar.ImmersionBar;
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
import com.kongzue.dialogx.dialogs.BottomDialog;
import com.kongzue.dialogx.dialogs.BottomMenu;
import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener;
import com.kongzue.dialogx.interfaces.OnMenuItemSelectListener;
import org.jetbrains.annotations.NotNull;
@ -1555,7 +1559,7 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe
return;
}
App.runOnUiThread(() -> {
MyAlertDialog.build(this)
/*MyAlertDialog.build(this)
.setTitle("缓存书籍")
.setSingleChoiceItems(getResources().getStringArray(R.array.download), selectedIndex,
(dialog, which) -> selectedIndex = which).setNegativeButton("取消", ((dialog, which) -> dialog.dismiss())).setPositiveButton("确定",
@ -1574,7 +1578,31 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe
addDownload(0, mChapters.size());
break;
}
}).show();
}).show();*/
BottomMenu.show("缓存书籍", getResources().getStringArray(R.array.download))
.setSelection(selectedIndex)
.setOnMenuItemClickListener(new OnMenuItemSelectListener<BottomMenu>() {
@Override
public void onOneItemSelect(BottomMenu dialog, CharSequence text, int which) {
selectedIndex = which;
}
}).setOkButton("确定", (baseDialog, v) -> {
switch (selectedIndex) {
case 0:
addDownload(mPageLoader.getChapterPos(), mPageLoader.getChapterPos() + 50);
break;
case 1:
addDownload(mPageLoader.getChapterPos() - 50, mPageLoader.getChapterPos() + 50);
break;
case 2:
addDownload(mPageLoader.getChapterPos(), mChapters.size());
break;
case 3:
addDownload(0, mChapters.size());
break;
}
return false;
}).setCancelButton(R.string.cancel);
});
}
@ -1952,7 +1980,7 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe
break;
case 3:
selectString = StringUtils.deleteWhitespace(binding.readPvContent.getSelectStr());
MyAlertDialog.build(ReadActivity.this)
/*MyAlertDialog.build(ReadActivity.this)
.setTitle(R.string.search)
.setItems(R.array.search_way, (dialog, which) -> {
String url = "";
@ -1978,7 +2006,33 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe
ToastUtils.showError(e.getLocalizedMessage());
}
}).setNegativeButton("取消", null)
.show();
.show();*/
BottomMenu.show(R.string.search, getResources().getStringArray(R.array.search_way))
.setOnMenuItemClickListener((dialog, text, which) -> {
String url = "";
switch (which) {
case 0:
url = URLCONST.BAI_DU_SEARCH;
break;
case 1:
url = URLCONST.GOOGLE_SEARCH;
break;
case 2:
url = URLCONST.YOU_DAO_SEARCH;
break;
}
url = url.replace("{key}", selectString);
Log.d("SEARCH_URL", url);
try {
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showError(e.getLocalizedMessage());
}
return false;
}).setCancelButton(R.string.cancel);
clearSelect();
break;
case 4:

@ -17,6 +17,8 @@ import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.kongzue.dialogx.dialogs.BottomMenu;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -187,7 +189,7 @@ public class ReplaceRuleActivity extends BaseActivity {
});
replaceDialog.show(getSupportFragmentManager(), "replaceRule");
} else if (itemId == R.id.action_import) {
MyAlertDialog.build(this)
/*MyAlertDialog.build(this)
.setTitle("导入规则")
.setItems(R.array.import_rule, (dialog, which) -> {
if (which == 0) {
@ -211,7 +213,32 @@ public class ReplaceRuleActivity extends BaseActivity {
(dialog1, which1) -> importDataS(url[0]));
}
}).show();
}).show();*/
BottomMenu.show("导入规则", getResources().getStringArray(R.array.import_rule))
.setOnMenuItemClickListener((dialog, text, which) -> {
if (which == 0) {
String pasteText = ClipBoardUtil.paste(this);
if (!isEmpty(pasteText)) {
importDataS(pasteText);
} else {
ToastUtils.showError("剪切板内容为空,导入失败");
}
} else if (which == 1) {
ToastUtils.showInfo("请选择内容替换规则JSON文件");
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/json");
startActivityForResult(intent, APPCONST.REQUEST_IMPORT_REPLACE_RULE);
} else {
String[] url = new String[1];
MyAlertDialog.createInputDia(this, "网络导入",
"请输入网址", "", true, 200,
text0 -> url[0] = text0,
(dialog1, which1) -> importDataS(url[0]));
}
return false;
}).setCancelButton(R.string.cancel);
} else if (itemId == R.id.action_export) {
if (mReplaceRules == null || mReplaceRules.size() == 0) {
ToastUtils.showWarring("当前没有任何规则,无法导出!");

@ -1,8 +1,14 @@
package xyz.fycz.myreader.ui.adapter;
import android.content.Context;
import android.view.View;
import android.widget.*;
import com.kongzue.dialogx.dialogs.BottomDialog;
import com.kongzue.dialogx.dialogs.BottomMenu;
import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener;
import com.kongzue.dialogx.interfaces.OnMenuItemSelectListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
@ -274,7 +280,7 @@ public abstract class BookcaseAdapter extends DragAdapter {
}
final int[] begin = new int[1];
final int[] end = new int[1];
MyAlertDialog.build(mContext)
/*MyAlertDialog.build(mContext)
.setTitle("缓存书籍")
.setSingleChoiceItems(mContext.getResources().getStringArray(R.array.download), selectedIndex,
(dialog, which) -> selectedIndex = which).setNegativeButton("取消", ((dialog, which) -> dialog.dismiss())).setPositiveButton("确定",
@ -302,7 +308,40 @@ public abstract class BookcaseAdapter extends DragAdapter {
mBookcasePresenter.addDownload(book, chapters, begin[0], end[0], false);
});
mBookcasePresenter.getEs().submit(downloadThread);
}).show();
}).show();*/
BottomMenu.show("缓存书籍", mContext.getResources().getStringArray(R.array.download))
.setSelection(selectedIndex)
.setOnMenuItemClickListener(new OnMenuItemSelectListener<BottomMenu>() {
@Override
public void onOneItemSelect(BottomMenu dialog, CharSequence text, int which) {
selectedIndex = which;
}
}).setOkButton("确定", (baseDialog, v) -> {
switch (selectedIndex) {
case 0:
begin[0] = book.getHisttoryChapterNum();
end[0] = book.getHisttoryChapterNum() + 50;
break;
case 1:
begin[0] = book.getHisttoryChapterNum() - 50;
end[0] = book.getHisttoryChapterNum() + 50;
break;
case 2:
begin[0] = book.getHisttoryChapterNum();
end[0] = 99999;
break;
case 3:
begin[0] = 0;
end[0] = 99999;
break;
}
Thread downloadThread = new Thread(() -> {
ArrayList<Chapter> chapters = (ArrayList<Chapter>) mChapterService.findBookAllChapterByBookId(book.getId());
mBookcasePresenter.addDownload(book, chapters, begin[0], end[0], false);
});
mBookcasePresenter.getEs().submit(downloadThread);
return false;
}).setCancelButton(R.string.cancel);
}
static class ViewHolder {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save