Most of the Kotlin Mutliplatform samples I’ve created have focussed on the sharing of non-UI code and have included a fully SwiftUI based iOS client, along primarily with Compose clients for the other platforms (e.g. Android, Wear, Desktop, and Web). In the PeopleInSpace sample I also created, some time ago, a separate basic standalone Compose for iOS client as an initial exploration of the technology. My feeling is that the vast majority of iOS UI development will be done using SwiftUI but an interesting area that a number of folks have written about (for example this article by Touchlab) is the possibility of using Compose for iOS for some subset of the UI, either a particular screen or some UI component within a screen. In this article I’m going to explore what would be involved in doing this for one of the screens in the Confetti KMM sample.
The current Android and iOS Confetti applications (as shown below) display a list of sessions for a particular conference. A user can click on a particular session and view more detailed information about it….and it’s that session details screen that we’re going to use as an example here.
The SwiftUI code for the list of sessions includes, in both cases, the following code to navigate to the SessionDetailsView
screen.
1
2
3
NavigationLink(destination: SessionDetailsView(session: session)) {
SessionView(session: session)
}
In the pure SwiftUI case SessionDetailsView
contains the native SwiftUI code for that screen whereas when using Compose that struct
conforms to the UIViewControllerRepresentable
protocol (as described in this article).
1
2
3
4
5
6
7
8
9
10
struct SessionDetailsView: UIViewControllerRepresentable {
var session: SessionDetails
func makeUIViewController(context: Context) -> UIViewController {
return SharedViewControllersKt.SessionDetailsViewController(session: session)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
}
This in turn creates the following SessionDetailsViewController
view controller (implemented in our shared Kotlin Multiplatform code) with SessionView
being
a standard Compose function (also in shared code). Note that at this point we’re in the realm of Compose Multiplatform so won’t for example be able to use any Android specific Jetpack Compose
related dependencies. There are though an increasing number of Multiplatform ready Compose library
(e.g. compose-imageloader that we’re using in this example).
1
2
3
4
fun SessionDetailsViewController(session: SessionDetails): UIViewController =
Application("Confetti") {
SessionDetailView(session)
}
The following is what the Compose and SwiftUI based versions of that screen look like in the iOS application. Both versions here are using same SwiftUI based TabView and navigation etc with just the inner content coming from shared Compose code in the 1st case.
Another interesting aspect of this, in this particular project, is that the Compose and SwiftUI clients are sharing the same View Model (based on use of the KMM-ViewModel library) and that also applies to the shared Compose code that we’re consuming here in our SwiftUI application.
Platform specific styling
In this exploration I updated the colors, dimentions etc in the Compose code to match somewhat closely with what was used in the SwiftUI code. In reality, when sharing the same Compose code on on both platforms, we’d need to use an approach that allows having specific styling for each platform, something that can be done using Kotlin Multiplatform’s expect/actual mechanism.
The changes made so far have been pushed to this branch of the Confetti repository.
Featured in Android Weekly Issue #558
Related tweet
Wrote a short article about exploring use of Compose for iOS for one of the screens in the SwiftUI application that's part of the Confetti #KMM sample (.https://t.co/3Wqa46X31F). #iOSDev #AndroidDev https://t.co/rxBj4C2w4n
— John O'Reilly (@joreilly) February 15, 2023