Kotlin syntetyczny w adapterze lub ViewHolder

87

Jestem nowy w Kotlinie. Znalazłem i próbowałem użyć metody syntetycznej zamiast irytującej metody findViewByIdw mojej Activityklasie, ale znalazłem „Jeśli chcemy wywołać właściwości syntetyczne w widoku (przydatne w klasach adapterów), powinniśmy również zaimportować kotlinx.android.synthetic.main .widok.*." Ale nie mogę dowiedzieć się, jak to dokładnie działa? Czy są jakieś przykłady?

busylee
źródło
Możesz sprawdzić tego bloga lub ten przykład
Cabezas

Odpowiedzi:

99

Prosty przykład z 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()
        }
    }
}

Nie musisz pisać

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

Właśnie

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

Proste i skuteczne!

Peter Zhao
źródło
4
ok, to może być głupie pytanie, ale skąd się bierze odwołanie do „itemView”?
Saulo Aguiar,
1
ok, zauważyłem, że brakuje mi .view. część importu. Teraz referencja itemView jest dostępna i wydaje się pochodzić z klasy RecyclerView.ViewHolder w pakiecie obsługi wersji 7. Tks
Saulo Aguiar,
4
Nie ma pamięci podręcznej dla rozszerzeń widoków, więc odniesienia do widoków powinny być przechowywane w pamięci podręcznej, tak jak w zwykłym obiekcie viewHolder.
Miha_x64,
2
@Mike od wersji Kotlin 1.1.4 wszystkie widoki będą buforowane. Nawet w ViewHolders. W opublikowanym artykule również o tym wspomina.
Stefan Medack
2
@StefanMedack Jestem autorem artykułu :) Chociaż muszę zaznaczyć, że jest to tylko część eksperymentalnych funkcji i wymaga ręcznego włączenia. Jeszcze tego nie próbowałem.
Miguel Beltran
37

Kotling 1.1.4 out

Więcej informacji: https://antonioleiva.com/kotlin-android-extensions/

Musisz włączyć rozszerzenia Kotlin dla systemu Android, dodając to do pliku build.gradle:

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

Od tej nowej wersji Kotlin rozszerzenia Androida zawierały kilka nowych interesujących funkcji: pamięci podręczne w dowolnej klasie (co ciekawe zawiera ViewHolder)

Używanie go w ViewHolder (lub dowolnej klasie niestandardowej). Zauważ, że ta klasa powinna implementować LayoutContainerinterfejs:

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

    fun bind(title: String) {
        itemTitle.text = "Hello Kotlin!"
    }
}
Dhaval Jivani
źródło
3
Dodając do tych informacji: Zgodnie z Kotlin 1.1.4 funkcja jest eksperymentalna i musi być włączona w pliku build.gradle
Miguel Beltran
2
Czy to już jest eksperymentalne? Chcę to wykorzystać w kodzie produkcyjnym
Carson Holzheimer
@CarsonHolzheimer ta funkcja jest wciąż eksperymentalna
the_dani
wydaje się, że to nawet nie działa 1.3.21. Myślę, że nie zamierzają tego zaimplementować
user924
ale możemy użyć containerView.itemTitle.text = "Hello Kotlin!"i myślę, że wystarczy
user924
11

Potrzebujesz

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

A później coś w rodzaju:

convertView.titleText.text = item.title

Chodzi o to, że view. * Wprowadza rozszerzenia do klasy View.

Zsolt Szatmari
źródło
1
odpowiedź została już udzielona stackoverflow.com/a/33428208/7767664 dlaczego to powtórzyłeś?
user924
8

Próbować

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

Widok obiektu udostępnia widoki ref: https://discuss.kotlinlang.org/t/unable-to-use-kotlin-android-extension-in-adapter-class/2890

hiena
źródło
odpowiedź została już udzielona stackoverflow.com/a/33428208/7767664 dlaczego to powtórzyłeś?
user924
@ user924. jeśli odpowiedź jest już w innym wątku, moderuj i oznacz bieżący wątek jako duplikat i dodaj odniesienie do innego wątku
hiena
4

Jeśli używasz najnowszej wersji l;., Nie musisz dodawać do niej Experimental = true.

na poziomie projektu Gradle

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

A na poziomie aplikacji Gradle

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

iw zależnościach.

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

i importuj poniżej jako

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

i przykład

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
    }
}

gdzie BaseViewHolder jest

abstract class BaseViewHolder<T>(parent: ViewGroup, layoutID: Int) : RecyclerView.ViewHolder(
    LayoutInflater.from(parent.context).inflate(layoutID, parent, false)
) {
    abstract fun bindData(model: T)
}
AndroidGeek
źródło
Czy jest jakieś oficjalne potwierdzenie tego? Uważam, że używanie .view.*importu mija się z celem, za findViewById<>każdym razem wyjściem będzie powrót do samego wzorca, od którego ViewHolderodradza.
Skynet
Wyjaśniono na: proandroiddev.com/…
Skynet
1

Oznacza to, że musisz umieścić tę linię na początku pliku źródłowego:

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

Więc teraz zamiast, na przykład, findView(R.id.textView) as TextViewnapiszesz po prostu textView. Ta ostatnia jest syntetyczną właściwością rozszerzenia znajdującą się w pakiecie kotlinx.android.synthetic.main.view, dlatego musisz zaimportować z niej wszystko.

Na oficjalnej stronie jest samouczek , spójrz.

Alexander Udalov
źródło
1
Już to widziałem. Zrobiłem to dla swojej działalności, jak opisałem powyżej. Ale jak mogę go używać w pochodnych BaseAdapter?
busylee
1
Cóż, w zasadzie możesz wywołać findViewById()metodę na View, jak holder.findViewById(R.id.name). Dzięki rozszerzeniom Kotlin na Androida możesz po prostu pisać holder.name. Załóżmy, że ten kod jest zapisany w getView()funkcji:val base = inflater.inflate(R.layout.list_item, parent, false) base.name.text = "John Smith"
yanex
Ale co, jeśli muszę użyć kilku uchwytów widoku z różnymi układami? Jak mogę to zrealizować za pomocą syntetycznego? Ponieważ musimy użyć specjalnego „linku syntetycznego” dla każdego układu, a mam kilka układów z podobnymi identyfikatorami.
Natan Rubinstein
0

FYI: powiązanie danych jest zalecane zamiast syntetycznego do wyszukiwania widoków.

Komentarz od DA dla Androida z Google na Reddit

Hej! Developer Advocate for Android w Google tutaj!

Chciałem dodać tutaj trochę tła. Rozszerzenia Kotlin z syntetycznymi poglądami nigdy nie były celowo „zalecane”, chociaż nie powinno to być traktowane jako zalecenie, aby ich nie używać. Jeśli pracują dla Ciebie, możesz nadal używać ich w swojej aplikacji!

Odsuwamy się od nich (np. Nie uczymy ich na kursie Udacity), ponieważ ujawniają globalną przestrzeń nazw identyfikatorów, która nie jest związana z układem, który jest faktycznie zawyżony bez sprawdzania nieprawidłowych wyszukiwań, są tylko Kotlin i nie Nie ujawniaj wartości null, gdy widoki są obecne tylko w niektórych konfiguracjach. Podsumowując, te problemy powodują, że interfejs API zwiększa liczbę awarii aplikacji na Androida.

Z drugiej strony oferują lekki interfejs API, który może pomóc w uproszczeniu wyszukiwania widoków. W tym miejscu warto również przyjrzeć się wiązaniu danych, które również wykonuje automatyczne wyszukiwanie widoków - a także integruje się z LiveData, aby automatycznie aktualizować widoki w miarę zmian danych.

Dziś jest kilka opcji w tej przestrzeni, które działają:

Wiązanie danych jest zaleceniem dotyczącym wyszukiwania i wiązania widoku, ale dodaje trochę narzutu w porównaniu z rozszerzeniami Kotlin dla systemu Android. Warto sprawdzić, czy to dobrze pasuje do Twojej aplikacji. Powiązanie danych umożliwia również obserwowanie funkcji LiveData w celu automatycznego łączenia widoków w przypadku zmiany danych. W porównaniu z rozszerzeniami Kotlin dodaje sprawdzanie czasu kompilacji wyszukiwań widoku i bezpieczeństwa typów. Rozszerzenia Android Kotlin nie są oficjalnie zalecane (co nie jest tym samym, co zalecenie przeciwko). Wiąże się to z problemami wymienionymi powyżej, więc w naszym kodzie ich nie używamy. Butter Knife to kolejne rozwiązanie, które jest niezwykle popularne i działa zarówno dla Kotlina, jak i języka programowania Java. Czytanie komentarzy tutaj wielu programistów, którzy mają wielkie szczęście z rozszerzeniami Kotlin. To świetnie - i coś, o czym będziemy pamiętać, szukając sposobów dalszego ulepszania naszych interfejsów API. Jeśli nie spojrzałeś na wiązanie danych, zdecydowanie daj mu szansę.

Nawiasem mówiąc, nasz wewnętrzny przewodnik po stylach kodu nie jest przeznaczony do bezpośredniego stosowania poza naszą bazą kodu. Na przykład używamy mPrefixVariables, ale nie ma powodu, aby każda aplikacja miała taki styl.

user158
źródło