├── .github └── workflows │ └── android-unit-test.yml ├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── cn │ │ └── hx │ │ └── dialogmanager │ │ └── ExampleInstrumentedTest.kt │ ├── debug │ ├── AndroidManifest.xml │ ├── java │ │ └── cn │ │ │ └── hx │ │ │ └── dialogmanager │ │ │ └── TestActivity.kt │ └── res │ │ └── layout │ │ └── activity_test.xml │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── cn │ │ │ └── hx │ │ │ └── dialogmanager │ │ │ ├── BaseActivity.kt │ │ │ ├── BaseAlertDialog.kt │ │ │ ├── BaseApplication.kt │ │ │ ├── BaseDialog.kt │ │ │ ├── BaseFragment.kt │ │ │ ├── FragmentTestActivity.kt │ │ │ ├── MainActivity.kt │ │ │ ├── OtherFragment.kt │ │ │ ├── SecondActivity.kt │ │ │ ├── SecondFragment.kt │ │ │ └── TestFragment.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_fragment_test.xml │ │ ├── activity_main.xml │ │ ├── activity_second.xml │ │ ├── fragment_other.xml │ │ ├── fragment_second.xml │ │ └── fragment_test.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── themes.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ ├── java │ └── cn │ │ └── hx │ │ └── dialogmanager │ │ ├── CanBeReplaceTest.kt │ │ ├── DismissDialogTest.kt │ │ ├── EventListenerTest.kt │ │ ├── LockWindowFinishActivityTest.kt │ │ ├── LockWindowFragmentActionTest.kt │ │ ├── LockWindowStartActivityTest.kt │ │ ├── OnlyDismissByUserTest.kt │ │ ├── PendingDialogTest.kt │ │ ├── PriorityDialogListenerTest.kt │ │ ├── PriorityStrategyTest.kt │ │ ├── PriorityTest.kt │ │ └── ShowDialogTest.kt │ └── resources │ └── robolectric.properties ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── cn │ │ └── hx │ │ └── prioritydialog │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── cn │ │ └── hx │ │ └── prioritydialog │ │ ├── ActivityAction.java │ │ ├── DefaultPriorityStrategy.java │ │ ├── DialogHost.java │ │ ├── DialogHostImpl.java │ │ ├── DialogManager.java │ │ ├── DialogManagerImpl.java │ │ ├── FragmentAction.java │ │ ├── FragmentStateData.java │ │ ├── FragmentUtil.java │ │ ├── OnCancelListener.java │ │ ├── OnDialogEventListener.java │ │ ├── OnDismissListener.java │ │ ├── PendingDialogState.java │ │ ├── PendingTransactionState.java │ │ ├── PriorityDialog.java │ │ ├── PriorityDialogConfig.java │ │ ├── PriorityDialogDelegate.java │ │ ├── PriorityDialogHostDelegate.java │ │ ├── PriorityDialogImpl.java │ │ ├── PriorityDialogListener.java │ │ ├── PriorityDialogManager.java │ │ ├── PriorityStrategy.java │ │ ├── WarpFragmentManager.java │ │ └── WarpFragmentTransaction.java │ └── test │ └── java │ └── cn │ └── hx │ └── prioritydialog │ └── ExampleUnitTest.kt └── settings.gradle /.github/workflows/android-unit-test.yml: -------------------------------------------------------------------------------- 1 | name: Android Uint Test 2 | 3 | on: 4 | push: 5 | branches: [ "develop" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: set up JDK 17 17 | uses: actions/setup-java@v3 18 | with: 19 | java-version: '17' 20 | distribution: 'temurin' 21 | cache: gradle 22 | 23 | - name: Grant execute permission for gradlew 24 | run: chmod +x gradlew 25 | - name: Build with Gradle 26 | run: ./gradlew :app:testDebugUnitTest 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | local.properties 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android 优先级对话框 2 | 3 | Android 默认对话框是不带优先级的,并且可以同时弹出多个,最后弹出的在最上面。往往我们更习惯一次只显示一个对话框,然后前一个关闭后一个才弹出。于是有了PriorityDialog 4 | 5 | PriorityDialog基于DialogFragment实现,以最小的倾入性实现优先级对话框。 6 | 7 | ### gradle依赖 8 | 9 | ```groovy 10 | dependencies { 11 | implementation 'com.github.qq549631030:priority-dialog:x.x.x' 12 | } 13 | ``` 14 | 15 | ### 初始化配置 16 | 17 | #### 1、初始化 18 | 19 | 在Application的onCreate方法调用PriorityDialogManager.init(this)初始化 20 | 21 | ```kotlin 22 | class BaseApplication : Application() { 23 | 24 | override fun onCreate() { 25 | super.onCreate() 26 | PriorityDialogManager.init(this) 27 | } 28 | } 29 | ``` 30 | 31 | #### 2、PriorityDialog配置 32 | 33 | 通过代理方式: 34 | 35 | PriorityDialog by PriorityDialogImpl()可实现将任意一个DialogFragment转变成优先级对话框 36 | 37 | ```kotlin 38 | open class BaseDialog : DialogFragment(), PriorityDialog by PriorityDialogImpl() { 39 | } 40 | ``` 41 | 42 | #### 3、DialogManager,DialogHost配置 43 | 44 | 通过代理方式: 45 | 46 | DialogManager by DialogManagerImpl() 可实现将任意一个FragmentActivity转变成对话框管理类 47 | 48 | DialogHost by DialogHostImpl() 可实现将任意一个FragmentActivity、Fragment转变成对话框宿主 49 | 50 | ```kotlin 51 | open class BaseActivity : AppCompatActivity(), DialogManager by DialogManagerImpl(), 52 | DialogHost by DialogHostImpl() { 53 | } 54 | ``` 55 | 56 | ```kotlin 57 | open class BaseFragment : Fragment(), DialogHost by DialogHostImpl() { 58 | } 59 | ``` 60 | 61 | #### 4、使用 62 | 63 | 在DialogHost(宿主)中调用showPriorityDialog(priorityDialog)即可 64 | 65 | ```kotlin 66 | val dialog = BaseDialog() 67 | dialog.priorityConfig.priority = 1 68 | showPriorityDialog(dialog) 69 | ``` 70 | 71 | ### 属性介绍 72 | 73 | #### 1、priority优先级,值越大优先级越高(默认值为0) 74 | 75 | 当同一宿主页面同时有多个对话框弹出时,优先级最高的先显示,等高优先级的关闭后,次优先级的再弹出。 76 | 77 | 分三种情况: 78 | 79 | 1、先**低**后**高**,**高**取代**低**显示,**高**关闭后**低**再显示 80 | 81 | ```kotlin 82 | val dialog1 = BaseDialog() 83 | dialog1.priorityConfig.priority = 1 84 | showPriorityDialog(dialog1) 85 | //当前显示dialog1 86 | val dialog2 = BaseDialog() 87 | dialog2.priorityConfig.priority = 2 88 | showPriorityDialog(dialog2) 89 | //当前显示dialog2 90 | dialog2.dismiss() 91 | //当前显示dialog1 92 | dialog1.dismiss() 93 | //当前无dialog 94 | ``` 95 | 96 | 2、先**高**后**低**,**低**不显示,**高**关闭后**低**再显示 97 | 98 | ```kotlin 99 | val dialog1 = BaseDialog() 100 | dialog1.priorityConfig.priority = 2 101 | showPriorityDialog(dialog1) 102 | //当前显示dialog1 103 | val dialog2 = BaseDialog() 104 | dialog2.priorityConfig.priority = 1 105 | showPriorityDialog(dialog2) 106 | //当前仍然显示dialog1 107 | dialog1.dismiss() 108 | //当前显示dialog2 109 | dialog2.dismiss() 110 | //当前无dialog 111 | ``` 112 | 113 | 3、同优先级,后弹出的优先级高 114 | 115 | ```kotlin 116 | val dialog1 = BaseDialog() 117 | dialog1.priorityConfig.priority = 1 118 | showPriorityDialog(dialog1) 119 | //当前显示dialog1 120 | val dialog2 = BaseDialog() 121 | dialog2.priorityConfig.priority = 1 122 | showPriorityDialog(dialog2) 123 | //当前显示dialog2 124 | dialog2.dismiss() 125 | //当前显示dialog1 126 | dialog1.dismiss() 127 | //当前无dialog 128 | ``` 129 | 130 | 以上是默认的优先级处理方式,也可以通过配置PriorityStrategy来自定义规则 131 | 132 | 通过PriorityDialogManager.init(this,priorityStrategy)初始化全局策略 133 | 134 | 或通过PriorityDialogManager.updatePriorityStrategy(priorityStrategy)修改全局策略 135 | 136 | 也可以通过DialogManager.setCurrentPriorityStrategy(priorityStrategy)来设置单个Activity的策略 137 | 138 | 具体实现方式可参数DefaultPriorityStrategy 139 | 140 | ```java 141 | public interface PriorityStrategy { 142 | //新对话框是否能取代现有对话框而显示 143 | boolean canNewShow(@NonNull PriorityDialog preDialog, @NonNull PriorityDialog newDialog); 144 | 145 | //新对话框和等待队列里的比是否能显示,默认true 146 | boolean canNewShowCasePending(@NonNull List pendingList, @NonNull PriorityDialog newDialog); 147 | 148 | //等待队列中相同优先级的对话框弹出顺序是不是先进先出,默认false 149 | boolean firstInFirstOutWhenSamePriority(); 150 | } 151 | ``` 152 | 153 | #### 2、isAddToPendingWhenReplaceByOther 当被其它对话框顶下去的时候是否要加入等待队列(默认值true) 154 | 155 | 如前面情况1,**低**被**高**取代,当**高**关闭后**低**会再次显示,如果想**低**不再显示,可以设置**低** 156 | isAddToPendingWhenReplaceByOther=false 157 | 158 | ```kotlin 159 | val dialog1 = BaseDialog() 160 | dialog1.priorityConfig.priority = 1 161 | dialog1.priorityConfig.isAddToPendingWhenReplaceByOther = false 162 | showPriorityDialog(dialog1) 163 | //当前显示dialog1 164 | val dialog2 = BaseDialog() 165 | dialog2.priorityConfig.priority = 2 166 | showPriorityDialog(dialog2) 167 | //当前显示dialog2 168 | dialog2.dismiss() 169 | //当前无dialog 170 | ``` 171 | 172 | #### 3、isLockWindow是否锁定当前页面(默认值false) 173 | 174 | 若为true则对话框显示时只能停留在当前页面,无法关闭无法跳走,会把这些操作缓存起来,当对话框关闭时会自动执行之前未执行的操作。 175 | 176 | ##### Activity级别操作 177 | 178 | Activity的 startActivity()、startActivityForResult()、finish() 179 | 180 | Fragment的 startActivity()、startActivityForResult() 181 | 182 | 要使这个属性生效,前面的BaseActivity配置要做如下调整: 183 | 184 | ```kotlin 185 | open class BaseActivity : AppCompatActivity(), DialogManager by DialogManagerImpl(), 186 | DialogHost by DialogHostImpl() { 187 | 188 | override fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?) { 189 | if (warpStartActivityForResult(intent, requestCode, options)) { 190 | return 191 | } 192 | super.startActivityForResult(intent, requestCode, options) 193 | } 194 | 195 | override fun finish() { 196 | if (warpFinish()) { 197 | return 198 | } 199 | super.finish() 200 | } 201 | } 202 | ``` 203 | 204 | ```kotlin 205 | val dialog = BaseDialog() 206 | dialog.priorityConfig.isLockWindow = true 207 | showPriorityDialog(dialog) 208 | //当前显示dialog 209 | startActivity(Intent(this, SecondActivity::class.java)) 210 | finish() 211 | //SecondActivity不会启动,当前页面不会关闭 212 | dialog.dismiss() 213 | //SecondActivity启动,当前页面关闭 214 | ``` 215 | 216 | ##### Fragment级别操作 217 | 218 | FragmentManager的各种Transaction以及popBackStack 219 | 220 | 要使这个属性生效,执行Transaction以及popBackStack操作时要使用warpParentFragmentManager或者warpChildFragmentManager 221 | 222 | ```kotlin 223 | val dialog = BaseDialog() 224 | dialog.priorityConfig.isLockWindow = true 225 | showPriorityDialog(dialog) 226 | //当前显示dialog 227 | warpParentFragmentManager.beginTransaction().replace(R.id.container, SecondFragment()).commit() 228 | //当前显示的Fragment不变 229 | dialog.dismiss() 230 | //当前显示的Fragment变成了SecondFragment 231 | ``` 232 | 233 | ##### 4、isSupportRecreate是否支持Activity重建前的dialog恢复显示(默认值true) 234 | 235 | ```kotlin 236 | val dialog = BaseDialog() 237 | dialog.priorityConfig.isSupportRecreate = true 238 | showPriorityDialog(dialog) 239 | //当前显示dialog 240 | 241 | //Activity recreate 242 | 243 | //当前显示dialog 244 | ``` 245 | 246 | ```kotlin 247 | val dialog = BaseDialog() 248 | dialog.priorityConfig.isSupportRecreate = false 249 | showPriorityDialog(dialog) 250 | //当前显示dialog 251 | 252 | //Activity recreate 253 | 254 | //当前无dialog 255 | ``` 256 | 257 | ##### 5、isAllowStateLoss是否支持onStop状态下显示dialog,默认false 258 | 259 | 默认在stop状态下弹对话框会被丢弃,可以通过设置isAllowStateLoss来改变这一行为 260 | 261 | ```kotlin 262 | val dialog = BaseDialog() 263 | //activity.onStop() 264 | showPriorityDialog(dialog) 265 | //当前无dialog 266 | //activity.onResume() 267 | //当前无dialog 268 | 269 | dialog.priorityConfig.isAllowStateLoss = true 270 | //activity.onStop() 271 | showPriorityDialog(dialog) 272 | //当前无dialog 273 | //activity.onResume() 274 | //当前有dialog 275 | 276 | ``` 277 | 278 | ##### 6、isAddToPendingWhenCanNotShow当不能显示的时候(如比优先级比当前显示的低)是否要加入等待队列,默认true 279 | 280 | 默认想弹的对话框比现在显示中或者比等待队列中最高优先级对话框(isCasePending=true时)的优先级低会加入等待队列, 281 | 可以通过设置isAddToPendingWhenCanNotShow来改变这一行为 282 | 283 | ```kotlin 284 | val dialog1 = BaseDialog() 285 | dialog1.priorityConfig.priority = 2 286 | showPriorityDialog(dialog1) 287 | //当前显示dialog1 288 | val dialog2 = BaseDialog() 289 | dialog2.priorityConfig.priority = 1 290 | dialog2.priorityConfig.isAddToPendingWhenCanNotShow = false 291 | showPriorityDialog(dialog2) 292 | //当前仍然显示dialog1(dialog2被丢弃) 293 | dialog1.dismiss() 294 | //当前无dialog 295 | ``` 296 | 297 | ##### 7、isAddToPendingWhenReplaceByOther当被其它高优先级对话框顶下去的时候是否要加入等待队列,默认true 298 | 299 | 默认被其它高优先级对话框顶下去的时候要加入等待队列,可以通过设置isAddToPendingWhenReplaceByOther = false来改变这一行为 300 | 301 | ```kotlin 302 | val dialog1 = BaseDialog() 303 | dialog1.priorityConfig.priority = 1 304 | dialog1.priorityConfig.isAddToPendingWhenReplaceByOther = false 305 | showPriorityDialog(dialog1) 306 | //当前显示dialog1 307 | val dialog2 = BaseDialog() 308 | dialog2.priorityConfig.priority = 2 309 | showPriorityDialog(dialog2) 310 | //当前显示dialog2(dialog1被丢弃) 311 | dialog2.dismiss() 312 | //当前无dialog 313 | ``` 314 | 315 | ##### 8、isShowImmediateAfterPreDismiss处于等待队列中的对话框是否在上一个显示中的对话框关闭后立即弹出,默认true 316 | 317 | 默认正在显示的对话框关闭后,等待队列里最高优先级的一个会立即弹出,可以通过设置isShowImmediateAfterPreDismiss = false来改变这一行为 318 | 之后可通过DialogManager.tryShowNextPendingDialog()或者DialogManager.tryShowPendingDialog(dialogInfo) 319 | 来手动显示等待队列中的对话框 320 | 321 | ```kotlin 322 | val dialog1 = BaseDialog() 323 | dialog1.priorityConfig.priority = 1 324 | dialog21.priorityConfig.isShowImmediateAfterPreDismiss = false 325 | showPriorityDialog(dialog1) 326 | //当前显示dialog1 327 | val dialog2 = BaseDialog() 328 | dialog2.priorityConfig.priority = 2 329 | showPriorityDialog(dialog2) 330 | //当前显示dialog2 331 | dialog2.dismiss() 332 | //当前无dialog (dialog1还在笔队列中) 333 | 334 | tryShowNextPendingDialog() 335 | //当前显示dialog1 336 | ``` 337 | 338 | ##### 9、isCasePending新对话框弹出时是否需要和等待队列中的对话框比较优先级,默认false 339 | 340 | 默认要弹对话框的时候只和现在正在显示的对话框比较优先级,不考虑等待队列中的,可以通过设置isCasePending = true来改变这一行为 341 | 342 | ```kotlin 343 | val dialog1 = BaseDialog() 344 | dialog1.priorityConfig.priority = 2 345 | dialog1.priorityConfig.isShowImmediateAfterPreDismiss = false 346 | showPriorityDialog(dialog1) 347 | //当前显示dialog1 348 | val dialog2 = BaseDialog() 349 | dialog2.priorityConfig.priority = 3 350 | showPriorityDialog(dialog2) 351 | //当前显示dialog2 352 | dialog2.dismiss() 353 | //当前无dialog (dialog1还在笔队列中) 354 | 355 | val dialog3 = BaseDialog() 356 | dialog3.priorityConfig.priority = 1 357 | dialog3.priorityConfig.isCasePending = true 358 | showPriorityDialog(dialog3) 359 | //当前显示dialog1(dialog3进入等待队列) 360 | dialog1.dismiss() 361 | //当前显示dialog3 362 | ``` 363 | 364 | ##### 10、isShowImmediateAfterPreCanNotShowCasePending是否在上一个对话框无法弹出(和等待队列比)后立即弹出,默认true 365 | 366 | 默认情况下,当想要弹的对话框比等待队列里最高优先级的对话框优先级低时,等待队列中最高优先级的对话框会自动弹出,可以通过设置isShowImmediateAfterPreCanNotShowCasePending 367 | = false来改变这一行为 368 | 369 | ```kotlin 370 | val dialog1 = BaseDialog() 371 | dialog1.priorityConfig.priority = 2 372 | dialog1.priorityConfig.isShowImmediateAfterPreDismiss = false 373 | dialog1.priorityConfig.isShowImmediateAfterPreCanNotShowCasePending = false 374 | showPriorityDialog(dialog1) 375 | //当前显示dialog1 376 | val dialog2 = BaseDialog() 377 | dialog2.priorityConfig.priority = 3 378 | showPriorityDialog(dialog2) 379 | //当前显示dialog2 380 | dialog2.dismiss() 381 | //当前无dialog (dialog1还在笔队列中) 382 | 383 | val dialog3 = BaseDialog() 384 | dialog3.priorityConfig.priority = 1 385 | dialog3.priorityConfig.isCasePending = true 386 | showPriorityDialog(dialog3) 387 | //当前无dialog(dialog1,dialog3都在等待孤队列) 388 | 389 | tryShowNextPendingDialog() 390 | //当前显示dialog1 391 | dialog1.dismiss() 392 | //当前显示dialog3 393 | ``` 394 | 395 | ##### PriorityDialog的defaultPriorityConfig(config)方法可以设置所有对话框的初始配置 396 | 397 | 有时候你的对话框行为和框架默认的不一样,但不想每次弹框都重复性的设置这些属性,可以能过这个方法统一设置 398 | 399 | ```kotlin 400 | open class BaseDialog : DialogFragment(), PriorityDialog by PriorityDialogImpl() { 401 | override fun defaultPriorityConfig(config: PriorityDialogConfig) { 402 | //低优先级的直接丢弃,不加入等待队列 403 | config.isAddToPendingWhenCanNotShow = false 404 | config.isAddToPendingWhenReplaceByOther = false 405 | } 406 | } 407 | ``` 408 | 409 | ### 对话框事件处理 410 | 411 | #### onCancel 412 | 413 | 可重写DialogHost的onCancel方法(推荐) 414 | 415 | ```kotlin 416 | override fun onCancel(priorityDialog: PriorityDialog) { 417 | if (priorityDialog.uuid == "custom_uuid") { 418 | //next 419 | } 420 | } 421 | ``` 422 | 423 | 也可用setOnCancelListener 424 | 425 | ```kotlin 426 | dialog.setOnCancelListener(object : OnCancelListener { 427 | override fun onCancel(dialog: PriorityDialog) { 428 | //这里只能通过dialog.dialogHost访问外部类的方法、属性 429 | //不可直接访问外部类方法、属性,因为Activity recreate后的情况下原dialogHost已经不存在了 430 | (dialog.dialogHost as? YourHostActivity)?.publicMethod() 431 | //(dialog.dialogHost as? YourHostFragment)?.publicMethod() 432 | } 433 | }) 434 | ``` 435 | 436 | #### onDismiss 437 | 438 | 可重写DialogHost的onDismiss方法(推荐) 439 | 440 | ```kotlin 441 | override fun onDismiss(priorityDialog: PriorityDialog) { 442 | if (priorityDialog.uuid == "custom_uuid") { 443 | //next 444 | } 445 | } 446 | ``` 447 | 448 | 也可用setOnDismissListener 449 | 450 | ```kotlin 451 | dialog.setOnDismissListener(object : OnDismissListener { 452 | override fun onDismiss(dialog: PriorityDialog) { 453 | //这里只能通过dialog.dialogHost访问外部类的方法、属性 454 | //不可直接访问外部类方法、属性,因为Activity recreate后的情况下原dialogHost已经不存在了 455 | (dialog.dialogHost as? YourHostActivity)?.publicMethod() 456 | //(dialog.dialogHost as? YourHostFragment)?.publicMethod() 457 | } 458 | }) 459 | ``` 460 | 461 | #### onDialogEvent 462 | 463 | 可重写DialogHost的onDialogEvent方法(推荐) 464 | 465 | event可以是任意的自定义事件,比如按钮点击,文字输入等等。 466 | 467 | ```kotlin 468 | override fun onDialogEvent(priorityDialog: PriorityDialog, event: Any) { 469 | if (priorityDialog.uuid == "custom_uuid") { 470 | when (event) { 471 | is BaseAlertDialog.AlertDialogClickEvent -> { 472 | if (event.which == DialogInterface.BUTTON_POSITIVE) { 473 | //next 474 | } 475 | } 476 | else -> {} 477 | } 478 | } 479 | } 480 | ``` 481 | 482 | 也可用setOnDialogEventListener 483 | 484 | ```kotlin 485 | dialog.setOnDialogEventListener(object : OnDialogEventListener { 486 | override fun onDialogEvent(dialog: PriorityDialog, event: Any) { 487 | //这里只能通过dialog.dialogHost访问外部类的方法、属性 488 | //不可直接访问外部类方法、属性,因为Activity recreate后的情况下原dialogHost已经不存在了 489 | (dialog.dialogHost as? YourHostActivity)?.publicMethod() 490 | //(dialog.dialogHost as? YourHostFragment)?.publicMethod() 491 | } 492 | }) 493 | ``` 494 | 495 | ### DialogManager相关方法 496 | 497 | #### 对话框显示状态监听 498 | 499 | registerPriorityDialogListener() 500 | unregisterPriorityDialogListener() 501 | 502 | ```kotlin 503 | open class BaseActivity : AppCompatActivity(), DialogManager by DialogManagerImpl(), 504 | DialogHost by DialogHostImpl() { 505 | private val priorityDialogListener = object : PriorityDialogListener { 506 | override fun onDialogShow(dialog: PriorityDialog) { 507 | //对话框显示 508 | } 509 | 510 | override fun onDialogDismiss(dialog: PriorityDialog) { 511 | //对话框关闭 512 | } 513 | 514 | override fun onDialogAddToPending(dialog: PriorityDialog) { 515 | //对话框加入等待队列 516 | } 517 | } 518 | 519 | override fun onCreate(savedInstanceState: Bundle?) { 520 | super.onCreate(savedInstanceState) 521 | registerPriorityDialogListener(priorityDialogListener) 522 | } 523 | 524 | override fun onDestroy() { 525 | unregisterPriorityDialogListener(priorityDialogListener) 526 | super.onDestroy() 527 | } 528 | } 529 | 530 | ``` 531 | 532 | #### 等待队列相关操作 533 | 534 | ```kotlin 535 | //获取所有等待队列对话框 536 | getAllPendingDialog() 537 | //手动弹出等待队列中最高优先级对话框 538 | tryShowNextPendingDialog() 539 | //手动弹出等待队列中指定对话框(这个方法可以先显示低优先级的) 540 | tryShowPendingDialog(dialogInfo) 541 | ``` 542 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | } 5 | 6 | android { 7 | compileSdk 34 8 | namespace 'cn.hx.dialogmanager' 9 | 10 | defaultConfig { 11 | applicationId "cn.hx.dialogmanager" 12 | minSdk 14 13 | targetSdk 34 14 | versionCode 1 15 | versionName "1.0" 16 | 17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | buildFeatures { 20 | viewBinding true 21 | } 22 | buildTypes { 23 | release { 24 | minifyEnabled true 25 | shrinkResources true 26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_1_8 31 | targetCompatibility JavaVersion.VERSION_1_8 32 | } 33 | kotlinOptions { 34 | jvmTarget = '1.8' 35 | } 36 | testOptions { 37 | unitTests { 38 | includeAndroidResources = true 39 | returnDefaultValues = true 40 | all { 41 | systemProperty 'robolectric.dependency.repo.url', 'https://maven.aliyun.com/repository/public/' 42 | systemProperty 'robolectric.dependency.repo.id', 'aliyun' 43 | } 44 | } 45 | } 46 | } 47 | 48 | dependencies { 49 | 50 | implementation 'androidx.appcompat:appcompat:1.0.0' 51 | implementation 'com.google.android.material:material:1.1.0' 52 | // implementation 'com.github.qq549631030:priority-dialog:1.1.2' 53 | implementation project(path: ':library') 54 | testImplementation 'junit:junit:4.13.2' 55 | testImplementation 'androidx.test.ext:junit:1.1.5' 56 | testImplementation "org.robolectric:robolectric:4.11.1" 57 | testImplementation 'androidx.test.espresso:espresso-core:3.5.1' 58 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 59 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 60 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/cn/hx/dialogmanager/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("cn.hx.dialogmanager", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/debug/java/cn/hx/dialogmanager/TestActivity.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.os.Bundle 4 | import android.widget.Toast 5 | import cn.hx.prioritydialog.PriorityDialog 6 | 7 | class TestActivity : BaseActivity() { 8 | 9 | var dismissAfterSavedState = false 10 | 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | setContentView(R.layout.activity_test) 14 | savedInstanceState ?: supportFragmentManager.beginTransaction() 15 | .add(R.id.container, TestFragment()).commit() 16 | } 17 | 18 | override fun onCancel(priorityDialog: PriorityDialog) { 19 | if (priorityDialog.priorityConfig.uuid == "onCancel_test_uuid") { 20 | Toast.makeText(this, "onCancel called", Toast.LENGTH_SHORT).show() 21 | } 22 | } 23 | 24 | override fun onDismiss(priorityDialog: PriorityDialog) { 25 | if (priorityDialog.priorityConfig.uuid == "onDismiss_test_uuid") { 26 | Toast.makeText(this, "onDismiss called", Toast.LENGTH_SHORT).show() 27 | } 28 | } 29 | 30 | override fun onDialogEvent(priorityDialog: PriorityDialog, event: Any) { 31 | if (priorityDialog.priorityConfig.uuid == "onDialogEvent_test_uuid") { 32 | when (event) { 33 | is BaseAlertDialog.AlertDialogClickEvent -> { 34 | Toast.makeText(this, "button ${event.which} clicked", Toast.LENGTH_SHORT).show() 35 | } 36 | else -> {} 37 | } 38 | } 39 | } 40 | 41 | override fun onStop() { 42 | super.onStop() 43 | if (dismissAfterSavedState) { 44 | dismissCurrentDialog(true) 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /app/src/debug/res/layout/activity_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import androidx.appcompat.app.AppCompatActivity 6 | import cn.hx.prioritydialog.DialogHost 7 | import cn.hx.prioritydialog.DialogHostImpl 8 | import cn.hx.prioritydialog.DialogManager 9 | import cn.hx.prioritydialog.DialogManagerImpl 10 | 11 | open class BaseActivity : AppCompatActivity(), DialogManager by DialogManagerImpl(), DialogHost by DialogHostImpl() { 12 | 13 | val TAG = this::class.java.simpleName 14 | 15 | @Deprecated("Deprecated in Java") 16 | @Suppress("DEPRECATION") 17 | override fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?) { 18 | val ignoreHoldWindow = intent.getBooleanExtra(EXTRA_IGNORE_DIALOG_LOCK, false) 19 | if (!ignoreHoldWindow && warpStartActivityForResult(intent, requestCode, options)) { 20 | return 21 | } 22 | super.startActivityForResult(intent, requestCode, options) 23 | } 24 | 25 | override fun finish() { 26 | val ignoreHoldWindow = intent.getBooleanExtra(EXTRA_IGNORE_DIALOG_LOCK, false) 27 | if (!ignoreHoldWindow && warpFinish()) { 28 | return 29 | } 30 | super.finish() 31 | } 32 | 33 | fun showAlertDialog(title: String? = null, message: String, priority: Int = 0, isAddToPendingWhenReplaceByOther: Boolean = true, lockWindow: Boolean = false, isSupportRecreate: Boolean = true, uuid: String? = null, isCanBeReplace: Boolean = true) { 34 | val dialog = createAlertDialog(title, message, priority, isAddToPendingWhenReplaceByOther, lockWindow, isSupportRecreate, uuid, isCanBeReplace) 35 | showPriorityDialog(dialog) 36 | } 37 | 38 | fun createAlertDialog(title: String? = null, message: String, priority: Int = 0, isAddToPendingWhenReplaceByOther: Boolean = true, lockWindow: Boolean = false, isSupportRecreate: Boolean = true, uuid: String? = null, isCanBeReplace: Boolean = true): BaseAlertDialog { 39 | val dialog = BaseAlertDialog.Builder() 40 | .title(title) 41 | .message(message) 42 | .positive("Confirm") 43 | .negative("Cancel") 44 | .create() 45 | dialog.priorityConfig.priority = priority 46 | dialog.priorityConfig.isAddToPendingWhenReplaceByOther = isAddToPendingWhenReplaceByOther 47 | dialog.priorityConfig.isLockWindow = lockWindow 48 | dialog.priorityConfig.isSupportRecreate = isSupportRecreate 49 | dialog.priorityConfig.isCanBeReplace = isCanBeReplace 50 | uuid?.let { 51 | dialog.priorityConfig.uuid = it 52 | } 53 | return dialog 54 | } 55 | 56 | companion object { 57 | const val EXTRA_IGNORE_DIALOG_LOCK = "extra_ignore_dialog_lock" 58 | } 59 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/BaseAlertDialog.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.app.Dialog 4 | import android.content.DialogInterface 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AlertDialog 7 | 8 | class BaseAlertDialog : BaseDialog(), DialogInterface.OnClickListener { 9 | 10 | private var title: CharSequence? = null 11 | private var message: CharSequence? = null 12 | private var positive: CharSequence? = null 13 | private var negative: CharSequence? = null 14 | private var neutral: CharSequence? = null 15 | 16 | init { 17 | savedStateRegistry.registerSavedStateProvider(KEY_ALERT_DIALOG_STATE) { 18 | Bundle().apply { 19 | putCharSequence(TITLE, title) 20 | putCharSequence(MESSAGE, message) 21 | putCharSequence(POSITIVE, positive) 22 | putCharSequence(NEGATIVE, negative) 23 | putCharSequence(NEUTRAL, neutral) 24 | } 25 | } 26 | } 27 | 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | savedStateRegistry.consumeRestoredStateForKey(KEY_ALERT_DIALOG_STATE)?.run { 31 | title = getCharSequence(TITLE) 32 | message = getCharSequence(MESSAGE) 33 | positive = getCharSequence(POSITIVE) 34 | negative = getCharSequence(NEGATIVE) 35 | neutral = getCharSequence(NEUTRAL) 36 | } 37 | } 38 | 39 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 40 | val builder = AlertDialog.Builder(requireContext()) 41 | builder.setTitle(title) 42 | .setMessage(message) 43 | positive?.let { 44 | builder.setPositiveButton(it, this@BaseAlertDialog) 45 | } 46 | negative?.let { 47 | builder.setNegativeButton(it, this@BaseAlertDialog) 48 | } 49 | neutral?.let { 50 | builder.setNeutralButton(it, this@BaseAlertDialog) 51 | } 52 | return builder.create() 53 | } 54 | 55 | override fun onClick(dialog: DialogInterface, which: Int) { 56 | onDialogEvent(AlertDialogClickEvent(which)) 57 | } 58 | 59 | class Builder { 60 | private var title: CharSequence? = null 61 | private var message: CharSequence? = null 62 | private var positive: CharSequence? = null 63 | private var negative: CharSequence? = null 64 | private var neutral: CharSequence? = null 65 | 66 | fun title(title: CharSequence?): Builder { 67 | this.title = title 68 | return this 69 | } 70 | 71 | fun message(message: CharSequence?): Builder { 72 | this.message = message 73 | return this 74 | } 75 | 76 | fun positive(positive: CharSequence?): Builder { 77 | this.positive = positive 78 | return this 79 | } 80 | 81 | fun negative(negative: CharSequence?): Builder { 82 | this.negative = negative 83 | return this 84 | } 85 | 86 | fun neutral(neutral: CharSequence): Builder { 87 | this.neutral = neutral 88 | return this 89 | } 90 | 91 | fun create(): BaseAlertDialog { 92 | return BaseAlertDialog().also { 93 | it.title = title 94 | it.message = message 95 | it.positive = positive 96 | it.negative = negative 97 | it.neutral = neutral 98 | } 99 | } 100 | } 101 | 102 | class AlertDialogClickEvent(val which: Int) 103 | 104 | companion object { 105 | 106 | private const val KEY_ALERT_DIALOG_STATE = "cn.hx.base.alertDialog.state" 107 | 108 | private const val TITLE = "title" 109 | private const val MESSAGE = "message" 110 | private const val POSITIVE = "positive" 111 | private const val NEGATIVE = "negative" 112 | private const val NEUTRAL = "neutral" 113 | } 114 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/BaseApplication.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.app.Application 4 | import cn.hx.prioritydialog.PriorityDialogManager 5 | 6 | class BaseApplication : Application() { 7 | 8 | override fun onCreate() { 9 | super.onCreate() 10 | PriorityDialogManager.init(this) 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/BaseDialog.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import androidx.fragment.app.DialogFragment 4 | import cn.hx.prioritydialog.PriorityDialog 5 | import cn.hx.prioritydialog.PriorityDialogImpl 6 | 7 | open class BaseDialog : DialogFragment(), PriorityDialog by PriorityDialogImpl() { 8 | 9 | val TAG = this::class.java.simpleName + this.hashCode() 10 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import androidx.fragment.app.Fragment 4 | import cn.hx.prioritydialog.DialogHost 5 | import cn.hx.prioritydialog.DialogHostImpl 6 | 7 | open class BaseFragment : Fragment(), DialogHost by DialogHostImpl() { 8 | 9 | val TAG = this::class.java.simpleName 10 | 11 | fun showAlertDialog(title: String? = null, message: String? = null, priority: Int = 0, isAddToPendingWhenReplaceByOther: Boolean = true, lockWindow: Boolean = false, uuid: String? = null) { 12 | val dialog = BaseAlertDialog.Builder() 13 | .title(title) 14 | .message(message) 15 | .positive("Confirm") 16 | .negative("Cancel") 17 | .create() 18 | dialog.priorityConfig.priority = priority 19 | dialog.priorityConfig.isAddToPendingWhenReplaceByOther = isAddToPendingWhenReplaceByOther 20 | dialog.priorityConfig.isLockWindow = lockWindow 21 | uuid?.let { 22 | dialog.priorityConfig.uuid = it 23 | } 24 | showPriorityDialog(dialog) 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/FragmentTestActivity.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.os.Bundle 4 | 5 | class FragmentTestActivity : BaseActivity() { 6 | 7 | override fun onCreate(savedInstanceState: Bundle?) { 8 | super.onCreate(savedInstanceState) 9 | setContentView(R.layout.activity_fragment_test) 10 | savedInstanceState ?: supportFragmentManager.beginTransaction() 11 | .add(R.id.container, TestFragment()).commit() 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.content.DialogInterface 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.os.Handler 7 | import android.os.Looper 8 | import android.util.Log 9 | import cn.hx.dialogmanager.databinding.ActivityMainBinding 10 | import cn.hx.prioritydialog.PriorityDialog 11 | 12 | class MainActivity : BaseActivity() { 13 | 14 | lateinit var binding: ActivityMainBinding 15 | 16 | lateinit var handler: Handler 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | handler = Handler(Looper.getMainLooper()) 21 | binding = ActivityMainBinding.inflate(layoutInflater) 22 | setContentView(binding.root) 23 | binding.btnPriorityHigh.setOnClickListener { 24 | showAlertDialog( 25 | "first dialog", 26 | "this is the first dialog with priority = 1\nthis will dismiss when second dialog show", 27 | 1 28 | ) 29 | 30 | handler.postDelayed({ 31 | showAlertDialog( 32 | "second dialog", 33 | "this is the second dialog with priority = 2 \nthe first dialog will reshow after this dismissed", 34 | 2 35 | ) 36 | }, 3000L) 37 | } 38 | binding.btnPriorityLow.setOnClickListener { 39 | showAlertDialog( 40 | "first dialog", 41 | "this is the first dialog with priority = 2\nthis will stop the second dialog to show\nthe second dialog will show after this dismissed", 42 | 2 43 | ) 44 | 45 | handler.postDelayed({ 46 | showAlertDialog( 47 | "second dialog", 48 | "this is the second dialog with priority = 1\nthis show after first dialog dismiss ", 49 | 1 50 | ) 51 | }, 3000L) 52 | } 53 | 54 | binding.btnDismissByUserFalse.setOnClickListener { 55 | showAlertDialog( 56 | "first dialog", 57 | "this is the first dialog with priority = 1\nand with isAddToPendingWhenReplaceByOther = false\nthis will dismiss when second dialog show", 58 | 1, 59 | false 60 | ) 61 | 62 | handler.postDelayed({ 63 | showAlertDialog( 64 | "second dialog", 65 | "this is the second dialog with priority = 2\nthe first dialog will not reshow when this dismissed", 66 | 2 67 | ) 68 | }, 3000L) 69 | } 70 | binding.btnUnSupportRecreate.setOnClickListener { 71 | showAlertDialog( 72 | "first dialog", 73 | "this is the first dialog with with isSupportRecreate = false\nthis will dismiss when recreate", 74 | isSupportRecreate = false 75 | ) 76 | } 77 | binding.btnForStart.setOnClickListener { 78 | showAlertDialog( 79 | "first dialog", 80 | "this is the first dialog with priority = 1\nthis will dismiss when second dialog show", 81 | 1, 82 | lockWindow = true 83 | ) 84 | 85 | handler.postDelayed({ 86 | showAlertDialog( 87 | "second dialog starter", 88 | "this is the second dialog with priority = 2 \nthe first dialog will reshow after this dismissed", 89 | 2, 90 | uuid = "mock_uuid_1" 91 | ) 92 | }, 3000L) 93 | 94 | } 95 | binding.btnLockWindowForStart.setOnClickListener { 96 | showAlertDialog( 97 | "lock window dialog", 98 | "this dialog with lockWindow = true\nit will stop start Second Activity\nafter this dismiss the Second Activity will start again", 99 | lockWindow = true 100 | ) 101 | 102 | handler.post { 103 | startActivity(Intent(this, SecondActivity::class.java)) 104 | } 105 | } 106 | 107 | binding.btnLockWindowForFinish.setOnClickListener { 108 | showAlertDialog( 109 | "lock window dialog", 110 | "this dialog with lockWindow = true\nit will stop finish current Activity\nafter this dismiss the this Activity will finish", 111 | lockWindow = true 112 | ) 113 | 114 | handler.post { 115 | finish() 116 | } 117 | } 118 | binding.btnLockWindowOnFragment.setOnClickListener { 119 | startActivity(Intent(this, FragmentTestActivity::class.java)) 120 | } 121 | 122 | binding.btnLockShowTwo.setOnClickListener { 123 | showAlertDialog( 124 | "first dialog", 125 | "this is the first dialog with priority = 1\nthis will not dismiss when second dialog show\nthis will not dismiss when second dialog show\nthis will not dismiss when second dialog show\nthis will not dismiss when second dialog show\n", 126 | 1, 127 | isCanBeReplace = false 128 | ) 129 | 130 | handler.postDelayed({ 131 | showAlertDialog( 132 | "second dialog", 133 | "this is the second dialog with priority = 2", 134 | 2 135 | ) 136 | }, 1000L) 137 | } 138 | } 139 | 140 | override fun onDestroy() { 141 | handler.removeCallbacksAndMessages(null) 142 | super.onDestroy() 143 | } 144 | 145 | override fun onDialogEvent(priorityDialog: PriorityDialog, event: Any) { 146 | Log.d(TAG, "onDialogEvent() called with: priorityDialog = $priorityDialog, event = $event") 147 | if (event is BaseAlertDialog.AlertDialogClickEvent) { 148 | if (priorityDialog.priorityConfig.uuid == "mock_uuid_1" && event.which == DialogInterface.BUTTON_POSITIVE) { 149 | startActivity(Intent(this, SecondActivity::class.java)) 150 | } 151 | } 152 | } 153 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/OtherFragment.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | 8 | class OtherFragment : BaseFragment() { 9 | 10 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 11 | return inflater.inflate(R.layout.fragment_other, container, false) 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/SecondActivity.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.os.Bundle 4 | 5 | class SecondActivity : BaseActivity() { 6 | override fun onCreate(savedInstanceState: Bundle?) { 7 | super.onCreate(savedInstanceState) 8 | setContentView(R.layout.activity_second) 9 | } 10 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/SecondFragment.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.os.Handler 6 | import android.os.Looper 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.view.ViewGroup 10 | import cn.hx.dialogmanager.databinding.FragmentSecondBinding 11 | 12 | class SecondFragment : BaseFragment() { 13 | 14 | private var _binding: FragmentSecondBinding? = null 15 | 16 | private val binding get() = _binding!! 17 | 18 | lateinit var handler: Handler 19 | override fun onAttach(context: Context) { 20 | super.onAttach(context) 21 | handler = Handler(Looper.getMainLooper()) 22 | } 23 | 24 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 25 | _binding = FragmentSecondBinding.inflate(inflater, container, false) 26 | return binding.root 27 | } 28 | 29 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 30 | super.onViewCreated(view, savedInstanceState) 31 | binding.btnPop.setOnClickListener { 32 | showAlertDialog( 33 | "first dialog", 34 | "this is the first dialog with priority = 1\nthis will lock the window\nthe follow popBackStack will be stop and will restart after this dialog dismiss", 35 | 1, 36 | lockWindow = true 37 | ) 38 | handler.post { 39 | warpParentFragmentManager.popBackStack() 40 | } 41 | } 42 | } 43 | 44 | override fun onDestroyView() { 45 | super.onDestroyView() 46 | _binding = null 47 | } 48 | 49 | override fun onDetach() { 50 | handler.removeCallbacksAndMessages(null) 51 | super.onDetach() 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/hx/dialogmanager/TestFragment.kt: -------------------------------------------------------------------------------- 1 | package cn.hx.dialogmanager 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.os.Handler 7 | import android.os.Looper 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import cn.hx.dialogmanager.databinding.FragmentTestBinding 12 | 13 | class TestFragment : BaseFragment() { 14 | 15 | private var _binding: FragmentTestBinding? = null 16 | 17 | private val binding get() = _binding!! 18 | 19 | 20 | lateinit var handler: Handler 21 | override fun onAttach(context: Context) { 22 | super.onAttach(context) 23 | handler = Handler(Looper.getMainLooper()) 24 | } 25 | 26 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 27 | _binding = FragmentTestBinding.inflate(inflater, container, false) 28 | return binding.root 29 | } 30 | 31 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 32 | super.onViewCreated(view, savedInstanceState) 33 | binding.btnLockWindowForStart.setOnClickListener { 34 | showAlertDialog( 35 | "lock window dialog", 36 | "this dialog with lockWindow = true\nit will stop start Second Activity\nafter this dismiss the Second Activity will start again", 37 | lockWindow = true 38 | ) 39 | 40 | handler.post { 41 | startActivity(Intent(requireContext(), SecondActivity::class.java)) 42 | } 43 | } 44 | binding.btnLockWindowForFinish.setOnClickListener { 45 | showAlertDialog( 46 | "lock window dialog", 47 | "this dialog with lockWindow = true\nit will stop finish current Activity\nafter this dismiss the this Activity will finish", 48 | lockWindow = true 49 | ) 50 | 51 | handler.post { 52 | activity?.finish() 53 | } 54 | } 55 | binding.btnReplaceByOther.setOnClickListener { 56 | showAlertDialog( 57 | "first dialog", 58 | "this is the first dialog with priority = 1\nthis will dismiss when second dialog show", 59 | 1 60 | ) 61 | 62 | handler.postDelayed({ 63 | showAlertDialog( 64 | "second dialog", 65 | "this is the second dialog with priority = 2 \nthe first dialog will reshow after this dismissed", 66 | 2, 67 | lockWindow = true 68 | ) 69 | }, 3000L) 70 | handler.postDelayed({ 71 | warpParentFragmentManager.beginTransaction().replace(R.id.container, OtherFragment()).commit() 72 | }, 6000) 73 | } 74 | 75 | binding.btnReplaceByOtherToBack.setOnClickListener { 76 | showAlertDialog( 77 | "first dialog", 78 | "this is the first dialog with priority = 1\nthis will dismiss when second dialog show", 79 | 1 80 | ) 81 | 82 | handler.postDelayed({ 83 | showAlertDialog( 84 | "second dialog", 85 | "this is the second dialog with priority = 2 \nthe first dialog will reshow after this dismissed", 86 | 2, 87 | lockWindow = true 88 | ) 89 | }, 3000L) 90 | handler.postDelayed({ 91 | warpParentFragmentManager.beginTransaction().replace(R.id.container, SecondFragment()).addToBackStack(null).commit() 92 | }, 6000) 93 | } 94 | } 95 | 96 | override fun onDestroyView() { 97 | super.onDestroyView() 98 | _binding = null 99 | } 100 | 101 | override fun onDetach() { 102 | handler.removeCallbacksAndMessages(null) 103 | super.onDetach() 104 | } 105 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_fragment_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |