On my previous post I mentioned how I wanted to see if I could copy and paste code between Jetpack Compose and SwiftUI. This is the results of that experiment. I made a simple 2 screen app that has buttons going back and forth. I'll show you screen shots and the code for each app. Before that I want to point out that this was all made in one file. I know that isn't the proper way to structure apps but this is just a little experiment.

Jetpack Compose

Code

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NavigationTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    NavigationApp()
                }
            }
        }
    }
}

@Composable
fun NavigationApp(){
    val navController = rememberNavController()
    NavHost(navController = navController, startDestination = "first") {
        composable("first") { ScreenOne(navController) }
        composable("second") { ScreenTwo(navController) }
    }
}

@Composable
fun ScreenOne(navController: NavHostController) {
    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text(
                        text = "Navigation",
                        textAlign = TextAlign.Center,
                        modifier = Modifier.fillMaxWidth()
                    )
                }
            )
        },
        content = {
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    text = "Screen 1",
                    modifier = Modifier.padding(bottom = 10.dp)
                )
                Button(
                    content = {
                        Text("Go forward")
                    },
                    onClick = {
                    navController.navigate("second")
                    }
                )
            }
        }
    )
}

@Composable
fun ScreenTwo(navController: NavHostController) {
    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text(
                        text= "Navigation",
                        textAlign = TextAlign.Center,
                        modifier = Modifier.fillMaxWidth()
                    )
                }
            )
        },
        content = {
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    text = "Screen 2",
                    modifier = Modifier.padding(bottom = 10.dp)
                )
                Button(
                    content = {
                        Text(text = "Go Backwards")
                    },
                    onClick = {
                        navController.navigateUp()
                    }
                )
            }
        }
    )
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    NavigationTheme {
        NavigationApp()
    }
}

Screenshots

Screen 1 & 2 of Jetpack Compose app

Thoughts

This was actually a bit challenging for me. As far as navigation goes I wasn't able to wrap my mind around it the first few times. I'm so use to using nav graphs in Android that I immediately assumed that I'd have one and things would work the same. I was extremely wrong. I found this article that was able to break down the logic for me. Now I'll try to past this code directly into swift UI with a little doctoring.

Swift UI

Initial Paste/Doctoring

Jetpack Compose code copy and pasted to Xcode, and then fixed for errors. (no navigation)

Code - Final

struct ContentView: View {
    var body: some View {
        NavigationView {
            ScreenOne()
        }
    }
}

struct ScreenOne: View {
    var body: some View {
        VStack(content: {
            Text("Screen 1")
                .padding(.bottom, 10.0)
                .navigationTitle("Navigation")
            
            NavigationLink(destination: ScreenTwo()) {
                Text("Go forward")
            }
        })
    }
}

struct ScreenTwo: View {
    @Environment(\.presentationMode) var presentation
    var body: some View {
        VStack(content: {
            Text("Screen 2")
                .padding(.bottom, 10.0)
                .navigationTitle("Navigation")
                .navigationBarBackButtonHidden(true)
            
            Button("Go Backwards"){
                self.presentation.wrappedValue.dismiss()
            }
        })
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Screenshots

Screen 1 & 2 of SwiftUI app

Thoughts

Again navigation took me bit to grasp but not as long as Android. I think this might be because of how they are used. Android navigation is explicitly passed but iOS is not. Something I need to check on after this is the environment variable and why it has to be there to pop the backstack. That is a concept/logic I'm still unfamiliar with.


In conclusion the ability to copy and paste across platforms is kinda possible. I don't feel like it took me long to build the iOS app. All I really changed was the navigation. Granted Android stumped me for navigation understanding, but I think regardless this is a really cool thing. If you can learn the basics of both I think you will be an unstoppable force in the field (especially if you freelance). This is a slightly different meaning to "Code Once, Distribute to all", but its only a half a step off.

I look forward to continued testing of this copy and paste theory as time goes on. I can definitely see a "joint ide" in the future or some type of quick conversion app.