
В мае на Google I/O 2019 было объявлено о новом фреймворке для разработки декларативного UI под Android с названием Jetpack Compose. Через месяц на WWDC 2019 было объявлено о декларативном UI фреймворке под IOS с названием SwiftUI. После этих конференции стало понятно, к чему стремится мобильная разработка, и мне захотелось разобраться, что можно сделать с помощью этих фреймворков на данный момент и в чем разница между ними.
Беглый обзор
После беглого обзора стало понятно о наличии крутой документации в IOS

и о полном отсутствии документации в android. Для ознакомления с фреймворком на официальной странице советуют посмотреть демо приложение.

Hello World
Начать использовать SwiftUI очень просто, достаточно обновить macOS до beta версии, установить Xсode 11 Beta, и создать новый проект, при этом выбрав галочку “Use SwiftUI”.

В случае с Jetpack Compose все сложнее. Нам нужно скачать последнюю сборку с Jetpack. И на основе модуля ui-demos, методом тыка, разобраться, как работать c фраймворком и какие зависимости необходимы. Очень печальное первое впечатление от Compose по сравнению с SwiftUI.

Пример Compose
@Composable
fun HelloWorld() {
Text(text = "Hello world")
}
Пример SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello SwiftUI!")
}
}
Верстка UI выглядит очень схоже, что логично, так как она стремится к декларативному виду.
Визуальный редактор
Со SwiftUi поставляется визуальный редактор(canvas),
который:
— перерисовывeт экран моментально после изменения кода;

— умеет показывать сразу же несколько девайсов;

— дает возможность изменять атрибуты ui элементов из редактора;

— и самое интересное и крутое — можно запустить код ui из редактора и посмотреть, как работает экран.

В случае с Jetpack Compose никакого визуального редактора нет.
Работа со списками
Для работы в SwiftUI просто создаем view строки
struct ListRow: View {
let number:Int
var body: some View {
Text.init(verbatim: "Text \(number)")
}
}
и вставляем в список.
List(Array(0...44)) { number in
ListRow.init(number: number)
}
Список готов.

В Compose пока нет виджета работающего со списками. На первый взгляд, можно воспользоваться Column.
Column {
listOf(
"Артем",
"Святослав",
"Женя",
"Никита",
"Алина",
"Леша",
"Вадим",
"Паша",
"Ваня"
)
.forEach { name ->
Text(text = name, style = +themeTextStyle { h2 })
}
}
Но он не скролящийся.

Что самое печальное, даже пример от Google не доработан и не скролится.

Иерархия view
В SwiftUI корневым элементом на смену UIViewController становится новый компонент View с новым жизненным циклом. Это говорит о том, что Apple, проанализировав плюсы и минусы реализации UIViewController, попыталась сделать все по-новому, реализовав лучшие черты.
struct ContentView : View {
var body: some View {
Text("ContentView2 ")
.onDisappear(){
print("onDisappear")
}
.onAppear{
print("onAppear")
}
}
}
В случае же с Compose корневыми элементами остаются старый добрый Activity или Fragment, вместо привычной загрузки XML.
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
Идет загрузка виджетов из Compose.
class ComposeActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CraneWrapper {
MaterialTheme {
Text(text = "Hello world")
}
}
}
}
}
Это ведет к тому, что в Android не избавляются от легаси корневых вьюх. Просто старыe UI компоненты теперь общаются не с XML, а с Compose виджетами.
Навигация
Для навигации в SwiftUI необходимо указать, какая view должна открываться по нажатию на кнопку.
NavigationButton(destination: LandmarkDetail()) {
LandmarkRow(landmark: landmark)
}
Внутри Compose реализации навигации нет. Но наверное она и не должна быть, так как корневым элементом являeтся Activity или Fragment, в которых уже давным давно
Поддерживаемая версия
SwiftUI работает с IOS 13, выходящей в сентябре, которая уже не будет поддерживаться на iPhone 5S, iPhone6, iPhone 6 Plus. Разработчикам стоит задуматься, насколько они будут готовы отказаться от этих моделей.
Compose планирует поддерживаться на любой версии Android.
Заключения
После конференций я думал, что появилось два новых мощных фреймворка для ui. В итоге получилось, что Apple сделал крутое решение, от которого у многих “состояние экзальтации”. А Google анонсировала фреймворк, который настолько сырой, что не понятно, как будут работать многие моменты даже на уровне концепций.
Комментарии (10)
andrew8712
24.06.2019 09:04Не забываем, что у Google есть Flutter, который уже работает. Приложения на Flutter запускаются на iOS 8. Так что Apple тут в роли догоняющего
artemgapchenko
24.06.2019 10:13Лучше знакомство с Compose было начать с видео с Google IO 2019, они там по ходу презентации несколько раз прямо сказали — ребята, это даже не альфа, ни в коем случае не думайте о том, что это скоро будет production-ready. Мы анонсируем Compose сейчас для того, чтобы как можно раньше начать собирать фидбек и прорабатывать концепцию.
JediPhilosopher
24.06.2019 12:35Я к андроид разработке мало отношения имею, может глупость скажу, но для меня это выглядит как какой-то шаг назад. Ну вот сто лет назад был Swing, и в нем надо было все лайауты писать в коде. И все ругались, мол, неудобно, неправильно смешивать код и визуал и т.п. Затем пришел андроид, и в нем появился мощный визуальный редактор и описание экранов в хмл, и все радовались. А теперь пришел вот этот Jetpack, и мы снова UI пишем в коде. В чем смысл? А потом будет еще одна библиотека и мы опять начнем интерфейс делать на каком-нибудь языке разметки?
agent10
24.06.2019 21:14Думая, что всё просто. Когда появились первые телефоны, то они были примерно одного размера и логика/динамика были тривиальными. Обычной разметки было достаточно. Дальше стали появляться другие форм-факторы, размеры, разрешения и накрученная логика. Т.е. опять вернулись к сложным и динамично меняющимся «окнам». Отсюда и возврат к истокам.
dector
25.06.2019 07:48Дело не в том, где мы описываем UI, а в том, как мы это делаем.
Compose, SwiftUI, Flutter, React, Vue, Litho, Svelte и т.д. и т.п. реализуют подход под названием Declarative UI. Что это значит — в двух словах можно прочесть, например, на сайте Flutter'a.
Соавтор Compose Leland Richardson собрал материалы (в основном из мира React), которые могут помочь мобильным разработчикам лучше понять новый подход. А тулинг — дело наживное (для Compose, например, обещают сделать его не хуже текущего, но не скоро, конечно же).
Статья не корректно сравнивает существующий продукт (SwiftUI) и продукт в состоянии proof-of-concept (Compose). artemgapchenko совершенно верно заметил, что сначала следовало бы посмотреть первоисточник (анонс на Google I/O).
Также в Slack-чате языка Kotlin есть канал #compose, где можно внести предложение или задать вопрос, получив ответ из первых рук (Romain Guy и Leland Richardson регулярно принимают участь в обсуждениях).ivanlardis Автор
26.06.2019 13:13Соглашусь с вами, наверное, некорректно сравнивать продукт на ранней стадии разработки с готовым продуктом. Но моя цель была сравнить, на каком этапе разработки сейчас представленные на конференциях продукты.
Как мне показалась, это интересная тема.
Насчет того, что сначала стоило посмотреть первоисточник — я с первоисточника и начал. И я понимал, что Compose в очень ранней стадии разработки и понимал, что гугл сказал, что хочет собрать обратную связь от разработчиков. Но при этом всем, когда начал смотреть Compose, в голове держал, то что Google уже создал Flutter, который вызвал большой интерес у Android разработчиков. И что у Google уже есть обратная связь по Flutter от тех же разработчиков, от которых просит обратную связь по Compose. И ждал от Compose, то что он будет реализован на основе отзывов о Flutter, хоть и на уровне концепции. А по факту, сейчас Compose — это пара полурабочих вьюх. Какого отзыва Google ждет и может ждать на основе такого? Складывается ощущение, что Google было важно анонсировать хоть что-то.
Насчет статьи надеюсь, хоть кому-то она была полезна.
vikarti
26.06.2019 05:20Собственно и для Андроид — Compose не первый.
Есть например Anko от Jetbrains
relativeLayout { padding = dip(16) val w = dip(200) val loginEditId = 155; val loginEdit = editText { id = loginEditId hint = "Login" }.layoutParams { centerInParent(); width = w } button("Sign up") { textSize = 18f onClick { doWork(loginEdit.getText().toString()) } }.layoutParams { below(loginEditId); sameLeft(loginEditId); width = w; topMargin = dip(8) } }
или так
constraintLayout { val sessionStart = textView { id = R.id.session_start textSize = 18f textColor = theme.getColor(R.attr.colorAccent) } val sessionTitle = textView { id = R.id.session_title textSize = 18f textColor = Color.BLACK }.lparams(0, wrapContent) textView { id = R.id.session_details textSize = 16f }.lparams(0, wrapContent) applyConstraintSet { // Connect without block // You may use view id or view itself to define connections connect( START of R.id.session_start to START of PARENT_ID margin dip(10), TOP of sessionStart to TOP of PARENT_ID margin dip(10) ) // constraint configuration on view sessionTitle { connect( START to START of PARENT_ID margin dip(SESSION_LIST_HEADER_MARGIN), TOP to TOP of PARENT_ID margin dip(10), END to END of PARENT_ID margin dip(10), BOTTOM to TOP of R.id.session_details ) horizontalBias = 0.0f defaultWidth = MATCH_CONSTRAINT_WRAP } // constraint configuration on view Id R.id.session_details { connect( START to START of PARENT_ID margin dip(SESSION_LIST_HEADER_MARGIN), TOP to BOTTOM of sessionTitle margin dip(2), END to END of PARENT_ID margin dip(10), BOTTOM to BOTTOM of PARENT_ID margin dip(2) ) horizontalBias = 0.0f defaultWidth = MATCH_CONSTRAINT_WRAP } } }
Preview-плагин для Android Studio есть.
Списки — ну поддержка RecyclerView более менее штатная и вообще совместимость со «стандартной» моделью для Android — получше.
Чем Compose СЕЙЧАС лучше Anko?
saag
У меня ощущение, что compose jetpack это Flutter, только на котлине
sergeyfitis
да так и есть, они тесно работают с коммандой Flutter, если посмотреть в репозиторий, там даже дарт код есть тыц