Mark
01/19/2023, 12:55 PMAlertDialogBuilder
to compose. I have a multi-module application which I would like to migrate slowly to Compose. In the existing code, one module has a function that takes a Context
and shows a dialog. This function is called from another module (not app module). I can declare the AlertDialog
composable, but am lost (sorry, I’m a newbie in Compose) as to how to call this from non-composable code. The only examples I see are using setContent { … }
(or declaring ComposeView
in existing content XML) neither of which are really applicable here. Any pointers please?robercoding
01/19/2023, 3:09 PMAlertDialog
?
Some code examples would be nice to visualize what you're trying to do
Note: I haven't migrated from XML to Compose, so I'm also not an expert in this field, but might be able to helpMark
01/20/2023, 1:30 AMContext
is enough), others require launching coroutines to grab a list of items to display in the dialog. But really, once I figure out how to show a simple dialog, the others should be easy.navigation-compose
?AlertDialogBuilder
(1.5.1) and pass a programmatically instantiated ComposeView
to setView
. However, this gives:
java.lang.IllegalStateException: Composed into the View which doesn't propagateViewTreeSavedStateRegistryOwner!
at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:1135)
After searching around, I found various suggestions like this:
val decorView = dialog.window?.decorView ?: return
ViewTreeLifecycleOwner.set(decorView, context as AppCompatActivity)
ViewTreeViewModelStoreOwner.set(decorView, context) decorView.setViewTreeSavedStateRegistryOwner(decorView.findViewTreeSavedStateRegistryOwner())
without success. I tried placing this just before and just after calling AlertDialog.show
Any sample code out there for this?robercoding
01/22/2023, 7:20 AMnavigation-compose
for this, you should be able to use AlertDialog
from Compose without having to pass context or anything
Since I haven't worked with XML interoperability I have no idea 🤔Mark
01/22/2023, 7:22 AMDialogFragment
but there seem to be so many bugs. For example, when displaying a TextField in the dialog, I need to switch to 1.4.0 alpha in order to get the keyboard to show at all. But even then, it’s below the dialog window and so key presses are not detectedTepes Lucian Victor
01/27/2023, 6:05 PMMark
01/28/2023, 1:53 AMTepes Lucian Victor
02/01/2023, 7:42 AM/**
* ComposeView (copied code since you can't extend from it) who implements DialogWindowProvider
* and returns a window from the attached dialog.
*/
class DialogComposeView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AbstractComposeView(context, attrs, defStyleAttr), DialogWindowProvider {
constructor(dialog: Dialog): this(dialog.context) {
this.dialog = dialog
}
private val content = mutableStateOf<(@Composable () -> Unit)?>(null)
var dialog: Dialog? = null
override val window: Window
get() = dialog?.window ?: throw IllegalStateException("Not attached to a dialog or a window")
@Suppress("RedundantVisibilityModifier")
protected override var shouldCreateCompositionOnAttachedToWindow: Boolean = false
private set
@Composable
override fun Content() {
content.value?.invoke()
}
override fun getAccessibilityClassName(): CharSequence {
return javaClass.name
}
/**
* Set the Jetpack Compose UI content for this view.
* Initial composition will occur when the view becomes attached to a window or when
* [createComposition] is called, whichever comes first.
*/
fun setContent(content: @Composable () -> Unit) {
shouldCreateCompositionOnAttachedToWindow = true
this.content.value = content
if (isAttachedToWindow) {
createComposition()
}
}
}
ComposeView
in the dialog fragment, use DialogComposeView
^Mark
02/01/2023, 10:33 AMoverride fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val composeView = DialogComposeView(requireContext()).apply {
setContent {
// my composable
}
}
return MaterialAlertDialogBuilder(requireContext()).apply {
setView(composeView)
}.create().also {
composeView.dialog = it
}
}
Tepes Lucian Victor
02/01/2023, 10:41 AMAppCompatDialogFragment
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val dialog = requireDialog() as ComponentDialog
return DialogComposeView(dialog).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
id = composeViewId
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
CompositionLocalProvider(
LocalOnBackPressedDispatcherOwner provides dialog,
) {
MyTheme {
FragmentContent()
}
}
}
}
}
AlertDialog
or the material one.AlertDialog
and custom viewsMark
02/01/2023, 12:36 PMAlertDialog
to work, but it seems fine when using a compose AlertDialog
and removing the onCreateDialog
implementation.AlertDialog
doesn’t play nicely with TextField
, particularly when the text does not fit onto one line (line breaks or wrapping). So, it looks like I have to use Dialog
but I find styling Dialog
to be really hardTepes Lucian Victor
02/01/2023, 1:27 PMMark
02/01/2023, 2:16 PMTextField
issue I just mentioned, I just set the minLines
and maxLines
to be the same value (in my case, 3)