RecyclerView, Android'de liste veya grid gibi tekrarlayan verileri performanslı bir şekilde göstermek için kullanılan en güçlü bileşenlerden biridir. Modern Android uygulamalarında, eski ListView bileşeninin yerini tamamen almıştır. Bu makalede RecyclerView’un ne olduğunu, nasıl kullanıldığını ve en iyi kullanım pratiklerini adım adım öğreneceksiniz.
RecyclerView Nedir?
RecyclerView, Android Jetpack kütüphanelerinin bir parçasıdır ve büyük veri setlerinin verimli bir şekilde kullanıcıya sunulmasını sağlar. Adından da anlaşılacağı gibi, görünüm hücrelerini geri dönüştürerek (recycle) belleği ve işlemciyi optimize eder.
Özellikleri:
- Scroll edilebilir liste ve grid oluşturma
- Farklı ViewType desteği
- Animasyonlarla geçişler
- Swipe, drag & drop desteği
- ViewBinding, DiffUtil, ListAdapter ile uyumluluk
Gerekli Bağımlılıklar
build.gradle (app):
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.3.1'
}
Jetpack Compose kullanmıyorsanız RecyclerView için bu bağımlılık yeterlidir. Ek olarak ViewBinding aktif olmalıdır:
android {
buildFeatures {
viewBinding true
}
}
RecyclerView Kullanım Adımları
RecyclerView kullanımı için temel bileşenler şunlardır:
- RecyclerView bileşeni (layout içinde)
- ViewHolder (her bir satırı temsil eden sınıf)
- Adapter (veriyi bağlayan sınıf)
- LayoutManager (liste düzeni)
1. XML Tasarımı
activity_main.xml
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:listitem="@layout/item_user" />
item_user.xml
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:elevation="4dp"
android:padding="12dp">
<TextView
android:id="@+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kullanıcı Adı"
android:textSize="18sp"
android:textStyle="bold" />
</androidx.cardview.widget.CardView>
Model Sınıfı
data class User(val id: Int, val name: String)
ViewHolder ve Adapter
class UserAdapter(private val userList: List<User>) :
RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
inner class UserViewHolder(val binding: ItemUserBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val binding = ItemUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return UserViewHolder(binding)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val user = userList[position]
holder.binding.textViewName.text = user.name
}
override fun getItemCount(): Int = userList.size
}
RecyclerView Tanımlama – MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val sampleList = listOf(
User(1, "Ahmet Yılmaz"),
User(2, "Zeynep Demir"),
User(3, "Mehmet Kara")
)
val adapter = UserAdapter(sampleList)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = adapter
}
}
ListAdapter ve DiffUtil ile Gelişmiş Kullanım (Önerilir)
RecyclerView içinde büyük veri setleriyle çalışırken notifyDataSetChanged() yerine DiffUtil kullanmak performansı ciddi oranda artırır.
class UserDiffCallback : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(oldItem: User, newItem: User) = oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: User, newItem: User) = oldItem == newItem
}
class UserListAdapter : ListAdapter<User, UserListAdapter.UserViewHolder>(UserDiffCallback()) {
inner class UserViewHolder(val binding: ItemUserBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val binding = ItemUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return UserViewHolder(binding)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val user = getItem(position)
holder.binding.textViewName.text = user.name
}
}
En İyi Kullanım Tavsiyeleri
- ViewBinding kullanın: XML şişkinliğini azaltır, hataları önler.
- ListAdapter + DiffUtil: Büyük veri setlerinde
notifyDataSetChanged()yerine tercih edilmelidir. - ViewType desteği ekleyin: Farklı satır görünümleri gerekiyorsa
getItemViewType()ile destekleyin. - Lifecycle-aware yaklaşım: LiveData veya StateFlow ile birlikte kullanın.
- RecyclerView optimizasyonları:
setHasFixedSize(true)kullanımı performansı artırır.
RecyclerView ile Kullanılabilecek Diğer Olaylar ve Özellikler
1. Sonsuz Liste / Sayfalama (Pagination)
Büyük veri setlerinde verilerin hepsini aynı anda yüklemek hem kullanıcı deneyimini bozar hem de performans sorunlarına neden olur. Bunun yerine, verileri sayfa sayfa yüklemek (infinite scroll) tercih edilir.
Kullanım Mantığı:
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val lastVisibleItem = layoutManager.findLastVisibleItemPosition()
val totalItemCount = layoutManager.itemCount
if (!isLoading && lastVisibleItem >= totalItemCount - 3) {
loadNextPage() // API'den sonraki verileri çek
isLoading = true
}
}
})
2. Swipe ile Silme (Swipe to Delete)
RecyclerView’de bir öğeyi sağa veya sola kaydırarak silmek için ItemTouchHelper kullanılır.
val itemTouchHelperCallback = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder) = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val position = viewHolder.adapterPosition
myList.removeAt(position)
adapter.notifyItemRemoved(position)
}
}
ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(recyclerView)
3. Drag & Drop
Öğelerin sürüklenerek yer değiştirmesini sağlamak için yine ItemTouchHelper kullanılabilir. Bu sayede kullanıcılar liste sırasını değiştirebilir.
4. Çoklu ViewType Kullanımı (Multiple View Types)
Bazı listelerde farklı tipte öğeler aynı RecyclerView içinde gösterilir. Örneğin, başlık, içerik ve footer gibi. Bunun için getItemViewType() metodu kullanılır.
override fun getItemViewType(position: Int): Int {
return when (items[position]) {
is Header -> VIEW_TYPE_HEADER
is Content -> VIEW_TYPE_CONTENT
is Footer -> VIEW_TYPE_FOOTER
else -> throw IllegalArgumentException("Bilinmeyen tip")
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
VIEW_TYPE_HEADER -> {
val binding = ItemHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
HeaderViewHolder(binding)
}
VIEW_TYPE_CONTENT -> {
val binding = ItemContentBinding.inflate(LayoutInflater.from(parent.context), parent, false)
ContentViewHolder(binding)
}
VIEW_TYPE_FOOTER -> {
val binding = ItemFooterBinding.inflate(LayoutInflater.from(parent.context), parent, false)
FooterViewHolder(binding)
}
else -> throw IllegalArgumentException("Bilinmeyen viewType")
}
}
5. Item Seçimi & Vurgulama (Selection State)
RecyclerView öğelerinin seçilmesi ve seçili öğelerin vurgulanması için item'ların durumunu yönetmeniz gerekir. Basitçe adapter içinde seçili pozisyonu tutabilir ve seçimi değiştirdiğinizde ilgili itemların arayüzünü güncelleyebilirsiniz.
class UserAdapter(private val userList: List<User>) :
RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
private var selectedPosition = RecyclerView.NO_POSITION
inner class UserViewHolder(val binding: ItemUserBinding) :
RecyclerView.ViewHolder(binding.root) {
init {
binding.root.setOnClickListener {
notifyItemChanged(selectedPosition)
selectedPosition = adapterPosition
notifyItemChanged(selectedPosition)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val binding = ItemUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return UserViewHolder(binding)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val user = userList[position]
holder.binding.textViewName.text = user.name
holder.itemView.isSelected = (selectedPosition == position)
// Veya farklı bir vurgulama: background renk değiştirme gibi
holder.itemView.setBackgroundColor(
if (selectedPosition == position) Color.LTGRAY else Color.WHITE
)
}
override fun getItemCount(): Int = userList.size
}
Eğer RecyclerView ile ilgili daha spesifik bir kullanım veya kod örneği istersen, ya da başka Android konularında destek lazım olursa bana sorabilirsin.