Website loading
Wolfpack Digital is a proud winner of
european tehnology awards logoeuropean tehnology awards logoeuropean tehnology awards logo

Building your App’s UI for 2023 – Part II

Blogpost-featured-image
publisher-image
Dan
Head of Mobile Development
Dec 30, 2022 • 7 min

If you're looking to build a mobile app in 2023 and beyond, it's crucial to pick the best tools for the job. In the first part of this series, we explored the available options for building native mobile app UI for iOS (UIKit and SwiftUI) and Android (XML layouts and Jetpack Compose).

We saw that in the last few years, Apple and Google published new declarative-based UI frameworks, promising to improve your app development experience.

Are they ready and worth it? Should you switch to them? This second part dives deeper into the pros and cons of each framework, as well as integration examples and tips.

If you didn't get the chance to check the first part, read it here.

Let's start with the iOS side.

The good, the bad, and SwiftUI

• Declarative framework
• Launched in 2019, current version: 4.0
• Programming language: Swift
• Way of use: Programmatically-build UI + Live Previews

The first strong point of SwiftUI seems to be that you can achieve more with less code. Let's see a quick example:

What we want to build: a reactive label that is automatically updated based on what you type in a text field.

UIKit code:

SwiftUI code:

Not a big difference, right? It's a huge difference. We explored this in more detail in a dedicated article.

Another great thing about SwiftUI is live previews. You can see in real-time the UI component you're building and run it in a local context. It's a step forward from UIKit, which had an interface builder, but you could also modify your UI from code without having the changes reflected on Storyboards or XIB files.

SwiftUI also has a more reactive approach compared to UIKit, and there are native mechanisms to support that. You now have property wrappers like @State, @ObservedObject, and @StateObject observed by your UI components. Whenever something changes, the engine rebuilds the layout, so you don't have to do it manually like before.

In conclusion, SwiftUI makes it much simpler to get into iOS development and create impressive user interfaces for your apps, even if you don't have too much iOS experience. But what's the catch?

As with any new framework, there's still room for improvements, and you also must accept some trade-offs. One of them is the lack of backward compatibility. SwiftUI only works on devices supporting iOS 13 and above, and it doesn't seem like a big deal today, but in the first 2-3 years after the official launch, it made it difficult for people to adopt it. Furthermore, everything that comes in a new version of SwiftUI is incompatible with older iOS versions.

As you get deeper into the code, you realize that it still depends on UIKit in many situations. For example, you can't fully customize the NavigationBar or the TabBar directly from SwiftUI. On iOS 13, lists are still based on UITableView. The TextEditorView can't change its white background color. The solutions to all these problems rely on UIKit code, as in the examples below.

Moving to other popular components like ScrollViews, they don't have delegates in SwiftUI, so you can't play with contentOffset or velocity. A workaround you can make is to use a GeometryReader for reading the sizes. Furthermore, if you want to integrate popular libraries like Google Maps, most don't have a SwiftUI API, so you need to rely on UIViewRepresentable.

Finally, navigating between screens seems simple, using NavigationView and NavigationLinks. However, this couples the navigation logic with the UI, making it difficult to control the flow, compared to an MVVM-C approach in UIKit, for example. The hybrid approach worked quite well for us, creating SwiftUI views and loading them into UIHostingControllers, which are then presented in the old-fashioned way.

Let's look at the Android side and see what's different there.

Jetpack Compose

• Declarative
• 2021, current version: 1.3.1
• Kotlin
• Programmatically + Preview
• Backwards compatible down to Android 5.0

Google's description states that Compose is a modern toolkit that simplifies and accelerates UI development on Android, bringing your apps to life with less code, powerful tools, and intuitive Kotlin APIs

Let's see how much of this is true. Since Compose is very similar to SwiftUI, we won't dive too deep into similar aspects, like Live Previews or the declarative nature. Here is a small code sample that can give you a good idea about the composition of elements and how the code looks.

If we want to put to the test Google's statement: "simplifies and accelerates UI development ... with less code", we can look at a common scenario to implement in a mobile app: a scrollable dynamic list.

Doing that with XML layouts requires the following:

  • Layout for the RecyclerView (the list itself)
  • Layouts for Items (each element of the list)
  • Adapter and ViewHolder (binding the layouts with data)
  • Configuring everything in a Fragment / Activity

On the flip side, creating the List with Compose would look like this:

It's pretty clear that the latter requires less code and less time once you're used to the framework. Therefore, it's easier for developers to learn it and reuse as much code as possible on the UI side. One more thing: it's all done in Kotlin. 🎉

Alright, but what about the downsides?

Well, the navigation side is similar to SwiftUI. You need to specify destinations inside composable functions, which couples the UI with the navigation logic. Moreover, the only way to send data from one screen to another is by using String arguments in route paths, making it difficult to send other types of data. You need to either use a share ViewModel or convert your data into JSON and pass it like that, a big string argument.

As you might expect, some components are not supported yet, like Autosize text, flow layouts, scrollbars, or snapping. You can check the roadmap for upcoming components.

Finally, on the performance side, you can occasionally notice longer screen loading times on older devices, especially if your app has a mix of XML layouts and Compose. The APK size and build times are also increasing in a Compose+XMLs app, but everything gets better after you fully convert it to Compose.

Speaking of mixing and converting, how can you make these new frameworks work along with the older ones?

Interoperability

The bright side of SwiftUI and Jetpack Compose is that you can use them together with the "old" frameworks, making it easier to try and adopt them over time in your projects.

a) SwiftUI integration

Probably the first scenario you'll meet will be to integrate SwiftUI into a UIKit-based project. There is a dedicated component called UIHostingController, which allows you to create a ViewController (fundamental class of iOS apps with UIKit) whose root view is a SwiftUI View. See the code example below:

If you want to make it work the other way around, to integrate a UIKit library into your SwiftUI project, there are two options: 

  • UIViewRepresentable for views;
  • UIViewControllerRepresentable for ViewControllers.

b) Jetpack Compose integration

Starting again with the popular scenario, Compose into an XML-based app, there's a dedicated component called ComposeView that you can use in your XML Layouts.

Looking at the reverse, when you need an XML Layout in a composable, the AndroidView component is what you need. It allows you to inflate a layout and show it inside its body.

Should you use SwiftUI and Compose right now?

Looking at the examples from above, they seem like a great choice for most situations. The development is faster, the code is easier to understand, and you only have to use one programming language across your entire app. In 80-90% of situations, it will make things easier and more enjoyable. 

However, remember the edge cases presented above and consider that for 10-20% of your app, SwiftUI and Compose will require workarounds and unexpected bug fixes. The development speed won't be great in the beginning, during the learning phase. Nonetheless, the bigger the app, the better return on investment in development time since things will speed up after getting used to the frameworks.

The safest way to try and adopt them would be to integrate one screen or component built with SwiftUI/Compose into an existing app of yours. If things don't go well, you can quickly revert it, but if it looks promising, you can continue in the same manner and slowly migrate towards the new declarative frameworks completely.

All in all, technology is moving forward, coming up with better versions of what we're already using, and that's the case with these declarative UI frameworks as well. They are not flawless, but they bring numerous advantages to the table, so it's worth trying and considering them for your next mobile app.

We hope this article gave insight into the latest trends and musts about how to build your mobile app in 2023. We want to thank our two great mobile software engineers who contributed to this, Roxana & Dan, and took the time to share their knowledge and insights.

tech insights & news

blog

Stay up to date with the tech solutions we build for startups, scale-ups and companies around the world. Read tech trends and news about what we do besides building apps.