👨🏼‍💻 RecyclerView Multiple View Types

Sertaç Ayhan
Huawei Developers - Türkiye
4 min readJun 3, 2022
# Image Source

Giriş

Merhaba arkadaşlar, bu yazımda sizlere RecyclerView’ı farklı view tipleriyle beraber kullanarak gerçek bir problemi nasıl çözeriz sorusunun cevabını aktarmaya çalışacağım. Keyifli okumalar :)

Problem : <PhotoModel>’lerden oluşan bir listem var. Bu model fotoğrafın path’ini ve koordinat bilgisini vb. değerleri tutuyor. Ben bu fotoğrafları ekranda tarihlerine göre gruplandırılmış bir şekilde görmek istiyorum.

Sizin de bildiğiniz gibi RecyclerView yapısı her satırda benzer öğeleri içeren bir liste oluşturuyor. Ancak bu sefer birden fazla türde öğe içeren tamamen farklı türde bir liste oluşturacağız. Benim oluşturacağım layout, date değerini gösterecek bir TextView ve o date değerine sahip fotoğrafları gösterecek olan ImageView’dan oluşacak. Hadi başlayalım.

Layouts

fragment xml’imiz

Date değerini gösterecek date_item.xml’imiz

Fotoğrafları gösterecek gallery_item.xml’iz.

RecyclerView Item Data Class

RecyclerView data’sını tutabilmek için sealed class yazıyoruz.

RecyclerView Adapter

Sıradan RecyclerViewAdapter’a benzeyen bir kod yazdık, buradaki ekstra getItemViewType() fonksiyonu . Bu fonksiyonla layout id’den gelen item’in tipini kontrol ediyoruz.

onCreateViewHolder() içinde gelen ViewType’a göre, ViewHolder instance üretiyoruz.

onBindViewHolder() içinde holder’in tipini kontrol edip buna göre data’yı ViewHolder ile bind ediyoruz

RecyclerView ViewHolders

Genellikle yalnızca tek bir ViewHolder yaparız, ancak bu sefer karmaşık bir liste oluşturuyoruz ve birden fazla ViewHolder’a ihtiyacımız var. Her ViewHolder, listemiz için gerekli olan belirli bir View’a sahip olacaktır.
Sealed bir ViewHolder class’ı oluşturdum ve ardından tüm ViewHolder (bu durumda 2) class’larım aynı sealed ViewHolder class’ı kullanılarak tanımlandı. Sealed class kullanmak, bunların yalnızca ViewHolder için kullanılabilen seçenekler olduğundan emin olmamıza yardımcı olacaktır. Daha fazla View tipine ihtiyacınız varsa, bu sealed class’a daha fazla ViewHolder ekleyebilirsiniz.
Ayrıca her ViewHolder uygulamasının içinde, verilen öğeyi View ile bağlayacak bir bind fonksiyonumuz var.

ViewModel

PhotoModel

ViewModel’i anlatmadan önce kısaca kullandığım PhotoModel’den bahsedeceğim.

PhotoModel

Bu PhotoModel class’ı bizim fotoğrafın bilgilerini tuttuğumuz bir data class. Gördüğünüz gibi path ve coordinate değişkenlerini ve ClusterItem tutuyor. Bu ClusterItem ise getLatitude, getLongtitude gibi yetenekleri sağlayan, kütüphanenin kendisinden gelen bir interface. Biz buradaki path değeriyle işlem yapacağımız için daha fazla detaya girmiyorum. Kütüphanenin detaylarını öğrenmek için aşağıdaki linke göz atabilirsiniz :)

Bize PhotoModel’lerden oluşan bir liste dönüyor. Bu listeyi parcelable ile HomeFragment’dan ClusteredPhotosFragment’a taşıdım.

Şimdi sırada ViewModel’imiz var. ilk olarak items adında ClusteredPhotosViewItem tipinde veri alan bir mutable list oluşturdum. Bu liste bize dönen fotoğraf listesini tarihe göre gruplayıp tutmamızı sağlayacak.

Bunu yapmak için setClusteredItems adında Array<PhotoModel> tipinde photolist, ContentResolver tipinde contentResolver parametleri olan bir fonksiyon yazdım. Bu fonksiyon groupBy ile ilk olarak fotoğrafın path’ini kullanarak fotoğrafın çekildiği date’i ClusteredPhotosViewItem’ in date değişkenine atıyor.

Sonrasında bu date’i bir extension fonksiyon ile istediğimiz formata çeviriyoruz. Ardından forEach ile o date’i items listesinin date kısmına atıyoruz. Sonrasında tekrardan forEach kullanarak o date’e sahip her fotoğrafın path değişkenini yine items listesinin tipi olan ClusteredPhotosViewItem’ in image değişkenine atıyoruz.

Bu sayede fotoğraflarımız tarihe göre gruplanmış oluyor :)

getDateInfoFromPhoto fonksiyonu adından da anlaşılacağı üzere fotoğraftan bilgileri almamıza yarayan bir fonksiyon. Bu Exif interface sayesinde mümkün oluyor. Telefon hafızasındaki fotoğrafları gösterme ve fotoğrafların konum bilgilerine nasıl ulaşacağınızı bilmiyorsanız takım arkadaşımın bu yazısını inceleyebilirsiniz. Exif interface’i nasıl kullanabiliriz sorusunun cevabını da bu yazıda bulabilirsiniz :)

getFormattedDate fonksiyonu da yine adından anlaşılacağı üzere, bize dönen date’i istediğimiz formata dönüştürmeye yarıyor.

RecyclerView oluşturma

Evet arkadaşlar sona geldik, Bize PhotoModel’lerden oluşan bir liste dönüyor. Bu listeyi parcelable ile HomeFragment’dan ClusteredPhotosFragment’a taşıdım. Sonrasında setupUi fonksiyonu içinde viewModel’da yazdığımız setClusteredItems fonksiyonuna parametre olarak verdik. setupUi fonksiyonu bizim BaseFragment’ta yazdığımız onViewCreated() içinde çalışan bir fonksiyon, base’de yazdığımız için override edip kullandık yanı aslında direkt olarak onViewCreated() içinde kullandığımızı düşünebilirsiniz.

Sonrasında sırasıyla o tarihi ve o tarihe ait fotoğrafları gösterebilmek için GridLayoutManager’ı SpanSizeLookup fonksiyonuyla beraber içeride getSpanSize fonksiyonu ile kullandık. Bu fonksiyon position daki ögenin kapladığı yayılma sayısını döndürüyor.. Date’in tekli şekilde, fotoğrafların 4'lü şekilde gözükmesini istedim. date_item’a 4, gallery_item’a 1 vermemizin sebebi bu yapının ters bir mantığa sahip olmasından kaynaklanıyor.

En son artık RecyclerView tanımımızı yapıp LayoutManager’ını belirtiyoruz. Adapterımızı listemize bağlıyoruz ve RecyclerView ile Adapter’i eşleştiriyoruz.

Sonuç

Sonunda tarihlerine göre gruplandırılmış fotoğrafları görüntüleyebiliyoruz :)

--

--