Chapter 8: SwiftUI and Jetpack Compose

Kotlin Multiplatform Mobile

link SwiftUI and Jetpack Compose

Introduction

In this section, we will discuss the differences between SwiftUI and Jetpack Compose. Later on, we will provide an overview on how to integrate the KMM repository with our client-side view models.

Let's start with an analysis of Jetpack Compose and SwiftUI.

link Jetpack Compose

Builder Book

Jetpack Compose is Android’s modern toolkit for building native UI. Jetpack Compose uses declarative layouts, instead of the imperative layouts provided by Android's standard libraries. Declarative code is much easier to read and understand, because it expresses what you want to do instead of how you want to do it.

Let's see a quick example of displaying a button on Android:

Declarative UI:

Layout {
   Button("click me")
}

Imperative UI:

val button = Button()
button.text = "click me"
val layout = Layout()
layout.add(button)

The declarative approach uses less code, and may even look familiar to those web developers with React experience. React uses the declarative approach to rendering data and has gained popularity in the web development community.

Between Jetpack Compose and SwiftUI, there are many differences in the way we express user interfaces.

link SwiftUI

Builder Book

SwiftUI is an innovative, exceptionally simple way to build user interfaces across all Apple platforms with the power of Swift. SwiftUI also leverages declarative layouts.

Let's see a quick example of displaying a button on iOS:

Declarative UI:

VStack {
    Button(
        label: { Text("click me") }
    )
}

Imperative UI:

let button = UIButton()
button.setTitle("click me", for: .normal)
self.view.addSubview(button)

Once again, the declarative layout is used to describe a view. It feels more intuitive and expresses the view in it's current state. Each time we want to change the View according to it's state we can describe how to reflect the updates automatically.

link Comparing Views

Let's compare how Jetpack Compose and SwiftUI display data.

For example, let's preview the app landing screens and see how both platforms display a row of text:

Android - Composable

Builder Book

@Composable
fun DessertListRowView(dessert: Dessert) {
  Row {
    Column {
      Text(dessert.name, style = MaterialTheme.typography.h6)
      Text(dessert.description,
           style = MaterialTheme.typography.subtitle2, color = Color.Gray)
    }
  }
}

iOS - View

Builder Book

struct DessertListRowView: View {
    let dessert: Dessert

    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text(dessert.name)
                    .font(.title3)
                    .foregroundColor(.accentColor)
                Text(dessert.description_)
                    .font(.footnote)
                    .foregroundColor(.gray)
            }
        }
    }
}

As seen in the above code, we have two somewhat similar approaches to building a row of text. The key differences are as follows:

  1. We declare views in Jetpack Compose as functions, while in SwiftUI we declare them as structs.

Compose functions use the @Composable annotation, while SwiftUI structs declare a computed property called body, which implements the View protocol.

Both approaches implement a tree-like structure to represent the UI. @Composable functions and View structs can contain multiple subviews, such as Text.

  1. Views can be aligned vertically, horizontally or in a stack. It may be useful to note the syntax for aligning views on each platform:
Compose SwiftUI
Row HStack
Column VStack
Stack ZStack

Summary

While there are plenty of differences in each platform, both are taking steps toward creating apps with less code. Welcome to the future of mobile app development!

link Architectural Patterns

When writing the client-side code, developers will typically follow one of several common architecture patterns:

  • MVC (Model View Controller)
  • MVVM (Model View ViewModel)
  • MVP (Model View Presenter)
  • MVI (Model View Intent)

...and many more!

There is no such thing as "perfect" architecture, and each comes with a set of tradeoffs. With MVVM, we are able to separate the client-side logic from the UI and increase flexibility as any app requirements change.

For an iOS overview of MVVM, visit raywenderlich.com

For an Android overview of MVVM, visit raywenderlich.com

Sharing UI Behavior

Based on the official KMM documentation, if we wanted to share the UI behavior using an architectural pattern, we should use MVP or MVI. These patterns:

  • Make a clear distinction between the UI and presentation layers.

  • Are completely decoupled from the UI platform.

  • Are easily testable without a UI environment.

The problem with sharing UI behavior is that we can only share reactions to inputs and communications with the backend. As the documentation recommends, the user interface (including animations & transitions) should be platform-specific, so we would need write the UI separately anyway.

MVVM

Following the MVVM pattern, we write client-side view models to keep the logic separate from the user interface.

The following graph illustrates how the KMM repository is integrated with the client-side view models.

Once again, we use dependency injection to integrate the repository methods with the client app. In iOS we manually inject each dependency, while on Android we stick with Koin for automated DI.

For more information on architectural patterns for sharing UI behavior, visit kotlinlang.org

link Final Project - Choose Your Platform

Choose your platform. It's time to start building the client-side application for iOS and Android.

Final Project: Create the client-side implementation of the "JustDesserts" mobile app.

  • Choose between iOS (SwiftUI) and Android (Jetpack Compose) or both.
  • You may also want to follow an architectural pattern, such as MVVM.

For a SwiftUI introduction, visit developer.apple.com

For a Jetpack Compose introduction, visit developer.android.com

App Screens

The following is a complete list of screens to implement:

  1. DessertListView
  2. DessertDetailView
  3. FavoritesListView
  4. LoginView
  5. ProfileView
  6. DessertFormView
  7. ReviewFormView

For a preview of the completed app screens, download here.

Once again, try to implement this on your own before taking a peak at the solution code.

Solution Code

For the completed code, please refer to the main branch of the Github repository.

Today we introduced the future of mobile app development with SwiftUI and Jetpack Compose frameworks. Then we kick-started the client-side mobile app project.

Congratulations!!

Looking forward to seeing your next mobile app!

Questions? Feedback? Submit a new issue here.

link References

format_list_bulleted
help_outline