Котлин синтетический в адаптере или ViewHolder

87

Я новичок в котлине. Я нашел и попытался использовать синтетический метод вместо раздражающего метода findViewByIdв моем Activityклассе, но я обнаружил: «Если мы хотим вызвать синтетические свойства в представлении (полезно в классах адаптеров), мы также должны импортировать kotlinx.android.synthetic.main .Посмотреть.*." Но я не могу понять, как именно это работает? Есть примеры?

занятой
источник
Вы можете проверить этот блог или этот пример
Кабезас

Ответы:

99

Простой пример из https://github.com/antoniolg/Kotlin-for-Android-Developers

import kotlinx.android.synthetic.item_forecast.view.*

class ForecastListAdapter() : RecyclerView.Adapter<ForecastListAdapter.ViewHolder>() {

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {

        fun bindForecast(forecast: Forecast) {
            itemView.date.text = forecast.date.toDateString()
        }
    }
}

Не нужно писать

val view = itemView.findViewById(R.id.date) as TextView
view.text = forecast.date.toDateString()

Просто

itemView.date.text = forecast.date.toDateString()

Просто и эффективно!

Питер Чжао
источник
4
хорошо, это может быть глупый вопрос, но откуда взялась ссылка на itemView?
Сауло Агияр,
1
хорошо, я заметил, что мне не хватает .view. часть импорта. Теперь доступна ссылка на itemView, и, похоже, она исходит из класса RecyclerView.ViewHolder в пакете поддержки v7. Tks
Сауло Агияр
4
Для расширений представлений нет кеша, поэтому ссылки на представления должны кэшироваться, как в обычном viewHolder.
Miha_x64
2
@Mike, начиная с версии Kotlin 1.1.4, все представления будут кэшироваться. Даже во ViewHolders. В опубликованной вами статье это тоже упоминается.
Стефан Медак
2
@StefanMedack Я являюсь автором статьи :) Хотя должен отметить, что это только часть экспериментальных функций и ее нужно включить вручную. Я еще не пробовал.
Мигель Белтран
37

Котлинг 1.1.4 выход

Дополнительная информация: https://antonioleiva.com/kotlin-android-extensions/

Вам необходимо включить расширения Kotlin для Android, добавив это в свой build.gradle:

apply plugin: 'org.jetbrains.kotlin.android.extensions'
androidExtensions {
    experimental = true
}

Начиная с этой новой версии Kotlin, расширения Android включают некоторые новые интересные функции: кеши в любом классе (который, что интересно, включает ViewHolder)

Используя его в ViewHolder (или любом настраиваемом классе). Обратите внимание, что этот класс должен реализовывать LayoutContainerинтерфейс:

class ViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView), 
        LayoutContainer {

    fun bind(title: String) {
        itemTitle.text = "Hello Kotlin!"
    }
}
Дхавал Дживани
источник
3
Добавление к этой информации: Согласно Kotlin 1.1.4 эта функция является экспериментальной, и ее необходимо включить в файле build.gradle
Мигель Белтран
2
Это уже эксперимент? Я хочу использовать это в производственном коде
Carson Holzheimer
@CarsonHolzheimer, эта функция все еще экспериментальная
the_dani
кажется, даже не работает 1.3.21. Я думаю, они не собираются это реализовывать
user924
но мы можем использовать, containerView.itemTitle.text = "Hello Kotlin!"и я думаю, что этого достаточно
user924
11

Тебе нужно

import kotlinx.android.synthetic.row_wall.view.*

А потом что-то вроде:

convertView.titleText.text = item.title

Дело в том, что view. * Вводит расширения в класс View.

Жолт Сатмари
источник
1
ответ уже был дан stackoverflow.com/a/33428208/7767664 почему вы его повторили?
user924
8

Пытаться

class CustomViewModel(val baseView: View) {
    val firstName = baseView.firstName
    val lastName = baseView.lastName
}

Объект представления предоставляет представления ref: https://discuss.kotlinlang.org/t/unable-to-use-kotlin-android-extension-in-adapter-class/2890

гиена
источник
ответ уже был дан stackoverflow.com/a/33428208/7767664 почему вы его повторили?
user924
@ user924. если ответ уже в другом потоке, пожалуйста умеренной и отметьте текущую нить , как дубликат и добавить ссылку на другой нити
гиены
4

Если вы используете последнюю версию l;., Вам не нужно добавлять к ней экспериментальный = true.

на уровне проекта Gradle

classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21'

И на уровне приложения Gradle

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' //These should be on the top of file.

и в зависимостях ..

implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21'

и импортируйте ниже как

import kotlinx.android.synthetic.main.your_layout_file_name.view.*

и пример

import kotlinx.android.synthetic.main.item_animal.view.*

class AnimalVH(parent: ViewGroup, layoutID: Int) : BaseViewHolder<Animal>(parent, layoutID) {

    override fun bindData(animal: Animal) {
        itemView.tv_animal.text = animal.title
    }
}

где BaseViewHolder - это

abstract class BaseViewHolder<T>(parent: ViewGroup, layoutID: Int) : RecyclerView.ViewHolder(
    LayoutInflater.from(parent.context).inflate(layoutID, parent, false)
) {
    abstract fun bindData(model: T)
}
AndroidGeek
источник
Есть ли этому официальное подтверждение? Я считаю, что использование .view.*импортированных поражений будет целью findViewById<>, и каждый раз откат будет заключаться в том , что сам шаблон ViewHolderотговаривает.
Скайнет
Объяснение: proandroiddev.com/…
Skynet
1

Это означает, что вы должны поместить эту строку в начало исходного файла:

import kotlinx.android.synthetic.main.view.*

Так что теперь вместо, например, findView(R.id.textView) as TextViewвы должны написать просто textView. Последнее является синтетическим свойством расширения, находящимся в пакете kotlinx.android.synthetic.main.view, поэтому вам нужно импортировать все из него.

На официальном сайте есть учебник , посмотрите.

Александр Удалов
источник
1
Я это еще не видел. Я делаю это для своей деятельности, как я описал выше. Но как я могу использовать его внутри производных от BaseAdapter?
Busylee
1
Ну, по сути, вы можете вызвать findViewById()метод для Viewтипа holder.findViewById(R.id.name). С помощью расширений Kotlin для Android вы можете писать просто holder.name. Предположим, что этот код написан внутри getView()функции:val base = inflater.inflate(R.layout.list_item, parent, false) base.name.text = "John Smith"
yanex
Но что, если мне придется использовать несколько держателей представлений с разными макетами? Как это реализовать синтетикой? Потому что мы должны использовать определенную «синтетическую ссылку» для каждого макета, а у меня есть несколько макетов с похожими идентификаторами.
Натан Рубинштейн
0

К вашему сведению: для просмотра представлений рекомендуется связывание данных, а не синтетическое.

Комментарий DA for Android от Google на Reddit

Привет! Защитник разработчиков для Android в Google здесь!

Я хотел добавить сюда немного предыстории. Расширения Kotlin с синтетическими представлениями никогда преднамеренно не «рекомендуются», хотя это не следует воспринимать как рекомендацию не использовать их. Если они работают на вас, не стесняйтесь и дальше использовать их в своем приложении!

Мы отошли от них (например, мы не обучаем их в курсе Udacity), потому что они открывают глобальное пространство имен идентификаторов, не связанных с макетом, который на самом деле раздувается без проверок на недопустимые поиски, являются только Kotlin и не 'не допускает наличия NULL, если представления присутствуют только в некоторой конфигурации. Все вместе эти проблемы приводят к увеличению числа сбоев в работе приложений Android.

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

Сегодня в этой области есть несколько эффективных вариантов:

Привязка данных - это рекомендация как для просмотра представлений, так и для привязки, но она добавляет немного накладных расходов по сравнению с Android Kotlin Extensions. Стоит посмотреть, подходит ли это для вашего приложения. Привязка данных также позволяет наблюдать за LiveData для автоматической привязки представлений при изменении данных. По сравнению с Kotlin Extensions, он добавляет во время компиляции проверку просмотров и безопасность типов. Расширения Android Kotlin Extensions официально не рекомендуются (что не то же самое, что рекомендация против). У него есть проблемы, упомянутые выше, поэтому для нашего кода мы их не используем. Butter Knife - еще одно решение, которое чрезвычайно популярно и работает как для Kotlin, так и для языка программирования Java. Читая комментарии здесь, там ' много разработчиков, которым очень повезло с Kotlin Extensions. Это здорово - и мы будем помнить об этом, когда будем искать пути дальнейшего улучшения наших API. Если вы еще не рассматривали привязку данных, обязательно попробуйте.

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

user158
источник