Jetpack Compose and SwiftUI are modern, declarative UI frameworks for building native mobile applications on Android and iOS, respectively. Both aim to simplify UI development by leveraging a declarative programming model, eliminating the complexities of imperative UI frameworks like Android Views or UIKit. They share similar design philosophies but have platform-specific differences.
Jetpack Compose vs SwiftUI
| Feature | Jetpack Compose | SwiftUI |
|---|---|---|
| Platform | Android | iOS, macOS, watchOS, tvOS |
| Programming Language | Kotlin | Swift |
| Release Year | 2021 | 2019 |
| Declarative UI | Yes | Yes |
| State Management | remember, mutableStateOf | @State, @Binding, @ObservedObject |
| UI Components | Composable functions (@Composable) | Structs conforming to View |
| Navigation | Built-in Navigation Component | NavigationView and NavigationLink |
| Animations | animate*AsState, AnimatedVisibility | .animation modifier, withAnimation |
| Performance | Optimized with Android’s rendering pipeline | Highly optimized for Apple platforms |
| Ecosystem | Jetpack Libraries | Apple Ecosystem (Combine, CoreData, etc.) |
| Development Tools | Android Studio | Xcode |
| Cross-Platform | Android-only | Multi-platform (iOS, macOS, etc.) |
Here are some key features and differences along with usage examples:
Basic Structure and Syntax
SwiftUI
Uses View protocol and struct-based UI components.
struct ContentView: View {
var body: some View {
Text("Hello, World!")
}
}
Jetpack Compose
Uses @Composable functions to build UI.
@Composable
fun Greeting() {
Text(text = "Hello, World!")
}
State Management
SwiftUI
Manages state with @State, @Binding, and @ObservedObject.
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
}
}
}
Read more: Difference between StateObject and EnvironmentObject.
Jetpack Compose
Uses remember and mutableIntStateOf to manage state within composable functions. Simple Counter App in Jetpack Compoe:
@Composable
fun Counter() {
var count by remember { mutableIntStateOf(0) }
Column {
Text(text = "Count: $count")
Button(onClick = { count++ }) {
Text("Increment")
}
}
}
List Rendering
SwiftUI
SwiftUI uses List to display a collection of data.
struct NamesList: View {
let names = ["Alice", "Bob", "Charlie"]
var body: some View {
List(names, id: \.self) { name in
Text(name)
}
}
}
Jetpack Compose
Jetpack Compose uses LazyColumn to display lists with efficient scrolling. Full Project.
@Composable
fun NamesList() {
val names = listOf("Alice", "Bob", "Charlie")
LazyColumn {
items(names) { name ->
Text(text = name)
}
}
}
Navigation
SwiftUI
SwiftUI uses NavigationView / NavigationStack and NavigationLink for navigation.
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: DetailView()) {
Text("Go to Detail")
}
}
}
}
struct DetailView: View {
var body: some View {
Text("Detail Screen")
}
}
Jetpack Compose
Jetpack Compose uses NavHost and composable destinations for navigation. Get the full code from GitHub.
@Composable
fun MainScreen(navController: NavController) {
Button(onClick = { navController.navigate("detail") }) {
Text("Go to Detail")
}
}
@Composable
fun DetailScreen() {
Text("Detail Screen")
}
// Setup NavHost
NavHost(navController, startDestination = "main") {
composable("main") { MainScreen(navController) }
composable("detail") { DetailScreen() }
}
Styling / Modifier
SwiftUI
SwiftUI uses Modifiers to style components, e.g., .padding(), .background().
struct StyledText: View {
var body: some View {
Text("Styled Text")
.font(.headline)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
}
Jetpack Compose
Jetpack Compose: Modifier parameter is used to chain styling attributes like .padding() and .background(). Get the full example.
@Composable
fun StyledText() {
Text(
text = "Styled Text",
fontSize = 20.sp,
color = Color.White,
modifier = Modifier
.padding(16.dp)
.background(Color.Blue)
.padding(8.dp)
.clip(RoundedCornerShape(10.dp))
)
}
Animations
SwiftUI
SwiftUI uses withAnimation, animation, and @State to create basic animations.
struct AnimatedButton: View {
@State private var scale: CGFloat = 1.0
var body: some View {
Button("Press Me") {
withAnimation {
scale = scale == 1.0 ? 1.5 : 1.0
}
}
.scaleEffect(scale)
}
}
Jetpack Compose
Jetpack Compose uses animate*AsState functions to handle animations in a declarative way.
@Composable
fun AnimatedButton() {
var scale by remember { mutableStateOf(1f) }
val animatedScale by animateFloatAsState(targetValue = scale)
Button(onClick = {
scale = if (scale == 1f) 1.5f else 1f
}) {
Text("Press Me", modifier = Modifier.scale(animatedScale))
}
}
Image Handling
SwiftUI
SwiftUI uses Image with system or custom images.
struct ImageView: View {
var body: some View {
Image(systemName: "star.fill")
.resizable()
.frame(width: 100, height: 100)
.foregroundColor(.yellow)
}
}
Jetpack Compose
Jetpack Compose uses Image composable, loading images from resources or URLs (with libraries like Coil). ImageLoad using Coil demo.
@Composable
fun ImageView() {
Image(
painter = painterResource(id = R.drawable.ic_star),
contentDescription = "Star",
modifier = Modifier
.size(100.dp)
.background(Color.Yellow)
)
}
Conditional UI Rendering
SwiftUI
SwiftUI uses Conditional views built using if statements directly in the view body.
struct ConditionalTextView: View {
@State private var showFirstText = true
var body: some View {
VStack {
if showFirstText {
Text("Hello, SwiftUI!")
} else {
Text("Goodbye, SwiftUI!")
}
Button("Toggle") {
showFirstText.toggle()
}
}
}
}
Jetpack Compose
Jetpack Compose uses a similar approach with if statements within the composable function. ConditionalViews demo.
@Composable
fun ConditionalTextView() {
var showFirstText by remember { mutableStateOf(true) }
Column {
if (showFirstText) {
Text("Hello, Jetpack Compose!")
} else {
Text("Goodbye, Jetpack Compose!")
}
Button(onClick = { showFirstText = !showFirstText }) {
Text("Toggle")
}
}
}
TextField (User Input)
SwiftUI
SwiftUI uses TextField with @State to bind input.
struct InputView: View {
@State private var inputText = ""
var body: some View {
VStack {
TextField("Enter text", text: $inputText)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Text("You entered: \(inputText)")
}
}
}
Jetpack Compose
Jetpack Compose uses TextField composable with remember for managing input state. TextFieldDemo code.
@Composable
fun InputView() {
var inputText by remember { mutableStateOf("") }
Column {
TextField(
value = inputText,
onValueChange = { inputText = it },
label = { Text("Enter text") },
modifier = Modifier.padding(16.dp)
)
Text(text = "You entered: $inputText")
}
}
Alerts and Dialogs
SwiftUI
SwiftUI uses .alert modifier to show alerts.
struct AlertView: View {
@State private var showAlert = false
var body: some View {
Button("Show Alert") {
showAlert = true
}
.alert(isPresented: $showAlert) {
Alert(
title: Text("Alert"),
message: Text("This is an alert message."),
dismissButton: .default(Text("OK"))
)
}
}
}
Jetpack Compose
Jetpack Compose uses AlertDialog composable. AlertsDemo.
@Composable
fun AlertView() {
var showAlert by remember { mutableStateOf(false) }
if (showAlert) {
AlertDialog(
onDismissRequest = { showAlert = false },
title = { Text("Alert") },
text = { Text("This is an alert message.") },
confirmButton = {
Button(onClick = { showAlert = false }) {
Text("OK")
}
}
)
}
Button(onClick = { showAlert = true }) {
Text("Show Alert")
}
}
Switch (Toggle)
SwiftUI
SwiftUI uses Toggle for switches.
struct ToggleView: View {
@State private var isOn = false
var body: some View {
Toggle(isOn: $isOn) {
Text("Enable Feature")
}
.padding()
}
}
Jetpack Compose
Jetpack Compose uses Switch with remember to manage its state. ToggleDemo
@Composable
fun ToggleView() {
var isOn by remember { mutableStateOf(false) }
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(16.dp)
) {
Text("Enable Feature")
Spacer(modifier = Modifier.width(8.dp))
Switch(
checked = isOn,
onCheckedChange = { isOn = it }
)
}
}
Horizontal Scroll (Carousel)
SwiftUI
SwiftUI uses ScrollView with .horizontal axis.
struct HorizontalCarouselView: View {
let items = ["Item 1", "Item 2", "Item 3"]
var body: some View {
ScrollView(.horizontal) {
HStack {
ForEach(items, id: \.self) { item in
Text(item)
.padding()
.background(Color.gray)
.cornerRadius(8)
}
}
}
}
}
Jetpack Compose
Jetpack Compose uses LazyRow for horizontal scrolling. HorizontalScroll
@Composable
fun HorizontalCarouselView() {
val items = listOf("Item 1", "Item 2", "Item 3")
LazyRow {
items(items) { item ->
Text(
text = item,
modifier = Modifier
.padding(8.dp)
.background(Color.Gray)
.padding(16.dp)
.clip(RoundedCornerShape(8.dp))
)
}
}
}
Stacking Views (VStack/HStack vs. Column/Row)
SwiftUI
SwiftUI uses VStack for vertical stacking and HStack for horizontal.
struct StackingViews: View {
var body: some View {
VStack {
HStack {
Text("Left")
Text("Center")
Text("Right")
}
.padding()
Text("Below the HStack")
}
}
}
Jetpack Compose
Jetpack Compose uses Column and Row.
@Composable
fun StackingViews() {
Column {
Row(
modifier = Modifier.padding(8.dp)
) {
Text("Left")
Text("Center")
Text("Right")
}
Text("Below the Row")
}
}
ScrollView
SwiftUI
SwiftUI uses ScrollView.
struct VerticalScrollView: View {
var body: some View {
ScrollView {
VStack {
ForEach(1...10, id: \.self) { index in
Text("Item \(index)")
.padding()
}
}
}
}
}
Jetpack Compose
Jetpack Compose uses VerticalScroll or HorizontalScroll in Modifier. ScrollDemo.
@Composable
fun VerticalScrollView() {
Column(
modifier = Modifier.verticalScroll(rememberScrollState())
) {
for (index in 1..10) {
Text("Item $index", modifier = Modifier.padding(8.dp))
}
}
}
Card Design
SwiftUI
SwiftUI uses RoundedRectangle and .background. Example.
struct CardView: View {
var body: some View {
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue)
.frame(width: 200, height: 100)
.overlay(
Text("Card Content")
.foregroundColor(.white)
)
.shadow(radius: 5)
}
}
Jetpack Compose
Jetpack Compose uses Card composable.
@Composable
fun CardView() {
Card(
shape = RoundedCornerShape(10.dp),
elevation = 4.dp,
modifier = Modifier.size(width = 200.dp, height = 100.dp)
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.background(Color.Blue)
) {
Text("Card Content", color = Color.White)
}
}
}
Applying Background Image
SwiftUI
SwiftU uses .background with Image. Background.
struct BackgroundImageView: View {
var body: some View {
Text("Overlay Text")
.frame(width: 200, height: 100)
.background(
Image("backgroundImage")
.resizable()
.aspectRatio(contentMode: .fill)
)
.clipped()
}
}
Jetpack Compose
Jetpack Compose uses Modifier.background with painterResource. Full example with loading image from drawable and assets folder.
@Composable
fun BackgroundImageView(modifier: Modifier) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
.paint(
painter = painterResource(id = R.drawable.snow),
contentScale = ContentScale.Crop
)
) {
Text("Overlay Text", color = Color.White)
}
}