-
Notifications
You must be signed in to change notification settings - Fork 227
AdvancedExtendedUsage_en
Even though global configurations are available, developers can still make specific settings for individual components.
For example, if the global configuration is set to prevent dialogs from closing by clicking outside the dialog area, but you want BottomDialog to be an exception, you can use the following configuration:
BottomDialog.overrideCancelable = BaseDialog.BOOLEAN.TRUE;
You can also make separate settings for the animations of components, such as:
BottomDialog.overrideEnterDuration = 100; // Entrance animation duration is 100 milliseconds
BottomDialog.overrideExitDuration = 100; // Exit animation duration is 100 milliseconds
BottomDialog.overrideEnterAnimRes = R.anim.anim_dialogx_top_enter; // Entrance animation resource
BottomDialog.overrideExitAnimRes = R.anim.anim_dialogx_top_exit; // Exit animation resource
This method allows you to override the entrance and exit animations for a specific component. Note that these methods will not affect other components globally, only the animation effects of the specific component.
Priority: Instance method setting > Component override setting > Global setting.
Additionally, FullScreenDialog only offers animation duration settings and does not provide animation resource settings (this component only allows up and down entrance and exit animations);
CustomDialog has additional overrideMaskEnterAnimRes
and overrideMaskExitAnimRes
to override the animation effects of the background mask, setting it to 0 will cancel the animation.
At this time, other dialog components in the current project will still follow the global configuration, while dialogs with properties effective for individual components will be based on their individual settings.
Note that this configuration should be distinguished from the properties set for a single dialog instance, for example:
BottomDialog.build()
...
.setCancelable(true)
.show();
For instance, if you want to display PopTip toast prompts not as defined by the theme (e.g., at the bottom of the screen) but according to your own requirements (e.g., in the center of the screen), you can adjust the behavior of the dialog by overriding the theme, for example:
DialogX.globalStyle = new MaterialStyle(){
@Override
public PopTipSettings popTipSettings() {
return new PopTipSettings() {
@Override
public ALIGN align() {
return ALIGN.CENTER;
}
};
}
};
Please note this method is for situations where you need to fully control the content and details of the dialog. If you just want to change the overall animation without controlling the details, please refer to the custom open and close animation section for a specific dialog, such as 《Basic Dialogs MessageDialog and InputDialog - Customizing Open and Close Animations》
Using the DialogXAnimInterface
, you can fully customize the open and close animations.
Since the internal elements of DialogX dialog components are exposed, you can easily access and manipulate them. With this, combined with DialogXAnimInterface
, which handles the animation behavior of opening and closing the dialog, you can fully utilize it to achieve your desired effect.
For example, for a CustomDialog, you can control its opening and closing animations like this:
CustomDialog.show(new OnBindView<CustomDialog>(R.layout.layout_custom_dialog) {
@Override
public void onBind(final CustomDialog dialog, View v) {
//...
}
})
// Implement fully custom animation effects
.setDialogXAnimImpl(new DialogXAnimInterface<CustomDialog>() {
@Override
public void doShowAnim(CustomDialog customDialog, ViewGroup dialogBodyView) {
// Custom animation implementation
}
@Override
public void do
ExitAnim(CustomDialog customDialog, ViewGroup dialogBodyView) {
// Custom exit animation implementation
}
});
For animProgress
, it essentially acts as an inverse callback executor. Since the duration of the animation is uncertain, you need to notify DialogX what stage your animation has reached so that the dialog can act accordingly. For example, the closing animation process should go from 1f to 0f, and after completion, the dialog should be destroyed. So, when animProgress.run(0f)
is executed, the destruction process will commence. The opening animation should go from 0f to 1f, and when animProgress.run(1f)
is executed, the opening animation of the dialog is fully complete.
In some scenarios, there's a need for "modal" dialogs, i.e., creating multiple dialogs at once, forming a queue, and displaying them one by one. When one dialog closes, the next one automatically starts. In this case, you can use queue dialogs to accomplish this.
Here's an example code. In DialogX.showDialogList(...)
, build multiple dialogs. Note that these dialogs must be in an unstarted state, built using .build()
method, separated by “,” to form a queue, and they will start automatically.
DialogX.showDialogList(
// Multiple dialogs built and separated by commas
);
During use, you can stop the display of the subsequent queue dialogs at any time using .cleanDialogList()
.
There are two ways to adjust the implementation mode of DialogX, one of them is global adjustment, i.e., directly modify the global configuration of DialogX, for example:
DialogX.implIMPLMode= DialogX.IMPL_MODE.WINDOW;
The other way is a single modification that takes effect in only one popup, e.g.:
MessageDialog.build() // DialogImplMode must be specified when building with the build() method for it to take effect.
.setDialogImplMode(DialogX.IMPL_MODE.WINDOW)
.setTitle(“Title text”)
.setMessage(“Message content”)
.setOkButton(“OK”)
.show();
DialogX defaults to using the View implementation mode, self-adapting to the lifecycle. You can also choose the Window implementation solution (similar to AlertDialog). Note that using the Window implementation mode is experimental and has certain risks and known bugs. You can enable the Window implementation mode using:
DialogX.implIMPLMode= DialogX.IMPL_MODE.WINDOW;
WindowUtil provides interfaces for additional customization of WindowManager.LayoutParams:
WindowUtil.windowSettings = new WindowUtil.WindowSettings() {
@Override
public WindowManager.LayoutParams overrideWindowLayoutParamsInterface(Context context, View dialogView, WindowManager.LayoutParams originWindowLayoutParams) {
// Handle originWindowLayoutParams...
return originWindowLayoutParams;
}
@Override
public ViewGroup overrideRootView(Context context) {
// Customize the root layout, the dialog layout will be added to the root layout, return null means use the default FrameLayout
return null;
}
};
In addition, if the app has the hover window permission, a global popup window is also possible in Window mode, please use the following code to turn it on during initialization:
DialogX.globalHoverWindow = true;
In the latest version 0.0.41.beta4, the DialogFragment implementation method is provided. Use the following method to enable DialogFragment implementation:
DialogX.implIMPLMode= DialogX.IMPL_MODE.DIALOG_FRAGMENT;
No pending issues have been found in this mode so far, but it is still not recommended for use in production environments.
Similar to Window, a transparent-bottom Activity is used as the underlying bearer for the dialog. This approach can, to some extent, be launched from the background (PendingIntent).
DialogX.implIMPLMode= DialogX.IMPL_MODE.FLOATING_ACTIVITY;
On devices running Android 12 and above, you can achieve a background blur effect using RenderEffect
.
To apply this effect within a single dialog, you can utilize the lifecycle events of the activity to add a blur to its elements, thereby achieving a blurred background effect. Here is an example code snippet:
.setDialogLifecycleCallback(new DialogLifecycleCallback<CustomDialog>() {
@Override
public void onShow(CustomDialog dialog) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
RenderEffect blurEffect = RenderEffect.createBlurEffect(20f, 20f, Shader.TileMode.CLAMP);
((ViewGroup) dialog.getWindow().getDecorView()).getChildAt(0).setRenderEffect(blurEffect);
}
}
@Override
public void onDismiss(CustomDialog dialog) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
((ViewGroup) dialog.getWindow().getDecorView()).getChildAt(0).setRenderEffect(null);
}
}
})
To implement a global background blur effect for all dialogs, you can use a global lifecycle listener. Note that the following code filters out PopTip
and PopNotification
. If you need to filter other types of dialogs, please handle them accordingly:
DialogX.dialogLifeCycleListener = new DialogLifecycleCallback<BaseDialog>() {
@Override
public void onShow(BaseDialog dialog) {
super.onShow(dialog);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S && !(dialog instanceof NoTouchInterface)) {
RenderEffect blurEffect = RenderEffect.createBlurEffect(20f, 20f, Shader.TileMode.CLAMP);
((ViewGroup) dialog.getOwnActivity().getWindow().getDecorView()).getChildAt(0).setRenderEffect(blurEffect);
}
}
@Override
public void onDismiss(BaseDialog dialog) {
super.onDismiss(dialog);
List<BaseDialog> sameActivityRunningDialog = BaseDialog.getRunningDialogList(dialog.getOwnActivity());
Iterator<BaseDialog> iterator = sameActivityRunningDialog.iterator();
while (iterator.hasNext()) {
if (iterator.next() instanceof NoTouchInterface) {
iterator.remove();
}
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S
&& !(dialog instanceof PopTip)
&& !(dialog instanceof PopNotification)
&& (sameActivityRunningDialog.isEmpty() || sameActivityRunningDialog.get(0) == dialog)) {
((ViewGroup) dialog.getOwnActivity().getWindow().getDecorView()).getChildAt(0).setRenderEffect(null);
}
}
};
Please note that the above methods are only effective on Android 12+. If you cannot call RenderEffect
, consider updating your app's targetSdkVersion
to 31 or higher. The availability of RenderEffect
depends on system support; even on compatible versions, there may be instances where it is not supported and thus ineffective.
When you need to temporarily store data (such as network request results) during the lifecycle of a dialog or preload initialization data when constructing a dialog, you can use the data penetration feature.
- Sharing data between different components of a dialog
- Preloading initialization parameters for the dialog
- Temporarily caching user operation records
// Store data (supports any object type)
dialog.setData("userInfo", userObject);
// Retrieve data (automatic type adaptation)
User user = dialog.getData("userInfo");
When you need to reuse the same business logic at different interaction points (e.g., when the dialog is displayed or a button is clicked) while avoiding exposing the internal UI components of the dialog, you can use the predefined action feature.
- Triggering the same business logic from multiple locations (e.g., data refresh)
- Encapsulating sensitive operations to prevent external calls
- Decoupling complex business logic
// Predefine an action (example: action 1)
dialog.setActionRunnable(1, () -> {
// Write common business logic here
refreshData();
updateUI();
});
// Execute the predefined action (can be called from anywhere)
dialog.runAction(1);
For example, suppose you have a scenario where a network request needs to be made to load data after the dialog is launched, and the result should refresh the content UI inside the dialog. Additionally, when the dialog's button is clicked to submit data, the data may change, requiring the dialog content to be refreshed again. Since the button callback interface and the logic for displaying content after the dialog is launched are not at the same level (they belong to different inner classes) and cannot call each other directly, you can use action penetration to solve this problem, as shown below:
MessageDialog.show("Title", "This is the content.", "OK")
// Execute after the dialog is displayed...
.onShow(new DialogXRunnable<MessageDialog>() {
@Override
public void run(MessageDialog dialog) {
// Predefine action: action 1
dialog.setActionRunnable(1, new DialogXRunnable<MessageDialog>() {
@Override
public void run(MessageDialog dialog) {
tip("action 1 run!");
// Example: Load data via network and display it in the dialog
}
});
// Execute action 1
dialog.runAction(1);
}
})
// Execute after the button is clicked
.setOkButton(new OnDialogButtonClickListener<MessageDialog>() {
@Override
public boolean onClick(MessageDialog dialog, View v) {
PopTip.show("OK button clicked");
// Example: After clicking the OK button, perform some operations but need to reload action 1 without closing the dialog
// Penetrate and execute action 1
dialog.runAction(1);
return true;
}
});
- Secure Isolation: Business logic is encapsulated within the dialog, avoiding exposure of UI components.
- Logic Reusability: The same operation can be triggered in different scenarios (e.g., when displayed or after a button click).
- Flexible Control: Manage multiple independent business processes through action IDs.
- Lifecycle Safety: Automatically releases resources when the dialog is destroyed.