Android jetpack compose tutorial

Jetpack Compose Tutorials

Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

Audience

This tutorial has been prepared for the beginners to help them understand the basics of Jetpack compose. After completing this tutorial, you would understand the basics of Jetpack compose and will be able to build a simple android app using it.

Prerequisites

In this tutorial, I strongly recommend that you gain some basic knowledge of Kotlin programming language before proceeding with Jetpack compose.

Table of Content

  • Overview
  • Environment set up
  • Hello World example
  • UI Layouts
  • mini project
  • UI Controls
  • mini project
  • State Management
  • mini project
  • Navigation
  • mini project
  • Styles and Theme
  • Material Design Components
  • mini project
  • Android Useful Examples
  • Local Database
  • Internationalization
  • Accessing Rest API
  • Animation
  • Testing
  • Jetpack Compose Mini Project

Note: as at the time of writing this tutorial jetpack compose version is alpha-06, I will always make changes to this document to be updated

Overview:

What is Jetpack Compose?

Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

Why Jetpack Compose?

* Concise and Idiomatic Kotlin

— Built with the benefits that Kotlin brings

* Declarative

— Fully declarative for defining UI components

* Compatible

— Compatible with existing views

* Enable Beautiful Apps

— Designed with Material Design

* 100% Kotlin

– written in Kotlin programming language

* Accelerate Development

— writing less code and using tools

* One codebase

* Less code

  • Do more with less code and avoid entire classes of bugs, so code is simple and easy to maintain.

* Accelerate Development

  • Compatible with all your existing code so you can adopt when and where you want. Iterate fast with live previews and full Android Studio support.

Jetpack Compose is currently in Developer Preview. The API surface is not yet finalized, and should not be used in production apps.

Environment Set-Up:

For the best experience developing with Jetpack Compose, you should download the latest canary version of Android Studio Preview.

Источник

Основы Jetpack Compose: Урок №1

В этом руководстве вы создадите простой пользовательский интерфейс с помощью декларативных функций Jetpack Compose.

Что такое Jetpack Compose

Jetpack Compose — это современный набор инструментов для создания собственного пользовательского интерфейса в Android-приложении. Этот декларативный фреймворк упрощает и ускоряет разработку пользовательского интерфейса на Android с меньшим количеством кода, мощными инструментами и интуитивно понятными API-интерфейсами Kotlin.

В этом руководстве вы создадите простой пользовательский интерфейс с помощью декларативных функций. Вы не будете редактировать макеты XML или напрямую создавать виджеты пользовательского интерфейса. Вместо этого вы вызовете функции Jetpack Compose, чтобы сказать, какие элементы вы хотите видеть, а компилятор Compose сделает все остальное.

Примечание: Jetpack Compose в настоящее время находится в альфа-версии. API еще не доработаны, изменения запланированы и возможны.

Урок 1: Composable функции

Фреймворк работает на основе Composable функций. Эти функции позволяют программно определять пользовательский интерфейс вашего приложения, описывая его форму и зависимости, а не сосредотачиваться на процессе создания пользовательского интерфейса. Чтобы создать “составную” функцию, просто добавьте аннотацию @Composable к имени функции.

Добавляем текстовый элемент

Для начала следуйте инструкциям по настройке Jetpack Compose и создайте приложение, используя шаблон Empty Compose Activity. Шаблон по умолчанию уже содержит некоторые элементы Compose, но давайте создадим его шаг за шагом. Сначала удалите функции Greeting и Default Preview и удалите блок setContent из MainActivity, оставив действие пустым. Скомпилируйте и запустите пустое приложение.

Теперь добавьте текстовый элемент в пустое действие. Вы делаете это, определяя блок содержимого и вызывая функцию Text().

Блок setContent определяет макет активити. Вместо определения содержимого макета с помощью XML-файла, мы вызываем composable функции. Jetpack Compose использует кастомный плагин компилятора Kotlin для преобразования этих составных функций в элементы пользовательского интерфейса приложения. Например, функция Text() определяется библиотекой Compose UI — вы вызываете эту функцию, чтобы объявить текстовый элемент в своем приложении.

Определите Composable функцию

Составные функции могут вызываться только в рамках других составных функций. Чтобы сделать функцию составной, добавьте аннотацию @Composable. Чтобы попробовать это, определите функцию Greeting(), которой передается имя и которая использует это имя для настройки текстового элемента.

Предварительный просмотр вашей функции в Android Studio

Текущая canary сборка Android Studio позволяет вам предварительно просматривать ваши составные функции прямо в IDE, вместо того, чтобы загружать приложение на устройство Android или в эмулятор. Основное ограничение заключается в том, что составная функция не должна принимать никаких параметров. По этой причине вы не можете предварительно просмотреть функцию Greeting() напрямую. Вместо этого создайте вторую функцию с именем PreviewGreeting(), которая вызывает Greeting() с соответствующим параметром.

Читайте также:  Виды зарядок для телефонов андроид

Добавьте аннотацию @Preview перед @Composable.

Пересоберите свой проект. Само приложение не поменяется, поскольку новая функция previewGreeting() нигде не вызывается, но Android Studio добавляет окно предварительного просмотра. В этом окне отображается предварительный просмотр элементов пользовательского интерфейса, созданных Composable функцией, отмеченной аннотацией @Preview. Чтобы обновить предварительный просмотр в любое время, нажмите кнопку обновления в верхней части окна предварительного просмотра.

Источник

Jetpack Compose — как легко построить UI на Android

В июле этого года вместе с Android Studio Arctic Fox вышла одна из долгожданных библиотек — Jetpack Compose. Она позволяет создавать пользовательский интерфейс в декларативном стиле и обещает быть революцией в построении UI.

Разбираемся, так ли это на самом деле, какие у библиотеки преимущества и недостатки. Подробности — в статье.

Преимущества Jetpack Compose

Jetpack Compose — это набор инструментов для разработки UI в Android-приложении. Он призван ускорить и упростить разработку пользовательского интерфейса, избавить от лишнего кода и соединить модель реактивного программирования с лаконичностью Kotlin.

Сразу с места в карьер — какие есть преимущества у библиотеки:

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

2. Интуитивно понятный. Compose использует декларативный API — разработчику нужно лишь сказать, что сделать, а все остальное ляжет на плечи библиотеки.

3. Удобство внедрения. Compose совместим с любым существующим кодом. Например, можно вызвать Compose-код из вьюх (view) и, наоборот, вьюхи из Compose. Многие библиотеки вроде Jetpack Navigation, ViewModel и Coroutines уже адаптированы под Compose, что позволяет сравнительно быстро внедрить его в свой код. Кроме того, Android Studio Arctic Fox поддерживает превью создаваемых вьюх.

4. Имеет обширный инструментарий. Jetpack Compose позволяет создавать красивые приложения с прямым доступом к Android Platform API и build-in поддержкой Material Design, тёмной темы, анимаций и других крутых штук.

Далее пройдёмся по основным аспектам библиотеки и посмотрим, как сильно повышается производительность приложения.

Подключение к проекту

Чтобы подключить Jetpack Compose к проекту, необходимо указать некоторые строки кода в своем build.gradle.

В рутовом объявим переменную с версией Compose:

Здесь мы указываем, что в проекте будем использовать Jetpack Compose и объявляем необходимые зависимости (подробнее про зависимости можно почитать в официальном гайде).

Дальше всё просто. В активити (activity) объявлем Composable-функцию, строим иерархию вьюх с указанием необходимых атрибутов и смотрим результат.

Пройдемся по коду. Я написал две реализации вёрсток различной сложности:

1. Простая реализация

Добавляет TextView в вёрстку с текстом с конкатенацией Hello и аргумента, переданного в Greeting.

Важно отметить, что имена Composable-функций начинаются с заглавной буквы. Это соглашение по наименованию функций, поэтому если писать со строчной, то студия будет подсвечивать неверный нейминг.

2. Более сложная реализация

Этот вариант представляет собой скролящийся экран, который содержит изображение, текст и кнопку. Рассмотрим некоторые особенности:

Необходимо объявить Scroll State. Только не обычный, а тот, который позволяет сохранять состояние скролла сквозь рекомпозицию — rememberScrollState().

Column представляет собой ViewGroup с вертикальным расположением элементов.

Modifier позволяет управлять атрибутами, добавлять декорации и поведение к вьюхам.

Остальное интуитивно понятно. И это как раз одна из ключевых особенностей Jetpack Compose — даже если вы не использовали библиотеку ранее, то всё равно с ней разберётесь.

Добавить вьюхи в активити можно через extension setContent <>, например:

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

Для тестирования воспользуемся библиотекой Jetpack Benchmark, о которой, кстати, тоже рассказывали в отдельной статье. Код теста выглядит так:

Протестируем три версии установки вьюхи в активити:

При передаче ресурса в setContentView.

При передаче вьюхи в setContentView.

Итоги тестирования можно посмотреть в таблице: левый столбец — название теста, правый — время на выполнение:

Источник

Погружение в JetPack Compose. Часть 1/2

Собрал здесь лучшие статьи, библиотеки и проекты на Jetpack Compose:
Jetpack Compose Awesome

Ожидания по поводу разработки пользовательского интерфейса выросли. Сегодня мы не можем создать приложение и удовлетворить потребности пользователя, не имея отточенного пользовательского интерфейса, включая анимацию и движение UI-элементов. Этих требований не существовало при создании текущего UI Toolkit-а системы Android. Чтобы решить технические проблемы быстрого и эффективного создания безупречного пользовательского интерфейса, мы представили Jetpack Compose — современный набор инструментов для создания UI, который помогает разработчикам приложений добиться успеха на этом новом поприще.

В двух статьях мы расскажем о преимуществах Compose и посмотрим, как это работает «под капотом». Для начала в этом посте я расскажу о проблемах, которые решает Compose, о причинах некоторых наших дизайнерских решений и о том, как они помогают разработчикам приложений. Кроме того, я расскажу о ментальной модели Compose, о том, как вы должны думать о коде, который вы пишете в Compose, и о том, как вы должны формировать свой API.

Какие проблемы решает Compose?

Разделение ответственности (Separation of concerns) — это хорошо известный принцип разработки программного обеспечения. Это одна из фундаментальных вещей, которую мы, как разработчики приложений, узнаем. Несмотря на то, что этот принцип хорошо известен, часто трудно понять, соблюдается ли этот принцип на практике. Может быть полезно думать об этом принципе как о термине типа «сцепление» или «связанность».

Читайте также:  Web tts reader android

Когда мы пишем код, мы создаем модули, которые состоят из нескольких сущностей (unit-тов). Связанность (Coupling) — это зависимость между сущностями в разных модулях, которая отражает то, ка части одного модуля влияют на части других модулей. Целостность (Cohesion)- это, наоборот, взаимосвязь между сущностями (юнитами) в модуле и показывает, насколько хорошо сгруппированы юниты в модуле.

При написании поддерживаемого программного обеспечения наша цель — минимизировать связанность и максимизировать целостность.

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

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

Давайте перейдем к практике, и рассмотрим современные подходы решения этого вопроса в мире Android-разработки. Возьмем для примера ViewModel и XML-лейаут.

ViewModel предоставляет данные лейауту. Оказывается, здесь может быть спрятано много зависимостей: большая взаимосвязь между ViewModel и лейаутом. Один из наиболее частых и х хорошо знакомых нам случаев сильной взаимосвязи — это использование API (от Android или сторонних библиотек — прим. переводчика), в которых требуется знание о внутренностях самого XML-макета, например метод findViewByID .

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

Большинство современных приложений отображают пользовательский интерфейс динамически и меняются в процессе выполнения. В результате необходимо не только проверить, что эти зависимости (т. е. View-элементы) предоставляются XML-макетом, но также и то, что они будут предоставляться во время работы программы. Если элемент покидает иерархию View во время выполнения, некоторые из этих зависимостей могут быть нарушены и могут привести к таким проблемам, как NulReferenceExceptions .

Примечание переводчика:

Под «предоставлением зависимостей» имеется в виду наличие вьюшки в самом лейауте и возможность найти её через findViewById.

Обычно ViewModel определяется языке программирования Kotlin, а макет — в XML. Из-за этой разницы в языке существует принудительное разделение, хотя ViewModel и XML-макет иногда могут быть тесно связаны. Другими словами, они очень тесно связаны.

Возникает вопрос: что, если бы мы начали определять лейаут, т. е. структуру нашего пользовательского интерфейса на одном языке? Что, если мы выберем Kotlin?

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

Теперь вы можете подумать, что вы смешиваете логику с пользовательским интерфейсом. Реальность такова, что у вас будет логика, связанная с пользовательским интерфейсом, в вашем приложении, независимо от того, как оно структурировано. Сама структура не может этого изменить.

Но то, что может сделать фреймворк, — это предоставить вам инструменты, упрощающие разделение: этим инструментом является функция Composable. Функции — это то, что вы, вероятно, использовали в течение долгого времени для разделения задач в других местах вашего кода. Навыки, которые вы приобрели для такого рода рефакторинга и написания надежного, поддерживаемого, чистого кода, — те же навыки применимы и к Composable -функциям.

Устройство Composable-функции

Это пример Composable-функции.

Здесь функция получает данные как параметры из класса appData . В идеале это неизменяемые данные, которые Composable-функция не меняет: Composable-функция должна быть функцией преобразования для этих данных. Следовательно, мы можем использовать любой код на Kotlin, чтобы взять эти данные и использовать их для описания нашей иерархии, например вызвав функции Header() и Body() .

Это означает, что мы вызываем другие Composable-функции, и эти вызовы отражают структуру нашего UI. Мы можем использовать все примитивы предоставляемые Kotlin-ом. Мы можем включить операторы if и циклы for для управления структурой UI, чтобы справиться с более сложной логикой пользовательского интерфейса.

Composable-функции часто используют конечный лямбда-синтаксис Kotlin, поэтому Body() — это Сomposable-функция, которая принимает composable-лямбду в качестве параметра. Это подразумевает иерархию или структуру, поэтому Body() обертывает здесь набор элементов.

Декларативный UI

Декларативный — это модное, но важное слово. Когда мы говорим о декларативном программировании, мы говорим об его отличии от императивного программирования. Давайте рассмотрим пример.

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

С императивным интерфейсом нам, возможно, придется написать такую ​​функцию подсчета обновлений:

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

Если мы перепишем эту логику в декларативном стиле, мы получим нечто подобное:

Здесь мы говорим:

Если счет больше 99, покажи огонь ?.

Читайте также:  Winrar для андроид взломанный

Если счет больше 0, покажи бумагу

Если счетчик больше 0, отобрази значок счетчика

Это то, что подразумевается под декларативным API. Код, который мы пишем, описывает нужный нам пользовательский интерфейс, но не описывает, как перейти в это состояние. Важным здесь является то, что при написании декларативного кода, подобного этому, вам больше не нужно беспокоиться о том, в каком предыдущем состоянии был ваш пользовательский интерфейс, вам нужно только указать, каким должно быть ваше текущее состояние. Фреймворк контролирует, как перейти из одного состояния в другое, поэтому нам больше не нужно об этом думать.

Композиция vs Наследование

В разработке программного обеспечения композиция — это то, как несколько частей более простого кода могут объединяться в более сложный блок кода. В объектно-ориентированной модели программирования одной из наиболее распространенных форм композиции является наследование на основе классов. В мире Jetpack Compose, поскольку мы работаем только с функциями, а не с классами, метод композиции сильно отличается, но имеет много преимуществ перед наследованием. Давайте посмотрим на пример.

Допустим, у нас есть View и мы хотим создать поле ввода. В случае с наследованием наш код может выглядеть так:

View — это базовый класс. ValidatedInput является подклассом Input . Для проверки даты DateInput наследуется от ValidatedInput . Но тогда возникает проблема: мы хотим создать компонент с вводом диапазона дат, следовательно, нам нужно осуществлять проверку по двум датам — дате начала и дате окончания. Вы можете создать подкласс DateInput , но вам нужно сделать это дважды, а вы не можете этого сделать. Это ограничение наследования: у нас должен быть единственный родитель, от которого мы наследуем.

В Compose это не так сложно. Допустим, мы начинаем с базового composable-компонента Input :

Когда мы создаем наш ValidatedInput , мы просто вызываем Input в теле нашей функции. Затем мы можем дополнить его чем-нибудь для проверки.

Затем для DataInput мы можем напрямую вызвать ValidatedInput .

Теперь, когда мы сталкиваемся с вводом диапазона дат, у нас больше нет проблемы: это всего лишь два вызова вместо одного.

При создании UI-компонентов при помощи Compose, у них нет единственного родителя, и это решает проблему, которая возникла с в случае с использованием наследования.

Другой тип проблемы композиции — это абстрагирование от типа декотратора. Для примера рассмотрим следующий пример наследования:

FancyBox — это View, которое украшает другие View, в данном случае Story и EditForm . Мы хотим создать FancyStory и FancyEditForm , но как? Мы наследуем от FancyBox или мы наследуем от Story ? Это неясно, потому что, опять же, у нас может быть только один родитель в цепочке наследования.

Compose же справляется с этим очень хорошо.

У Composamble-функции есть лямбда, в которой мы описываем дочерние View, т. е. мы определяем View, которая обертывает другие View. Итак, теперь, когда мы хотим создать FancyStory , мы вызываем Story внутри FancyBox и можем сделать то же самое с FancyEditForm . Это способ композиции в Compose.

Инкапсуляция

Еще одна вещь, которую хорошо выполняет Compose — это инкапсуляция. Это то, о чем вы должны думать, когда делаете общедоступные API-интерфейсы Composable-функций: публичный API-интерфейс Composable-функций — это набор параметров, которые она получает, поэтому он не может их контролировать. С другой стороны, Composable-компонент может управлять состоянием и создавать его, а затем передавать это состояние вместе с любыми данными, которые он получил, в другие Composable-компонентыв качестве параметров.

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

Перекомпоновка (перерисовка компонентов)

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

Например, вот функция bind , которую вы можете встретить сегодня в разработке для Android.

У нас есть LiveData , на которую мы хотим подписаться для обновления View. Для этого мы вызываем метод observe в классе, имеющем жизненный цикл (LifecycleOwner — Activity или Fragment), а затем передаем лямбду. Лямбда вызывается каждый раз при обновлении LiveData, и когда это происходит, мы хотим обновлять и View.

С помощью Compose мы можем изменить этот способ взаимодействия с LiveData:

Это аналогичный Composable-компонент Messages , который получает LiveData и вызывает compose-метод observationAsState . Метод observeAsState преобразует LiveData в State . Это означает, что вы можете использовать полученное значение в теле функции. Экземпляр State подписан на экземпляр LiveData, что означает, что он будет обновляться при каждом обновлении LiveData. Это также означает, что где бы ни читался экземпляр State , окружающая compose-функция, в которой он читается, будет автоматически подписываться на эти изменения. Конечным результатом является то, что больше нет необходимости указывать LifecycleOwner или коллбэк для обновления, поскольку Composable может неявно выполнять функцию их обоих.

Заключительные мысли

Compose предоставляет современный подход к созданию вашего UI, позволяя эффективно разделять ответственность в коде. Поскольку compose-функции очень похожи на обычные функции Kotlin, вы можете использовать те же самые инструменты для рефакторинга, что и для обычного Kotlin-кода.

В следующем посте я собираюсь сосредоточить внимание на некоторых деталях реализации Compose и его компилятора. Дополнительные ресурсы по Compose можно найти здесь.

Источник

Оцените статью