Open-source project
orhanobut/dialogplus avatar
orhanobut/dialogplus

DialogPlus: a customizable Android dialog built around holders and a builder chain

Advanced dialog solution for android

4,957 stars779 forksKotlinApache-2.0

At a glance

What is it?
A small Kotlin library for list, grid and custom-layout dialogs with headers, footers and drag-to-expand. The API is easy to learn, the released artifact is ten years old, and the branch on GitHub is not the same thing.
Who is it for?
DialogPlus is a good fit for a small app that wants a bottom-sheet style dialog with a header, a list and a confirm button without writing a DialogFragment subclass. The builder chain reads well, and holder selection is the right amount of abstraction for the problem.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly Kotlin, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What problem a dialog library actually solves on Android

The platform gives you `AlertDialog` and a `DialogFragment`, and for a plain message that is genuinely enough. The friction appears as soon as you want a dialog with a custom layout, a header above the content, a footer with an action, and the ability to drag it taller. At that point most codebases end up with a base class in their own package, subclassed per screen, that slowly grows into a dialog framework nobody wants to own.

DialogPlus exists to be that base class for other people. The README describes it as an advanced dialog solution for an Android Activity, showing customizable dialogs from a list, a grid, or your own layout, with animated placement at the top, center, or bottom. The feature list is short and concrete: list and grid content backed by a `BaseAdapter`, custom content from a layout resource or an existing `View`, optional headers and footers with click and cancellation callbacks, expandable dialogs with drag gestures, and configurable animations, dimensions, margins, padding and backgrounds.

That list is the honest scope of the library. It is a presentation component with a builder, not a state-management solution, and it makes no attempt to be one. If your dialog needs to survive rotation, be coordinated with a ViewModel, or resolve across two screens, none of that is here.

The dependency resolves to a 2016 release

Installation is a single Maven Central coordinate, and the README states plainly that the available release is 1.11:

kotlin
repositories {
    mavenCentral()
}

dependencies {
    implementation("com.orhanobut:dialogplus:1.11")
}

The README asks you to use the ordinary Maven dependency declaration so Gradle picks up the dependency metadata, and notes that its examples use APIs available in 1.11. That version number has a date behind it: the 1.11 release was published on 2016-01-31, and its notes are four lines about a padding fix in the utils, the addition of `setContentBackgroundResource` defaulting to white and `setOverlayBackgroundResource` defaulting to semi-transparent black, and a change so that a `ListViewHolder` item click position returns 0 rather than 1 when there is a header.

That last detail is the kind of thing that only matters if you are reading the release notes closely, and it matters because it tells you the list holder has a header-aware position contract baked into it. The two earlier releases are shorter still: v1.10 fixed header and footer placement plus a ListHolder width issue, and v1.9 was a single NPE fix. So the release history is three tags deep, ending in 2016, with no published version after that.

Holders decide what sits inside the dialog body

The content model is the part of the API worth understanding. You pick a holder, and the holder determines what the dialog renders and whether you need an adapter:

kotlin
// A list is the default.
.setContentHolder(ListHolder())

// A grid with three columns.
.setContentHolder(GridHolder(3))

// A custom layout, or use ViewHolder(existingView).
.setContentHolder(ViewHolder(R.layout.dialog_content))

// Gravity.BOTTOM is the default. TOP and CENTER are also supported.
.setGravity(Gravity.CENTER)

`ListHolder` is the default, `GridHolder` takes a column count, and `ViewHolder` takes either a layout resource or an existing `View`. The README is specific that `ViewHolder` does not need an adapter, while list and grid holders do. Once created, you reach custom content through `dialog.holderView` or with `dialog.findViewById(R.id.your_view)`, which is a thin wrapper rather than anything magical.

Here is a complete dialog in the shape the README recommends, created and shown from an Activity on the UI thread:

kotlin
val adapter = ArrayAdapter(
    this,
    android.R.layout.simple_list_item_1,
    listOf("Share", "Save", "Open"),
)

val dialog = DialogPlus.newDialog(this)
    .setAdapter(adapter)
    .setOnItemClickListener { dialog, item, _, _ ->
        Toast.makeText(this, item.toString(), Toast.LENGTH_SHORT).show()
        dialog.dismiss()
    }
    .create()

dialog.show()

Note the imports the README calls out: `com.orhanobut.dialogplus.DialogPlus`, `android.widget.ArrayAdapter` and `android.widget.Toast`. One small trap is called out in the same paragraph: list item positions exclude the scrolling header, so an index of 0 is the first real row even when a header is present.

Every dimension in the builder is pixels

The builder offers a long list of chained setters, and the one detail that will cost you an afternoon is stated plainly in the README: dimensions, margins and padding are in pixels, not dp. You convert using display density yourself if you want dp semantics.

kotlin
.setHeader(R.layout.dialog_header) // Also accepts a View.
.setFooter(R.layout.dialog_footer) // Also accepts a View.
.setExpanded(true, 300)            // List and grid only; initial height in pixels.
.setContentWidth(ViewGroup.LayoutParams.MATCH_PARENT)
.setContentHeight(ViewGroup.LayoutParams.WRAP_CONTENT)
.setMargin(16, 24, 16, 24)
.setPadding(8, 8, 8, 8)
.setOutMostMargin(0, 0, 0, 0)

Two behaviours in that block are worth internalizing. Expansion is off by default, `setExpanded(true)` starts at two fifths of the available display height, and the explicit pixel height you pass to `setExpanded(true, 300)` overrides that. Expansion applies to list and grid holders only, so asking for it with a `ViewHolder` is a request the library will not honor. Separately, centered dialogs get default margins unless you set them, which is one of those quiet defaults that changes layout between placement modes.

Headers and footers accept either a layout resource or a `View`, and both `dialog.headerView` and `dialog.footerView` return the configured view or null, so a nullable check is part of normal use. Clicks on those regions are handled by `setOnClickListener`, which fires for views that have an ID, rather than by the item listener used for rows.

Cancelling, dismissing and the back key

The lifecycle callbacks are conventional, with one wrinkle. A cancelable dialog closes on an outside touch or on the back key, and `setCancelable(false)` turns off automatic cancellation while leaving `dismiss()` working as before.

kotlin
.setOnClickListener { _, view ->
    when (view.id) {
        R.id.confirm -> confirmSelection()
    }
}
.setOnCancelListener { /* Back button or outside touch cancellation. */ }
.setOnDismissListener { /* Exit animation has completed. */ }
.setOnBackPressListener { /* Legacy back key was received. */ }

The wrinkle is `setOnBackPressListener`, and the README labels it as the legacy back key. It exists because release 1.11 predates predictive back. The README gives explicit guidance for apps on newer Android versions: route the dialog's back action to `dialog.onBackPressed(dialog)` and leave the app's normal back action active when the dialog is hidden. In practice that means writing the dispatcher wiring yourself, since the released artifact will not do it.

The rest of the Activity integration advice is short and worth following literally. Pass an Activity context, because the dialog attaches to the Activity's content view. Keep dialog operations on the UI thread. Retain the dialog in the Activity and dismiss it when that Activity is destroyed, and avoid retaining it across configuration changes, which means the usual onSaveInstancePath handling is yours to write. For edge-to-edge Activities, the README asks you to apply system-bar insets to the hosting content so dialogs and controls stay clear of the system UI.

A Kotlin branch and a 2016 artifact in the same repository

Here is the tension a reader has to resolve, because the README and the repository state do not describe the same thing.

On one side, the README describes a current library. The repository's primary language is reported as Kotlin, its topics list android, bottom-sheet, dialog, java and kotlin, and the default branch `master` was last pushed on 2026-10-03. The tree at the top of that branch is unmistakably a modern Android project: `build.gradle.kts`, `settings.gradle.kts`, `gradle.properties`, a `gradle/` directory, `gradlew` and `gradlew.bat` wrappers, an `api/` module, an `app/` module, a `dialogplus/` module, `scripts/`, `.github/` and `MAINTAINING.md`.

On the other side, the README says the available Maven Central release is 1.11 and that release 1.11 supports Android API 10 and later, which is a 2016 statement about a 2016 artifact. A contributor guide in the form of `MAINTAINING.md` sits alongside a scripts directory and Kotlin build files, none of which existed when 1.11 shipped.

Both facts are true and they describe different objects. The Maven coordinate you copy gives you the 1.11 code, with legacy back-key handling and API 10 as the floor. Cloning the default branch gives you a current multi-module Kotlin project with a different build, and no guarantee that its public API matches the 1.11 signatures the README documents. A practical way to judge before you commit is to open the same method on both sides: take `setExpanded` from the README, find it in the 1.11 source the artifact pulls in, and then look for the same signature in the `dialogplus/` module on the default branch. If the two agree, you can treat the README as describing the branch as well. If they diverge, pin the version explicitly, which the README's own coordinate already does, and treat the repository tree as a place where future work is happening rather than as the code you are compiling against.

Editorial conclusion

DialogPlus is a good fit for a small app that wants a bottom-sheet style dialog with a header, a list and a confirm button without writing a DialogFragment subclass. The builder chain reads well, and holder selection is the right amount of abstraction for the problem. Two things to check before adopting: the released version pins you to a 2016 artifact with legacy back-key handling that needs a manual bridge on modern Android, and every dimension in the builder is in pixels, so a dialog that looks right on one density class will not on another. Read the `setExpanded` and `setMargin` calls as the two places a screen is most likely to break, and check whether the pinned 1.11 artifact or the current default branch matches the Kotlin version your app compiles against.

Frequently asked questions

What is DialogPlus?

DialogPlus is an Android library for displaying customizable dialogs inside an Activity. Content can be a list, a grid, or a custom layout, and the dialog can be placed with animated positioning at the top, center, or bottom, with optional headers, footers, click callbacks and drag-to-expand behaviour.

Which version of DialogPlus is published on Maven Central?

The README states that the available Maven Central release is 1.11, published on 2016-01-31, and that its examples use APIs available in that version. The repository's default branch is a much newer Kotlin and Gradle project, so the published artifact and the branch are not the same codebase.

Are DialogPlus margins and padding expressed in dp?

No. The README is explicit that dimensions, margins and padding are in pixels rather than dp, so you convert using display density when you want dp semantics. The same applies to the explicit initial height passed to `setExpanded(true, 300)`, which is also in pixels.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. orhanobut/dialogplus on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/orhanobut-dialogplus.svg)](https://hysenlabs.com/projects/orhanobut-dialogplus)