Розеттский камень для двойной нативной мобильной разработки

Если вы хотите вести разработку на обоих родных языках одновременно, эта статья включает несколько фундаментальных примеров кода для Swift и Kotlin.

Базовая настройка

При написании кода в Android Studio есть один параметр, который вы захотите включить в своих настройках, а именно «Автоматический импорт» и «Автоматическая очистка».

В отличие от SwiftUI, где большинство компонентов включается, когда вы «импортируете SwiftUI» в верхней части файла, Jetpack Compose основан на Kotlin/Java, где вы импортируете каждый используемый компонент. Включение настроек автоматического импорта сэкономит вам много времени, пытаясь выяснить, какую версию вещи импортировать (я узнал это на собственном горьком опыте). На скриншоте ниже выделены параметры, которые мы хотим включить.

Я хочу, чтобы это был живой документ, изменяющийся и улучшающийся по мере роста моих знаний, поэтому, если вы не найдете то, что ищете сегодня, не стесняйтесь сохранить эту статью в закладки и вернуться позже, чтобы увидеть, если она был добавлен.

Дополнительные ресурсы

Если вам нужно более подробное руководство о языковой разнице между Swift и Kotlin, ознакомьтесь с этой статьей от Kodeco: https://www.kodeco.com/6754-a-comparison-of-swift-and-kotlin-languages.

Если вам нужен полный список модификаторов, доступных (и в каком объеме) в Jetpack Compose, ознакомьтесь с их документацией: https://developer.android.com/jetpack/compose/modifiers-list

Если вы новичок в SwiftUI, вы можете узнать больше о том, как создавать приложения с помощью SwiftUI, здесь: https://medium.com/@jpmtech/basics-of-swiftui-c8eab0edf13b.

Небольшое замечание по формату статьи, я приведу пример кода в SwiftUI, затем прямо под ним приведу такой же пример с использованием Jetpack Compose.

Если вы получаете пользу от этой статьи, рассмотрите возможность подписаться на меня, аплодировать этой статье или поделиться ею, чтобы помочь другим легче найти статью.

Если у вас есть какие-либо вопросы по теме или вы знаете другой способ выполнить ту же задачу, не стесняйтесь ответить на сообщение или поделиться им с другом и узнать их мнение по этому поводу.

Если вы хотите узнать больше о Swift и SwiftUI, вы можете ознакомиться с другими статьями, которые я написал здесь: https://medium.com/@jpmtech.

Если вы хотите увидеть приложения, созданные с помощью Swift и SwiftUI, вы можете ознакомиться с моими приложениями здесь: https://jpmtech.io/apps.

Спасибо, что нашли время оценить мою работу! Теперь давайте перейдем к содержанию, которое привело вас сюда.

Отображать представления, которые складываются вертикально

SwiftUI

VStack {
  // code here
}

Реактивный ранец

Column {
  // code here
}

Отображение представлений, которые располагаются горизонтально

SwiftUI

HStack {
  //code here
}

Реактивный ранец

Row {
  //code here
}

Отображает виды друг над другом (стек глубины)

SwiftUI

ZStack {
  //code here
}

Реактивный ранец

Box {
  //code here
}

Разделитель, который заполняет все доступное пространство

SwiftUI

Spacer()

Реактивный ранец

Spacer(Modifier.weight(1f))

Кнопка

SwiftUI

Button {
  //code here
} label: {
  Text("click me")
}

Реактивный ранец

Button(onClick = {
    //code here
}) {
  Text(text = "click me")
}

Отображение текста

SwiftUI

Text("I’m text")

Реактивный ранец

Text(text = "I’m text")

Получение текста из пользовательского ввода с использованием локальной переменной состояния

SwiftUI

@State var userInput = ""
//...
TextField("input name", text: $userInput)

Реактивный ранец

var userInput = remember {
  mutableStateOf("")
}
//...
TextField(
  value = userInput.value,
  onValueChange = {userInput.value = it},
  label = { Text(text = "input name") }
)

Логический тумблер/переключатель

SwiftUI

@State var isOn = true
//...
Toggle("the toggle is", isOn: $isOn)

Реактивный ранец

var isOn = remember {
  mutableStateOf(true)
}
//...
Row {
  Checkbox(
    checked = isOn.value,
    onCheckedChange = {isOn.value = it}
  Text(
    text = "the toggle is",
    modifier = Modifier.align(Alignment.CenterVertically)
  )
}

Создание средства выбора даты

SwiftUI

@State var selectedDate = Date.now
//...
DatePicker("select a date", selection: $selectedDate, displayedComponents: .date)

Jetpack Compose (в настоящее время еще не доступен в Material 3, поэтому мы создадим свой собственный, который будет выглядеть и действовать так же, как на iOS)

@Composable
fun CustomDatePicker(labelText: String, selection: MutableState<ZonedDateTime>) {
  val context = LocalContext.current
  //the month is off by 1 on this older built in date picker,
  //which is the reason for the random (+/-)1 values
  val datePickerDialog = DatePickerDialog(
    context,
    {_: DatePicker, selectedYear: Int, selectedMonth: Int, selectedDayOfMonth: Int ->
      selection.value = ZonedDateTime.of(
        selectedYear,
        selectedMonth + 1,
        selectedDayOfMonth,
        selection.value.hour,
        selection.value.minute,
        selection.value.second,
        selection.value.nano,
        selection.value.zone
      )
    }, selection.value.year, selection.value.monthValue - 1, selection.value.dayOfMonth
  )

  Row {
    Text(
      text = labelText,
      modifier = Modifier.align(Alignment.CenterVertically)
    )
    Spacer(Modifier.weight(1f))
    Button(onClick = {
      datePickerDialog.show()
    }) {
      Text(DateTimeFormatter.ofPattern("M/d/yyyy").format(selection.value)
    }
  }
}

// in the view we want to use it in
var selectedDate = remember {
  mutableStateOf(ZonedDateTime.now())
}
//...
CustomDatePicker(labelText = "select a date", selection = selectedDate)

Двусторонняя привязка

SwiftUI

//parent view
@State var myValue = true
//...
ChildView(myBinding: $myValue)

//child view
@Binding var myBinding: Bool
//...
Button {
  myBinding = false
} label: {
  Text("change binding to false")
}

Реактивный ранец

//parent view
var myValue = remember {
  mutableStateOf(true)
//...
ChildView(myBinding = myValue)

//child view
@Composable
ChildView(myBinding: MutableState<Boolean>) {
  Button(onClick = {
    myBinding = false
  }) {
    Text(text = "change binding to false")
  }
}

Отображение изображений/значков, которые уже есть на устройстве

SwiftUI

Если вы хотите узнать больше о встроенных изображениях для iOS под названием SF Symbols, прочтите эту статью: https://medium.com/@jpmtech/how-to-use-custom-colors-in-an- SF-символ-18b72451b15f

Image(systemName: "person")

Реактивный ранец

Icon(imageVector = Icons.Default.Person, contentDescription = null)

Добавление отступов к представлению

SwiftUI

Text("vertical specific").padding(.vertical, 16)
Text("horizontal default").padding(.horizontal)
Text("leading specific").padding(.leading, 16)
Text("trailing default").padding(.trailing)
Text("default padding on all sides").padding()

Реактивный ранец

//vertical
modifier=Modifier.padding(vertical=16.dp)
//horizontal
modifier=Modifier.padding(horizontal=16.dp)
//leading
modifier=Modifier.padding(start=16.dp)
//end
modifier=Modifier.padding(end=16.dp)
//Jetpack Compose does not have a default padding

Сделать представление прокручиваемым

SwiftUI

ScrollView {
  // content
}

Реактивный ранец

Column(
  modifier = Modifier
  .verticalScroll(rememberScrollState())
) {
  // content
}