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.Mark
01/20/2023, 4:44 AMnavigation-compose?Mark
01/20/2023, 8:48 AMAlertDialogBuilder (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()
}
}
}Tepes Lucian Victor
02/01/2023, 7:43 AMComposeView in the dialog fragment, use DialogComposeView ^Tepes Lucian Victor
02/01/2023, 7:43 AMMark
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()
}
}
}
}
}Tepes Lucian Victor
02/01/2023, 10:43 AMAlertDialog or the material one.Tepes Lucian Victor
02/01/2023, 10:54 AMTepes Lucian Victor
02/01/2023, 10:55 AMAlertDialog 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.Mark
02/01/2023, 1:26 PMAlertDialog 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)