Привет, «Хабр»! Прошло почти 9 месяцев с тех пор, как на Google I/O 2017 компания Google анонсировала Kotlin в качестве официального языка разработки под Android. Кто-то использует его как основной инструмент намного дольше, учитывая, что на нём можно было писать уже с середины 2014 года. В документации Google стали появляться примеры реализации на Kotlin. За это время разработчики смогли «потрогать» и оценить все преимущества этого языка. И многие, включая меня, думали: какой же шаг будет следующим? Support Library на Kotlin? Или что-то новое? И вот, встречайте: Android KTX! А мы представляем вашему вниманию перевод статьи, посвящённой его разбору.
5 февраля Google анонсировала выход библиотеки Android KTX, которая представляет собой набор расширений Kotlin для разработки приложений под Android. Этот шаг выглядит как логическое продолжение интеграции Kotlin в Android-разработку и добавление всех его преимуществ: меньше кода, больше удовольствия и облегчение понимания кода проекта.
Сейчас библиотека доступна только в preview и открыта для новых идей. Скорее всего, в ней будет значительно больше фичей и возможностей, когда её выведут в стабильную версию. Я писал эту статью, одновременно проглядывая документацию, и подумал, что хорошо было бы подробнее рассмотреть некоторые моменты. Вероятнее всего, вы сами начнёте изучать документацию лишь тогда, когда вам это понадобится. Но я надеюсь, что эта статья даст вам представление о том, что можно использовать уже сейчас. И если вы всё ещё не используете Kotlin, то поймёте, что вы упускаете.
Документацию по KTX вы можете найти здесь: core-ktx и саму библиотеку здесь: android/android-ktx.
Здесь собраны функции расширения, относящиеся к анимации. Давайте быстро пробежимся по тому, что доступно в текущем релизе.
Для начала установим animation listener на animator:
Эта конструкция позволяет нам получать колбэки для событий анимации. Мы также можем использовать функции расширения для определённых колбэков от listener, нужно только реализовать функции, которые вы хотите получать:
Это солидное уменьшение кода за счёт отсутствия реализации тех колбэков, в которых мы не нуждаемся и которые не используем.
У нас появилась возможность устанавливать listener на отдельные события: например, добавить listener на событие pause можно так же, как и функцию addListener():
Мы также можем «повесить» listener на событие анимации с помощью однострочного синтаксиса:
Если сейчас вы используете Java, то заметите, насколько меньше кода требуется для реализации и насколько легче это всё читается.
Здесь мы рассмотрим функции расширения, добавленные в пакет Content. Если нам необходимо получить системный сервис, то расширение позволяет сделать так:
Styled attributes также будут работать при использовании функций расширения:
Выполнить операции записи для SharedPreferences теперь максимально просто с использованием функции расширения edit:
Мы также можем создать экземпляр ContentValues, используя функцию contentValuesOf, передав в качестве аргументов экземпляры Pair:
KTX также предлагает использовать методы, относящиеся к работе со временем. Посмотрим, что мы здесь имеем.
Теперь можно получить DayOfWeek, Month и Year как Int-значение простым вызовом:
Класс Duration также имеет несколько доступных функций расширения:
Свойства Instant, LocalData, LocalDateTime, LocalTime могут быть получены следующими функциями расширения:
Так же, как в методах, перечисленных выше, доступ к свойствам классов MonthDay, OffsetDateTime и OffsetTime может быть получен через вызовы следующих методов:
Если вы используете класс Period, то библиотека KTX содержит несколько функций расширения для доступа к свойствам и операциям этого класса:
Ещё здесь есть несколько других функций расширения, которые могут быть использованы для получения необходимых значений:
Следующие функции расширения являются действительно хорошим дополнением и позволяют нам легко перевести Int-значение в необходимый класс, предусмотренный вызовом функции:
Так же это работает для Long-значений:
Здесь собраны функции расширения, направленные на взаимодействие с пакетом Android OS.
Они включают в себя несколько функций расширения для работы с классом Handler:
Создание экземпляра класса Bundle сейчас выглядит намного приятнее:
И если вы записываете trace events для Systrace tool, запись сообщений trace будет проще и красивее:
В пакете Util собраны функции расширения для работы с файлами, массивами и другими основными типами данных.
Если вы работаете с AtomicFiles, то вы можете использовать следующие функции:
Для LongSparseArray, SparseArray, SparseBooleanArray, SparseIntArray, SparseLongArray типов нам стали доступны:
Работа с классом Pair стала немного легче:
Мы также можем конвертировать Kotlin Pair в Android Pair:
Если вы работаете с классом Half, то благодаря KTX стало проще конвертировать в него данные других типов:
Используя функции расширения, теперь можно преобразовать экземпляр класса ClosedRange в Range:
Над экземпляром класса Range появилась возможность выполнять следующие действия:
Оба класса Size и SizeF могут использовать функции расширения:
В данном разделе собраны функции расширения, доступные для класса Cursor. Каждая группа функций расположена в следующем порядке:
В данный момент для SQLite есть всего одна функция, но зато очень полезная. Она позволяет нам производить транзакции, используя заданные SQL-операторы.
Что касается ресурсов, то пока добавлены только те функции расширения, которые упрощают работу с классом TypedArray.
Примечание: Все throw пробрасывают IllegalArgumentException, если указанный индекс не существует.
Большинство приложений, над которыми мы (разработчики) работаем, используют текст в разным местах этих самых приложений. К счастью, в KTX есть несколько функций для работы с ним, в частности для класса SpannableStringBuilder.
Например, сразу после инициализации билдера мы можем использовать эти функции, чтобы добавить некоторый жирный текст в конец исходной строки:
Также есть build-функции, которые могут установить цвет фона или добавить отступы в текст:
И последняя функция — buildSpannedString, которая позволяет составить строку, используя вышеперечисленные функции расширения:
В пакете .net у нас есть одна функция, позволяющая с лёгкостью конвертировать строку в URI. То, что нужно!
Пакет Graphics в KTX вышел довольно массивным, зато он даёт нам возможность легко реализовывать все визуальные тонкости приложения.
В первую очередь хотелось бы отметить функции, конвертирующие Bitmap (и не только) в следующие типы:
Далее рассмотрим ключевые операции для работы с Bitmap:
И работа с Canvas стала намного легче:
Также появилось несколько нововведений для Color:
Функция plus() действительно крута и позволяет нам смешивать два цвета и получить в результате смешанный Color!
Кроме этого, стало проще работать с матрицами. Теперь можно перемножить две матрицы и в результате получить один объект Matrix:
А ещё мы можем работать с Picture через функцию record, используя блок параметров, чтобы выполнить соответствующие действия:
Если мы хотим поменять границы drawable, то можем просто вызвать функцию updateBounds и передать ей размеры в качестве параметров:
Нужно произвести трансформацию на Shader? Без проблем!
Появилось несколько функций расширения для работы с классом PorterDuff:
Работая с классом Region, теперь мы можем использовать эти функции:
Классу PointF также добавили некоторые функции для упрощения:
Тоже самое доступно для класса Point:
И для класса Rect тоже:
Вы не удивитесь, но для RectF они также доступны:
При работе с классом Path мы можем использовать следующие варианты:
Велика вероятность, что при работе с графикой мы будем работать с типами данных Int и Long. Тип Int предлагает нам следующие функции в KTX:
С другой стороны, тип Long содержит немного больше функций:
Итак, дойдя до класса Transition, мы видим, что здесь можно использовать функции расширения, аналогичные animation listeners:
Но есть небольшое отличие в синтаксисе метода для отдельных колбэков:
Аналогичные функции были добавлены также и для класса View. Установка колбэков предельно понятна:
Метод postDelayed теперь доступен в качестве функции:
То же самое и с методом postOnAnimationDelayed:
Обновление паддингов для View теперь намного легче и понятнее, для этого нам были предоставлены несколько функций:
Если вам нужно конвертировать View в Bitmap, то теперь это можно сделать одной строкой кода!
Несколько достаточно крутых функций расширения были добавлены и для ViewGroup. Думаю, вам понравится! Например, проверка, содержит ли ViewGroup конкретную View:
Цикл по child ViewGroup (где it представляет собой child):
Доступ к child конкретной позиции в стиле Kotlin:
Получение экземпляра MutableIterator:
И несколько других операций с ViewGroup:
Так же, как и паддинги для View, мы можем добавлять margins для LayoutParams с помощью следующих функций:
Как мы видим, KTX предлагает нам мощные инструменты для использования Kotlin в разработке Android-приложений. Я очень рад возможности использовать их в своих проектах и с нетерпением жду, что же будет ещё добавлено в ближайшее время.
5 февраля Google анонсировала выход библиотеки Android KTX, которая представляет собой набор расширений Kotlin для разработки приложений под Android. Этот шаг выглядит как логическое продолжение интеграции Kotlin в Android-разработку и добавление всех его преимуществ: меньше кода, больше удовольствия и облегчение понимания кода проекта.
Сейчас библиотека доступна только в preview и открыта для новых идей. Скорее всего, в ней будет значительно больше фичей и возможностей, когда её выведут в стабильную версию. Я писал эту статью, одновременно проглядывая документацию, и подумал, что хорошо было бы подробнее рассмотреть некоторые моменты. Вероятнее всего, вы сами начнёте изучать документацию лишь тогда, когда вам это понадобится. Но я надеюсь, что эта статья даст вам представление о том, что можно использовать уже сейчас. И если вы всё ещё не используете Kotlin, то поймёте, что вы упускаете.
Документацию по KTX вы можете найти здесь: core-ktx и саму библиотеку здесь: android/android-ktx.
Animator functions
Здесь собраны функции расширения, относящиеся к анимации. Давайте быстро пробежимся по тому, что доступно в текущем релизе.
Animation listener
Для начала установим animation listener на animator:
animator.addListener { handleAnimation(it) }
Эта конструкция позволяет нам получать колбэки для событий анимации. Мы также можем использовать функции расширения для определённых колбэков от listener, нужно только реализовать функции, которые вы хотите получать:
animator.addListener(
onEnd = {},
onStart = {},
onCancel = {},
onRepeat = {}
)
Это солидное уменьшение кода за счёт отсутствия реализации тех колбэков, в которых мы не нуждаемся и которые не используем.
Отдельные listeners для событий анимации
У нас появилась возможность устанавливать listener на отдельные события: например, добавить listener на событие pause можно так же, как и функцию addListener():
animator.addPauseListener { handleAnimation(it) }
// или
animator.addPauseListener(
onPause = {},
onResume = {}
)
Мы также можем «повесить» listener на событие анимации с помощью однострочного синтаксиса:
animator.doOnPause { handleAnimation(it) }
animator.doOnCancel { handleAnimation(it) }
animator.doOnEnd { handleAnimation(it) }
animator.doOnRepeat { handleAnimation(it) }
animator.doOnStart { handleAnimation(it) }
animator.doOnResume { handleAnimation(it) }
Если сейчас вы используете Java, то заметите, насколько меньше кода требуется для реализации и насколько легче это всё читается.
Content
Здесь мы рассмотрим функции расширения, добавленные в пакет Content. Если нам необходимо получить системный сервис, то расширение позволяет сделать так:
val alarmManager = systemService<AlarmManager>()
Styled attributes также будут работать при использовании функций расширения:
context.withStyledAttributes(set = someAttributeSet, attrs = attributes, defStyleAttr = ..., defStyleRes = ...) {
// Какие-то действия
}
context.withStyledAttributes(set = someAttributeSet, attrs =
attributes) {
// Какие-то действия
}
Выполнить операции записи для SharedPreferences теперь максимально просто с использованием функции расширения edit:
sharedPreferences.edit {
putBoolean(key, value)
}
Мы также можем создать экземпляр ContentValues, используя функцию contentValuesOf, передав в качестве аргументов экземпляры Pair:
val contentValues = contentValuesOf(somePairs...)
Time operations
KTX также предлагает использовать методы, относящиеся к работе со временем. Посмотрим, что мы здесь имеем.
Теперь можно получить DayOfWeek, Month и Year как Int-значение простым вызовом:
DayOfWeek.FRIDAY.asInt()
Month.APRIL.asInt()
Year.now().asInt()
Класс Duration также имеет несколько доступных функций расширения:
// Получение значений
val (seconds, nanoseconds) = Duration.ofSeconds(1)
// умножение
val resultValue = Duration.ofSeconds(1) * 2
// Деление
val resultValue = Duration.ofSeconds(2) / 2
// Инверсия
val resultValue = -Duration.ofSeconds(2)
Свойства Instant, LocalData, LocalDateTime, LocalTime могут быть получены следующими функциями расширения:
// Получение значений
val (seconds, nanoseconds) = Instant.now()
// Получение значений
val (year, month, day) = LocalDate.now()
// Получение значений
val (localDate, localTime) = LocalDateTime.now()
// Получение значений
val (hour, minute, second, nanosecond) = LocalTime.now()
Так же, как в методах, перечисленных выше, доступ к свойствам классов MonthDay, OffsetDateTime и OffsetTime может быть получен через вызовы следующих методов:
// Получение значений
val (month, day) = MonthDay.now()
// Получение значений
val (localDataTime, ZoneOffset) = OffsetDateTime.now()
// Получение значений
val (localTime, ZoneOffset) = OffsetTime.now()
Если вы используете класс Period, то библиотека KTX содержит несколько функций расширения для доступа к свойствам и операциям этого класса:
// Получение значений
val (years, month, days) = Period.ofDays(2)
// Умножение
val resultValue = Period.ofDays(2) * 2
// Инверсия
val resultValue = -Period.ofDays(2)
Ещё здесь есть несколько других функций расширения, которые могут быть использованы для получения необходимых значений:
// Получение значений
val (year, month) = YearMonth.now()
// Получение значений
val (localDateTime, ZoneId) = ZonedDateTime.now()
Следующие функции расширения являются действительно хорошим дополнением и позволяют нам легко перевести Int-значение в необходимый класс, предусмотренный вызовом функции:
someInt.asDayOfWeek() // возвращает экземпляр DayOfWeek
someInt.asMonth() // возвращает экземпляр Month
someInt.asYear() // возвращает экземпляр Year
someInt.days() // возвращает экземпляр Period
someInt.hours() // возвращает экземпляр Duration
someInt.millis() // возвращает экземпляр Duration
someInt.minutes() // возвращает экземпляр Duration
someInt.months() // возвращает экземпляр Period
someInt.nanos() // возвращает экземпляр Duration
someInt.seconds() // возвращает экземпляр Duration
someInt.years() // возвращает экземпляр Period
Так же это работает для Long-значений:
someLong.asEpochMillis() // возвращает экземпляр Instant
someLong.asEpochSeconds() // возвращает экземпляр Instant
someLong.hours() // возвращает экземпляр Duration
someLong.millis() // возвращает экземпляр Duration
someLong.minutes() // возвращает экземпляр Duration
someLong.nanos() // возвращает экземпляр Duration
someLong.seconds() // возвращает экземпляр Duration
OS
Здесь собраны функции расширения, направленные на взаимодействие с пакетом Android OS.
Они включают в себя несколько функций расширения для работы с классом Handler:
handler.postAtTime(uptimeMillis = 200L) {
// Какое-то действие
}
handler.postDelayed(delayInMillis = 200L) {
// Какое-то действие
}
Создание экземпляра класса Bundle сейчас выглядит намного приятнее:
val bundle = bundleOf("some_key" to 12, "another_key" to 15)
val bundle = persistableBundleOf("some_key" to 12, "another_key" to 15)
И если вы записываете trace events для Systrace tool, запись сообщений trace будет проще и красивее:
trace("section_name") { }
Utils
В пакете Util собраны функции расширения для работы с файлами, массивами и другими основными типами данных.
Если вы работаете с AtomicFiles, то вы можете использовать следующие функции:
val fileBytes = atomicFile.readBytes()
val text = atomicFile.readText(charset = Charset.defaultCharset())
atomicFile.tryWrite {
// Ваша операция записи
}
atomicFile.writeBytes(byteArrayOf())
atomicFile.writeText("some string", charset = Charset.defaultCharset())
Для LongSparseArray, SparseArray, SparseBooleanArray, SparseIntArray, SparseLongArray типов нам стали доступны:
array.contains(someKey)
array.containsKey(someKey)
array.containsValue(someValue)
array.forEach { key, value -> doSomething(key, value) }
array.getOrDefault(key = keyValue, defaultValue = defaultValue)
array.getOrElse(key = keyValue, defaultValue = defaultValue)
array.isEmpty()
array.isNotEmpty()
val keyIterator = array.keyIterator()
val valueIterator = array.valueIterator()
array.plus(anotherArray)
array.putAll(anotherArray)
array.remove(key = keyValue, value = value)
array.set(key = keyValue, value = value)
array.size
Работа с классом Pair стала немного легче:
val pair = android.util.Pair("dsfn", "sdihfg")
// Получение значений
val (key, value) = pair
// Конвертирование Android Pair в Kotlin Pair
val kotlinPair = pair.toKotlinPair()
Мы также можем конвертировать Kotlin Pair в Android Pair:
val pair = Pair("dsfn", "sdihfg")
val androidPair = pair.toAndroidPair()
Если вы работаете с классом Half, то благодаря KTX стало проще конвертировать в него данные других типов:
short.toHalf()
string.toHalf()
float.toHalf()
double.toHalf()
Используя функции расширения, теперь можно преобразовать экземпляр класса ClosedRange в Range:
val range = closedRange.toRange()
Над экземпляром класса Range появилась возможность выполнять следующие действия:
val range = closedRange.toClosedRange()
// Возвращает пересечение двух диапазонов
val resultValue = closedRange and someOtherRange
// Возвращает наименьший диапазон, включающий два диапазона
val resultValue = closedRange += someOtherCloseRange
// Возвращает пересечение диапазона и заданного значения
val resultValue = closedRange += someValue
Оба класса Size и SizeF могут использовать функции расширения:
val size = Size(5, 5)
// Получение значений
val (width, height) = size
Database Cursor
В данном разделе собраны функции расширения, доступные для класса Cursor. Каждая группа функций расположена в следующем порядке:
- первая функция возвращает тип non-null, используя заданное имя столбца;
- вторая функция возвращает тип данных (или null), используя заданное имя столбца;
- третья функция возвращает тип данных (или null), используя заданный индекс.
cursor.getBlob(columnName = "some_column")
cursor.getBlobOrNull(columnName = "some_column")
cursor.getBlobOrNull(index = 0)
cursor.getDouble(columnName = "some_column")
cursor.getDoubleOrNull(columnName = "some_column")
cursor.getDoubleOrNull(index = 0)
cursor.getFloat(columnName = "some_column")
cursor.getFloatOrNull(columnName = "some_column")
cursor.getFloatOrNull(index = 0)
cursor.getInt(columnName = "some_column")
cursor.getIntOrNull(columnName = "some_column")
cursor.getIntOrNull(index = 0)
cursor.getLong(columnName = "some_column")
cursor.getLongOrNull(columnName = "some_column")
cursor.getLongOrNull(index = 0)
cursor.getShort(columnName = "some_column")
cursor.getShortOrNull(columnName = "some_column")
cursor.getShortOrNull(index = 0)
cursor.getString(columnName = "some_column")
cursor.getStringOrNull(columnName = "some_column")
cursor.getStringOrNull(index = 0)
SQLite
В данный момент для SQLite есть всего одна функция, но зато очень полезная. Она позволяет нам производить транзакции, используя заданные SQL-операторы.
sqLiteDatabase.transaction { "some SQL statement" }
Resources
Что касается ресурсов, то пока добавлены только те функции расширения, которые упрощают работу с классом TypedArray.
val boolean = typedArray.getBooleanOrThrow(0)
val int = typedArray.getColorOrThrow(0)
val colorStateList = typedArray.getColorStateListOrThrow(0)
val float = typedArray.getDimensionOrThrow(0)
val int = typedArray.getDimensionPixelOffsetOrThrow(0)
val int = typedArray.getDimensionPixelSizeOrThrow(0)
val drawable = typedArray.getDrawableOrThrow(0)
val float = typedArray.getFloatOrThrow(0)
val typeface = typedArray.getFontOrThrow(0)
val int = typedArray.getIntOrThrow(0)
val int = typedArray.getIntegerOrThrow(0)
val string = typedArray.getStringOrThrow(0)
val charSequenceArray = typedArray.getTextArrayOrThrow(0)
val charSequence = typedArray.getTextOrThrow(0)
Примечание: Все throw пробрасывают IllegalArgumentException, если указанный индекс не существует.
Text
Большинство приложений, над которыми мы (разработчики) работаем, используют текст в разным местах этих самых приложений. К счастью, в KTX есть несколько функций для работы с ним, в частности для класса SpannableStringBuilder.
Например, сразу после инициализации билдера мы можем использовать эти функции, чтобы добавить некоторый жирный текст в конец исходной строки:
val builder = SpannableStringBuilder(urlString)
.bold { append("hi there") }
// или bold / italic / underlined текст, если хотите.
val builder = SpannableStringBuilder(urlString)
.bold { italic { underline { append("hi there") } } }
Также есть build-функции, которые могут установить цвет фона или добавить отступы в текст:
.backgroundColor(color = R.color.black) {
// Действие в builder
}
.inSpans(spans = someSpans) {
// Действие в builder
}
И последняя функция — buildSpannedString, которая позволяет составить строку, используя вышеперечисленные функции расширения:
textView.text = buildSpannedString { bold { append("hitherejoe") } }
Net
В пакете .net у нас есть одна функция, позволяющая с лёгкостью конвертировать строку в URI. То, что нужно!
val uri = urlString.toUri()
Graphics
Пакет Graphics в KTX вышел довольно массивным, зато он даёт нам возможность легко реализовывать все визуальные тонкости приложения.
В первую очередь хотелось бы отметить функции, конвертирующие Bitmap (и не только) в следующие типы:
val adaptiveIcon = bitmap.toAdaptiveIcon()
val drawable = bitmap.toDrawable(resources)
val icon = bitmap.toIcon()
val drawable = someInt.toDrawable()
val icon = someByteArray.toIcon()
val icon = someUri.toIcon()
val colorDrawable = someColor.toDrawable()
val bitmap = drawable.toBitmap(width = someWidth, height = someHeight, config = bitMapConfig)
Далее рассмотрим ключевые операции для работы с Bitmap:
val bitmap = someBitmap.applyCanvas(block = { })
val colorInt = someBitmap.get(x, y)
val bitmap = someBitmap.scale(width, height, filter = true)
someBitmap.set(x, y, color)
И работа с Canvas стала намного легче:
canvas.withRotation(degrees, pivotX, pivotY) { // Обработка }
canvas.withSave { // Обработка }
canvas.withScale(x, y, pivotX, pivotY) { // Обработка }
canvas.withSkew(x, y) { // Обработка }
canvas.withTranslation(x, y) { // Обработка }
Также появилось несколько нововведений для Color:
// Получение значений
val (r, g, b, a) = color
// Смешивание цветов
val color += someColor
Функция plus() действительно крута и позволяет нам смешивать два цвета и получить в результате смешанный Color!
Кроме этого, стало проще работать с матрицами. Теперь можно перемножить две матрицы и в результате получить один объект Matrix:
// Умножение
val resultMatrix = matrix * someOtherMatrix
val values = matrix.values()
А ещё мы можем работать с Picture через функцию record, используя блок параметров, чтобы выполнить соответствующие действия:
val resultField = picture.record(width = someWidth, height = someHeight) {
// Какие-то действия над Canvas
}
Если мы хотим поменять границы drawable, то можем просто вызвать функцию updateBounds и передать ей размеры в качестве параметров:
drawable.updateBounds(left = 16, top = 16, right = 16, bottom = 16)
Нужно произвести трансформацию на Shader? Без проблем!
shader.transform { // Трансформация }
Появилось несколько функций расширения для работы с классом PorterDuff:
val porterDuffColorFilter = mode.toColorFilter(someColor)
val porterDuffXfermode = mode.toXfermode()
Работая с классом Region, теперь мы можем использовать эти функции:
// Возвращает объединение someRegion с Rect
val region = someRegion and someRect
// Возвращает объединение someRegion с Region
val region = someRegion and someRegion
// Возвращает разницу someRegion и Rect
val region = someRegion - someRect
// Возвращает разницу someRegion и другим Region
val region = someRegion - someRegion
// Возвращает пересечение someRegion и Rect
val region = someRegion or someRect
// Возвращает пересечение someRegion и другим Region
val region = someRegion or someRegion
// Возвращает объединение someRegion с Rect
val region = someRegion + someRect
// Возвращает объединение someRegion с Region
val region = someRegion + someRegion
// Возвращает объединение без пересечения someRegion и Rect
val region = someRegion xor someRect
// Возвращает объединение без пересечения someRegion и другим Region
val region = someRegion xor someRegion
val boolean = someRegion.contains(somePoint)
someRegion.forEach { doSomethingWithEachRect(it) }
val iterator = someRegion.iterator()
// Возвращает инвертированный someRegion как новый Region
val region = -someRegion
Классу PointF также добавили некоторые функции для упрощения:
val (x, y) = somePointF
val pointF = somePointF - someOtherPointF
val pointF = somePointF - someFloat
val pointF = somePointF + somePointF
val pointF = somePointF + someFloat
val point = somePointF.toPoint()
val pointF = -somePointF
Тоже самое доступно для класса Point:
val (x, y) = somePoint
val point = somePoint - somePoint
val point = somePoint - someFloat
val point = somePoint +somePoint
val point = somePoint + someFloat
val point = somePoint.toPointF()
val point = -somePoint
И для класса Rect тоже:
val rect = someRect and anotherRect
val (left, top, right, bottom) = someRect
someRect.contains(somePoint)
val region = someRect - anotherRect
val rect = someRect - someInt
val rect = someRect - somePoint
val rect = someRect or someRect
val rect = someRect + someRect
val rect = someRect + someInt
val rect = someRect + somePoint
val rectF = someRect.toRectF()
val region = someRect.toRegion()
val region = someRect xor someRect
Вы не удивитесь, но для RectF они также доступны:
val rectF = someRectF and anotherRectF
val (left, top, right, bottom) = somerectF
someRectF.contains(somePoint)
val region = someRectF - anotherRectF
val rectF = someRectF - someInt
val rectF = someRectF - somePoint
val rectF = someRectF or someRect
val rectF = someRectF + someRect
val rectF = someRectF + someInt
val rectF = someRectF + somePoint
val rect = someRectF.toRect()
val region = someRectF.toRegion()
val reactF = someRectF.transform(someMatrix)
val region = someRectF xor someRect
При работе с классом Path мы можем использовать следующие варианты:
val path = somePath and anotherPath
val path = somePath.flatten(error = 0.5f)
val path = somePath - anotherPath
val path = somePath or anotherPath
val path = somePath + anotherPath
val path = somePath xor anotherPath
Велика вероятность, что при работе с графикой мы будем работать с типами данных Int и Long. Тип Int предлагает нам следующие функции в KTX:
val alpha = int.alpha
val blue = int.blue
val green = int.green
val red = int.red
val luminance = int.luminance
val (alphaComp, redComp, greenComp, blueComp) = someInt
val color = someInt.toColor()
val color = someInt.toColorLong()
С другой стороны, тип Long содержит немного больше функций:
val alpha = long.alpha
val blue = long.blue
val green = long.green
val red = long.red
val luminance = long.luminance
val (alphaComp, redComp, greenComp, blueComp) = someLong
val color = someLong.toColor()
val color = someLong.toColorInt()
long.isSrgb
long.isWideGamut
long.colorSpace
Transitions
Итак, дойдя до класса Transition, мы видим, что здесь можно использовать функции расширения, аналогичные animation listeners:
transition.addListener { doSomethingWithTransition(it) }
transition.addListener(
onEnd = {},
onStart = {},
onCancel = {},
onResume = {},
onPause = {}
)
Но есть небольшое отличие в синтаксисе метода для отдельных колбэков:
transition.doOnCancel { }
transition.doOnEnd { }
transition.doOnPause { }
transition.doOnResume { }
transition.doOnStart { }
Views
Аналогичные функции были добавлены также и для класса View. Установка колбэков предельно понятна:
view.doOnLayout { }
view.doOnNextLayout { }
view.doOnPreDraw { }
Метод postDelayed теперь доступен в качестве функции:
view.postDelayed(delayInMillis = 200) { // Какое-то действие }
То же самое и с методом postOnAnimationDelayed:
view.postOnAnimationDelayed(delayInMillis = 200) { // Какое-то действие }
Обновление паддингов для View теперь намного легче и понятнее, для этого нам были предоставлены несколько функций:
view.setPadding(16)
view.updatePadding(left = 16, right = 16, top = 16, bottom = 16)
view.updatePaddingRelative(
start = 16, end = 16, top = 16, bottom = 16)
Если вам нужно конвертировать View в Bitmap, то теперь это можно сделать одной строкой кода!
val bitmap = view.toBitmap(config = bitmapConfig)
ViewGroup
Несколько достаточно крутых функций расширения были добавлены и для ViewGroup. Думаю, вам понравится! Например, проверка, содержит ли ViewGroup конкретную View:
val doesContain = viewGroup.contains(view)
Цикл по child ViewGroup (где it представляет собой child):
viewGroup.forEach { doSomethingWithChild(it) }
viewGroup.forEachIndexed { index, view ->
doSomethingWithChild(index, view) }
Доступ к child конкретной позиции в стиле Kotlin:
val view = viewGroup[0]
Получение экземпляра MutableIterator:
val viewGroupIterator = viewGroup.iterator()
И несколько других операций с ViewGroup:
viewGroup.isEmpty()
viewGroup.isNotEmpty()
viewGroup.size
// Удаление view из данной viewgroup
viewGroup -= view
// Добавление view в данную viewgroup
viewGroup += view
Margins
Так же, как и паддинги для View, мы можем добавлять margins для LayoutParams с помощью следующих функций:
params.setMargins(16)
params.updateMargins(left = 16, right = 16, top = 16, bottom = 16)
params.updateMarginsRelative(
start = 16, end = 16, top = 16, bottom = 16)
Заключение
Как мы видим, KTX предлагает нам мощные инструменты для использования Kotlin в разработке Android-приложений. Я очень рад возможности использовать их в своих проектах и с нетерпением жду, что же будет ещё добавлено в ближайшее время.