Blog   |   Website

We’re bringing you the latest mobile industry news, along with a new batch of tips and tricks from mobile development experts!

  • The iOS Droidcon App with Compose Multiplatform
  • More Jetpack Compose tips and tricks

The iOS Droidcon App with Compose Multiplatform

One of the most widely discussed topics among mobile developers is UI declarative frameworks and their cross-platform future. So, it’s no surprise that the introduction of the iOS Droidcon App by Touchlab, which was written using Native Compose UI, caused a stir in the iOS and Android development communities. You can download it from the AppStore, dig into the source code, and read the story behind it.

In the meantime, we asked Kevin Galligan what the value of such an approach is, and what was most challenging about implementing the iOS part of the UI.

Kevin Galligan

Kevin Galligan, Touchlab

Technology Partner, Kotlin GDE

What was challenging?

The Driodcon app with Compose for iOS started as a little experiment. We know the team has been working hard on Kotlin Multiplatform support, but since Kotlin/Native and iOS support got started later than the other platforms (and is such a huge effort), we figured we wouldn’t be able to do much. In the end, the biggest problem we had was just getting config setup to build.

We did run into other technical issues. Color space issues for some images, some unimplemented features, that kind of thing. But that’s all what we’d expect at this stage. It’s early for most teams to build with Compose UI on iOS, although clearly you can.

What’s the value?

Kotlin on iOS has great native interop, so you can add Kotlin modules alongside Swift modules. They can coexist in a natural way. Similarly, you can write parts of your UI with shared Compose, then if you decide that a screen should really be “native”, you can develop a Swift UI version of that screen right on top of the shared architecture. It is not an all-or-nothing approach, which is why we’ve loved the Kotlin approach since the beginning.

Of course, KMP for iOS is still relatively new. To really succeed, the developer experience for iOS needs to improve, which is where we’ve been spending a lot of our effort. Better interop for Swift, better tooling and workflows for teams. If we can really nail that, Android and iOS teams will start thinking and working as mobile teams. That’s part of the long term vision.

More Jetpack Compose tips and tricks

While Compose for iOS is still in a very experimental stage, Jetpack Compose for Android UI development is already an extremely popular and mature tool. We’re continuing to share Jetpack Compose tips and tricks from industry experts so that you can unlock the full power of this framework!

Igor Demin

Igor Demin, JetBrains

Team Lead in Compose Multiplatform UI, JetBrains

Check out this series of articles: Compose state explained. It describes in detail how `mutableStateOf` and the Snapshot system work, and helps you structure your applications better.

Anna Zharkova

Anna Zharkova, UseTech

Google Developer Expert

All of the variables and properties to describe a current state can be kept separate or combined in a special data model UIState. 

Use a sealed class to design the state with its cases:

sealed class AlbumState {
    object Loading : AlbumState()
    data class Success(val album: Album) : AlbumState()
    object Error : AlbumState()
}

For a better experience, store the state variable in your ViewModel.

Don’t forget to make it observable to register it as a listener and represent the value as a state. To do that, you can use the mutableStateOf API as the special extensions for StateFlow or LiveData.

class AlbumViewModel: ViewModel() {
    private val mutableState =
MutableStateFlow<AlbumState>(AlbumState.Loading)
    val state = mutableState.asStateFlow()
}

Don’t forget to keep the ViewModel using remember:

@Composable
internal fun AlbumScreen() {
    // Pretend that some injection is happening here
    val viewModel = remember { AlbumViewModel() }
    Content(viewModel.state.collectAsState().value)
}

This approach also introduces unidirectional data flow in your app. This is useful if your ViewModel not only keeps the data but also handles events coming from the UI or other layers of your app and updates the state holder based on the events.

Be careful with back navigation in order to avoid the loss of context and bugs when refreshing states from the ViewModel. You should only call navigate() as part of a callback, and not as part of your composable itself, to avoid calling navigate() on every recomposition.

Learn more:

  Brady Aiello

Brady Aiello, Touchlab

Senior Mobile Developer

Composables have two jobs: rendering the UI and passing input events up to the caller.

State travels from the caller down the UI tree as parameters. Events travel back up to the caller as callbacks. Based on this, there are two important rules which will help you keep the UI smooth and the code more reusable:

  • Don’t put long-running work in Composables. If we do this, the UI will be laggy, because long-running tasks block the rendering pipeline, and the whole UI won’t be redrawn until the task ends.
  • Avoid passing your ViewModel as a parameter where possible. Instead, pass callbacks to Composable functions to update the state. This improves the reusability of your Composables.
@Composable
fun ClickCounter(clicks: Int, onClick: () -> Unit) {
    Button(onClick = onClick) {
      Text("I've been clicked $clicks times")
    }
}

To keep your Composables flexible, use the “Slots” API pattern. 

In the Android View System’s Button, we can only pass text as the content, because it extends a TextView. If you want to put an image in a button, then you need to use MaterialButton. This is limiting – with Compose we can be more flexible.

Let’s look at the “content” parameter for a Composable Button:

@Composable
fun Button(
    onClick: () -> Unit,
    // more parameters,
    content: @Composable RowScope.() -> Unit
)

The content parameter is the “Slot” where some UI will go. This lets a Button display a Text, an Image, or any other Composable as its content. Using this pattern in your own Composables will let you reuse more code. Check out Chris Banes’ article on this for more information.

For more Jetpack Compose tips and tricks, check out the first installment of the Modern Mobile Newsletter if you haven’t already done so! And of course, don’t forget to share it with your friends and colleagues. 

Stay tuned. More great content is coming!