-
Notifications
You must be signed in to change notification settings - Fork 227
BottomDialog&BottomMenu_en
BottomDialog provides a dialog style that pops up from the bottom. It can be set with a title, message text, and custom layout. When using the Material theme, it also offers features like swiping down to close and swiping up to expand.
BottomMenu is an extension component of BottomDialog, adding menu functionality on top of the basic BottomDialog. The menu can be set with menu content/icons/single-choice feature. In different themes, a "Cancel" close button may be provided (Note: As Material can be closed by swiping down, no additional "Cancel" button is provided for the Material theme).
Use the following code to display a dialog:
BottomDialog.show("Title", "This is the dialog content.");
Please note, the BottomDialog in the Material theme is closed by default through a swipe-down action, and different themes might have different logic. For example, the iOS theme provides a "Cancel" button for closing.
In other themes, you can set the cancel button text and event using the .setCancelButton(...)
method:
BottomDialog.show("Title", "This is the dialog content.")
.setCancelButton("Cancel", new OnDialogButtonClickListener<BottomDialog>() {
@Override
public boolean onClick(BottomDialog baseDialog, View v) {
//...
return false;
}
});
The BottomMenu is a quick-selection menu dialog box implemented based on the BottomDialog. You can quickly display a menu by passing List<String>
, String[] menuList
, List<CharSequence> menuList
, or CharSequence[] menuList
:
BottomMenu.show("Open in new tab", "Read later", "Copy link address")
.setMessage("This is the title")
.setOnMenuItemClickListener(new OnMenuItemClickListener<BottomMenu>() {
@Override
public boolean onClick(BottomMenu dialog, CharSequence text, int index) {
toast(text);
return false;
}
});
In the code above, OnMenuItemClickListener
is the callback for menu item clicks, where text is the menu text, and index is the menu's index.
Radio menu can also easily set the menu icon, we try to save as much as possible to write the Adapter adapter trouble, to set the menu icon can be specified directly, for a menu does not need the icon can be passed directly into the 0:
.setIconResIds(R.mipmap.img_dialogx_demo_add, R.mipmap.img_dialogx_demo_edit...)
Whether the icon is colored according to the light/dark color theme can be adjusted with the following method:
.setAutoTintIconInLightOrDarkMode(boolean)
The bottom menu also provides a "selected" feature, allowing you to set a selected index. When the BottomMenu is displayed, the menu item at the corresponding position will be highlighted as selected. The selection effect may vary slightly depending on the theme.
private int selectMenuIndex;
BottomMenu.show("Deny", "Ask", "Always Allow", "Allow Only While Using")
.setMessage("This is the text description for permission confirmation, it's a demo of a single-choice menu.")
.setTitle("Permission Title")
.setOnMenuItemClickListener(new OnMenuItemClickListener<BottomMenu>() {
@Override
public boolean onClick(BottomMenu dialog, CharSequence text, int index) {
// Record the selected value
selectMenuIndex = index;
toast(text);
return false;
}
})
.setSelection(selectMenuIndex); // Specify the selected position
Similarly, when you set the return value to return true
in the OnMenuItemClickListener
, the menu will not automatically close after an item is clicked.
Alternatively, you can use a callback by implementing setOnIconChangeCallBack(...)
:
BottomMenu.show("Add", "View", "Edit", "Delete")
.setOnIconChangeCallBack(new OnIconChangeCallBack(true) { // The parameter indicates whether to tint icons based on light/dark mode
@Override
public int getIcon(BottomMenu bottomMenu, int index, String menuText) {
switch (menuText) {
case "Add":
return R.mipmap.img_dialogx_demo_add;
case "View":
return R.mipmap.img_dialogx_demo_view;
case "Edit":
return R.mipmap.img_dialogx_demo_edit;
case "Delete":
return R.mipmap.img_dialogx_demo_delete;
}
return 0; // Return 0 means no icon will be shown
}
})
.setOnMenuItemClickListener(new OnMenuItemClickListener<BottomMenu>() {
@Override
public boolean onClick(BottomMenu dialog, CharSequence text, int index) {
toast(text);
return false;
}
});
In the above code, OnIconChangeCallBack
has a parameter (boolean)autoTintIconInLightOrDarkMode
that determines whether the icons should be tinted to match the light or dark mode. When set to true, menu icons will automatically adjust their color according to the text color in light or dark mode. It's recommended to enable this feature when using linear or outline icons that are not multi-colored.
Since version 0.0.50.beta27, you can also asynchronously load menu icons from the network. This feature requires the use of the new MenuIconAdapter
. Here's how you can do it:
.setOnIconChangeCallBack(new MenuIconAdapter<BottomMenu>(false) {
String[] urls = {
"http://www.kongzue.com/test/res/dialogx/ic_menu_add.png",
"http://www.kongzue.com/test/res/dialogx/ic_menu_read_later.png",
"http://www.kongzue.com/test/res/dialogx/ic_menu_link.png"
};
@Override
public boolean applyIcon(BottomMenu dialog, int index, String menuText, ImageView iconImageView) {
Glide.with(MainActivity.this).load(urls[index]).into(iconImageView); // Example of loading network resources into menu icons using Glide
return true;
}
});
In the applyIcon
callback method, the ImageView iconImageView
of the menu icon is exposed, and you can use any asynchronous framework to load the icon resource. Returning true
indicates that the icon for this menu item should be displayed, while returning false
will hide the icon for that menu item.
If you need to select a menu item but not immediately close the dialog, maintaining the selected state for user confirmation or cancellation, you can use the single-choice state callback OnMenuItemSelectListener#onOneItemSelect
to monitor the menu's real-time selected state:
.setOnMenuItemClickListener(new OnMenuItemSelectListener<BottomMenu>() {
@Override
public void onOneItemSelect(BottomMenu dialog, CharSequence text, int index, boolean select) {
// index is the menu item index clicked by the user
}
})
// Enable single-choice mode, choose one of the following:
.setSelection(selectMenuIndex) // Enable single-choice mode and specify a selected item
.setSingleSelection() // Enable single-choice mode without specifying a selected item
In this case, the dialog does not immediately disappear after the user clicks on a menu item, but waits for possible further changes or selections by the user.
To get the menu item selected by the user when the dialog closes or later, you can use the .getSelectionIndex()
method to get the current selected menu index, and .getMenuList()
to get all menu texts.
To enable a multi-selection menu, you can implement the following code, using multi-selection menu state callbacks to get real-time selected items:
.setOnMenuItemClickListener(new OnMenuItemSelectListener<BottomMenu>() {
@Override
public void onMultiItemSelect(BottomMenu dialog, CharSequence[] text, int[] index) {
// index[] array is the collection of all selected menu item indexes, text[] is the collection of all selected menu item texts
}
})
// Enable multi-selection mode, choose one of the following:
.setSelection(selectMenuIndexArray); // Enable multi-selection mode and specify a selected index array
.setMultiSelection() // Enable multi-selection mode without specifying selected items
Here, the dialog does not immediately disappear after the user clicks on a menu item, but waits for possible further changes or additional selections by the user.
To get the menu items selected by the user when the dialog closes or later, you can use the .getSelectionIndexArray()
method to get the current selected menu index collection, .getSelectTextArray()
to get the collection of selected menu texts, and .getMenuList()
to get all menu texts.
Both BottomDialog and BottomMenu, like MessageDialog, support setting display for OK, Cancel, and Other buttons. However, please note that some themes may not support additional Cancel and Other buttons.
To set buttons and callbacks, similar to MessageDialog, use the following code:
.setOkButton("OK", new OnDialogButtonClickListener<BottomDialog>() {
@Override
public boolean onClick(BottomDialog dialog, View v) {
//...
return false;
}
})
.setCancelButton("Cancel", new OnDialogButtonClickListener<BottomDialog>() {
@Override
public boolean onClick(BottomDialog dialog, View v) {
//...
return false;
}
})
.setOtherButton("Other", new OnDialogButtonClickListener<BottomDialog>() {
@Override
public boolean onClick(BottomDialog dialog, View v) {
//...
return false;
}
})
The callback has a return value; if return true
, the dialog will not close automatically after a click.
Additionally, DialogX offers various methods to set callback and button text:
// Set only the button text
.setOkButton("OK")
// Set only the button click callback
.setOkButton(new OnDialogButtonClickListener<BottomDialog>() {
@Override
public boolean onClick(BottomDialog dialog, View v) {
toast("Clicked OK button");
return false;
}
});
// Set button text and callback
.setOkButton("OK", new OnDialogButtonClickListener<BottomDialog>() {
@Override
public boolean onClick(BottomDialog dialog, View v) {
toast("Clicked OK button");
return false;
}
});
// Hide the button
.setOkButton(null)
Please use as you prefer.
If your business process does not need to immediately handle user operations, but needs to know which button the user selected, you can hold a dialog handle and later obtain the selection status, for example:
private BottomDialog dialog;
// Business process simulation, creating and displaying a dialog but not immediately processing the click events
dialog = BottomDialog.show(...);
// When needed, you can get which button option the user clicked using the getButtonSelectResult() method
BUTTON_SELECT_RESULT result = dialog.getButtonSelectResult();
BUTTON_SELECT_RESULT is an enumeration that includes the following types:
NONE, // No selection made
BUTTON_OK, // OK button selected
BUTTON_CANCEL, // Cancel button selected
BUTTON_OTHER // Other button selected
You can determine which button the user clicked based on its status.
Based on this feature, if in your business process, the same part of the code needs to be executed regardless of the user's choice, developers can also handle the user's choice uniformly after the selection, for example, in the DialogLifecycle#onDismiss
dialog close event, to reduce redundant code;
To monitor the lifecycle of the dialog, you can implement its .setDialogLifecycleCallback(...)
interface. It is recommended to use the build()
method to construct the dialog:
BottomMenu.build()
.setDialogLifecycleCallback(new DialogLifecycleCallback<BottomMenu>() {
@Override
public void onShow(BottomMenu dialog) {
// Callback when the dialog starts
}
@Override
public void onDismiss(BottomMenu dialog) {
// Callback when the dialog closes
}
})
.show();
BottomDialog/BottomMenu also supports Lifecycle, and you can use .getLifecycle()
to get the Lifecycle object.
For scrollable BottomDialog/BottomMenu (limited by theme), you can use the enhanced DialogLifecycleCallback to implement BottomDialogSlideEventLifecycleCallback, which provides extended event handling and callbacks for the sliding process and slide-to-close:
.setDialogLifecycleCallback(new BottomDialogSlideEventLifecycleCallback<BottomDialog>() {
@Override
public boolean onSlideClose(BottomDialog dialog) {
log("Sliding close dialog triggered");
return false; // Default return false, return true to intercept, dialog will not continue to close;
}
@Override
public boolean onSlideTouchEvent(BottomDialog dialog, View v, MotionEvent event) {
log("#Sliding process triggered: action="+ event.getAction() + " y="+event.getY());
return false; // Default return false, return true to intercept, dialog will not handle sliding process, can implement touch event takeover;
}
})
You can also handle lifecycle events by overriding lifecycle events when constructing an instance using new, for example:
// Override event demonstration
new BottomDialog() {
@Override
public void onShow(BottomDialog dialog) {
//...
tip("onShow");
}
@Override
public void onDismiss(BottomDialog dialog) {
//...
tip("onDismiss");
}
}
You can also use the methods .onShow(DialogXRunnable)
and .onDismiss(DialogXRunnable)
to handle lifecycle transactions, for example:
BottomDialog.show(...)
.onShow(new DialogXRunnable<BottomDialog>() {
@Override
public void run(BottomDialog dialog) {
//BottomDialog show!
}
})
.onDismiss(new DialogXRunnable<BottomDialog>() {
@Override
public void run(BottomDialog dialog) {
//BottomDialog dismiss!
}
});
BottomDialog natively supports custom layouts. You can customize the layout of the bottom dialog using the following code:
BottomDialog.show("Title", "This is the dialog content.\nBottom dialog also supports custom layout extension usage.",
new OnBindView<BottomDialog>(R.layout.layout_custom_view) {
@Override
public void onBind(BottomDialog dialog, View v) {
//v.findViewById...
}
});
For BottomMenu menus, use the following code to add a custom layout:
BottomMenu.show(new String[]{"Open in new tab", "Read later", "Copy link address"})
.setMessage("Menu title")
.setOnMenuItemClickListener(new OnMenuItemClickListener<BottomMenu>() {
@Override
public boolean onClick(BottomMenu dialog, CharSequence text, int index) {
toast(text);
return true;
}
})
.setCustomView(new OnBindView<BottomDialog>(R.layout.layout_custom_view) {
@Override
public void onBind(BottomDialog dialog, View v) {
//v.findViewById...
}
});
In the callback parameters, v
is the instantiated component of your given layout file. You can instantiate other sub-layout components through v.findViewById(resId)
and set their functionality and event callbacks in the onBind
method.
If you are using ViewBinding, you can also replace it with OnBindingView to get the layout instance directly through binding:
BottomDialog.show("Title", "Here are the contents of the dialog box. The \n bottom dialog also supports custom layout extension usage.",
new OnBindingView<BottomDialog, LayoutCustomViewBinding>() {
@Override
public void onBind(BottomDialog dialog, View view, LayoutCustomViewBinding binding) {
//View childView = binding.childView
}
});
// set menu items
.setMenus("Add", "Edit", "Delete", "Share"...);
// set icons
.setIconResIds(R.mipmap.img_dialogx_demo_add, R.mipmap.img_dialogx_demo_edit...);
//Set the menu items (list or collection)
.setMenuList(list);
// Force a refresh of the interface
.refreshUI();
// Close the dialog
.dismiss();
// Set whether clicking outside the area or the back button is allowed to close the dialog
.setCancelable(boolean);
// Set the title text style
.setTitleTextInfo(TextInfo
);
// Set the message text style
.setMessageTextInfo(TextInfo);
// Set the button text style
.setCancelTextInfo(TextInfo);
// Set the back button callback
.setOnBackPressedListener(OnBackPressedListener);
// Get the dialog instance object, you can customize the Dialog features more deeply through this method
.getDialogImpl()
// Get the custom layout instance
.getCustomView()
// Set the background color, forcibly dye the dialog background. Note that the parameter is an int type color value, not an R.color index
.setBackgroundColor(ColorInt);
// Set the menu text style
.setMenuTextInfo(TextInfo)
// Set dialog corner radius (will crop content display, this setting in BottomDialog and BottomMenu only affects the top left and top right corners)
.setRadius(float px)
// Hide the dialog (no animation), to show again, execute the non-static method .show()
.hide();
// Hide the dialog (simulate the close dialog animation), to show again, execute the non-static method .show()
.hideWithExitAnim();
// Allow slide-to-close (only effective for Material theme)
.setAllowInterceptTouch(boolean)
// Check if it is currently displayed
.isShow()
// Front dialog box display hierarchy
.bringToFront()
// Specify the level of dialog display
.setThisOrderIndex(int)
BottomDialog supports modifying the background mask for added flexibility. To set the background mask, you can use the following code:
bottomDialog.setMaskColor(colorInt);
Please note, the parameter is a ColorInt value. You can use Color.parseColor("#4D000000")
to set a HEX color value, or getResources().getColor(R.color.black30)
to set a color resource value.
TextInfo is used to store basic text style settings, including a series of properties and their respective get/set methods, explained as follows:
Property | Explanation | Default Value |
---|---|---|
fontSize | Font size, -1 for default style, unit: dp | -1 |
gravity | Alignment, -1 for default style, can use values like Gravity.CENTER
|
-1 |
fontColor | Text color, 1 for default style, can use Color.rgb(r,g,b) to get value | 1 |
bold | Whether it's bold | false |
Note that fontColor is a ColorInt value. You can use Color.parseColor("#4D000000")
to set a HEX color value, or a resource getResources().getColor(R.color.black30)
to set a color resource value. Do not directly pass in a resource ID as it might not work.
In the Material theme style with BottomDialog by default, it is scrollable to close. When the cancelable
value is true, a "slide indicator" will be displayed at the top of the dialog. If you need to hide it according to your needs, you can close it as follows:
Disabling the swipe down dialog to close the BottomDialog hides the sliding prompt bar.
.setAllowInterceptTouch(false)
Leverage DialogX's feature of exposing internal elements to delete the tab layout.
BottomDialog.show("Title", "This is the dialog content.\nBottom dialog also supports custom layout extension usage.",
new OnBindView<BottomDialog>(R.layout.layout_custom_view) {
@Override
public void onBind(BottomDialog dialog, View v) {
if (dialog.getDialogImpl().imgTab != null) {
((ViewGroup) dialog.getDialogImpl().imgTab.getParent()).removeView(dialog.getDialogImpl().imgTab);
}
//...
}
});
Manually create a layout_dialogx_bottom_material
layout (dark mode corresponds to layout_dialogx_bottom_material_dark
), contents refer to layout_dialogx_bottom_material.xml (dark mode corresponds to layout_dialogx_bottom_material_dark.xml)
Modify and delete the <ImageView id="@+id/img_tab">
layout:
<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" />
This method utilizes resource override to make changes. No need to worry about null pointer, as DialogX has corresponding internal handling.
If your App incorporates multiple themes and you need a dialog to display in a specific non-global theme style in certain scenarios, you can use .build()
to construct the dialog. Then, apply .setStyle(style)
to specify the theme style, and finally execute .show()
to display the dialog. For example:
BottomDialog.build()
// or directly use .build(IOSStyle.style())
.setStyle(IOSStyle.style())
.setTitle("Title")
.setMessage("Message content.")
.setOkButton("OK")
.show();