RecyclerView

RecyclerView
RecyclerView, ilgili LayoutManager sınıflarını kullanarak listenin yatay(horizontal), dikey(vertical), zik-zak(staggered), ızgara(grid) görünüme sahip olabilmesini sağlayan esnek ve performanslı bir View öğesidir.
RecyclerView ile ListView Karşılaştırılması
RecyclerView, ListView’in daha gelişmiş ve esnek bir versiyonudur. Maddeler halinde recyclerview ve listview karşılaştıralım.

Öğe Yerleşimlerini Özelleştirebilme
ListView sadece dikey olarak listenebilir ve bu özelleştirilemez.
Buna karşılık RecyclerView, yatay (horizontal), kademeli ızgara (grid), zik-zak (staggered) gibi yerleşim düzenlerine izin veren bir RecyclerView.LayoutManager’a sahiptir.

ViewHolder Kullanımı
ListView adaptörleri, performansı geliştirmek için ViewHolder modelinin kullanımını gerektirmez.
Buna karşılık, RecyclerView için bir adaptörün uygulanması, RecyclerView.Viewholder’ı kullandığı ViewHolder kullanılmasını gerektirir.

Animasyon Kullanımı
ListView, öğelerin eklenmesi veya silinmesinde animasyon eklemek için bir sınıfa sahip değildir.
Buna karşılık, RecyclerView animasyonlar için RecyclerView.ItemAnimator sınıfına sahiptir.
RecyclerView Kullanımı
ecyclerView Kullanımı
Bir önceki yazımızda RecyclerView tanımını, ListView ile karşılaştırılmasını incelemiştik. Şimdi de adım adım RecyclerView nasıl kullanılır inceleyelim.

Temel olarak yapmamız gerekenleri 4 adımda özetleyen aşağıdaki görseli hazırladım. Adım adım bu işlemleri uygulayacağız.


Projeye recyclerview ve cardview bağımlılıklarını ekleyelim.

ProjectStructure/app/Dependencies/+ butonu/Library Dependencies tıklayarak açılan pencerede recylerview yazıyoruz.
Listeden recylerview seçerek “OK” butonuna tıklıyoruz. Bu sayede recyclerview projemizin module app seviyesinde build.gradle içerisinde dependencies alanına eklenmiş oluyor.
Aynı işlemi cardview için de yapıyoruz. Artık projemizde RecylerView ve CardView kullanabiliriz. 

1. adımda item_product_card.xml dosyamızı hazırlayacağız.
Bunun için res/layout/ dizinine sağ tıklayarak New Resource File tıklayalım ve item_product_card.xml adında dosyamızı oluşturalım.
Bu dosyayı oluştururken Root Element kısmını “CardView” seçelim. İlk olarak tasarımızın son hali üzerinde componentlerin yerleşimini gösteren bir görsel hazırladım.
Görselde gördüğümüz silme ikonu için res/drawable klasörüne “ic_delete_yellow” adında ikonumuzu ekledikten sonra tasarımımız için kodları inceleyelim.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="5dp"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="5dp"
    app:cardCornerRadius="5dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/productImage"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:src="@drawable/ic_launcher_background" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical">

            <TextView
                android:id="@+id/productName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="3dp"
                android:layout_marginTop="9dp"
                android:text="productAdi"
                android:textSize="15dp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/productDescription"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="3dp"
                android:layout_marginTop="3dp"
                android:text="Aciklama"
                android:textSize="12dp"
                android:textStyle="italic" />


        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/deleteproduct"
                android:layout_width="25dp"
                android:layout_height="25dp"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="5dp"
                android:src="@drawable/ic_delete_yellow" />

        </LinearLayout>


    </LinearLayout>


</android.support.v7.widget.CardView>


Burada root elementimizin CardView olduğuna dikkat edelim. CardView bir LayoutViewGrouptur. Her CardView öğesi aslında listemizin bir satırını oluşturuyor.İsimlendirmesinde item ifadesini kullanma sebebimiz de bu. Her satırımızın kenarlarına radius özelliği vermek için CardView bileşenimize “cardCornerRadius” özelliğini kullandık.

2. adımda activity_main.xml içerisine RecylerView ekleyelim

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.hasibezafer.recyclerview.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recylerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v7.widget.RecyclerView>

</android.support.constraint.ConstraintLayout>

Burada 1. adımda oluşturmuş olduğumuz item_product_card yani her bir satır tasarımımız diyebiliriz bunu activity_main.xml’de gösteriyoruz.
RecylerView bileşenini kullanmamızı sağlayan kodu yazımızın en başında dependicies içerisine eklemiştik.

3. adımda kendimize bir “Veri Modeli” oluşturacağız.
MainActivity dosyamızın da bulunduğu java dizinimize Product.java adında bir dosya oluşturalım ve Veri Modelimizi hazırlayalım. Bu sınıfı oluşturmamızın sebebi her bir satırımızda farklı tiplerden oluşan verilere tek seferde ulaşıp satırı inflate etmek. 

Veri modelimizde fotoğraflara sırasıyla erişmek için int tipinde değişken, albüm adını ve açıklaması için String tipinde değişkenler oluşturduk. Kodlarımızı incelemeden önce her bir satırımızda kullanacağımız görseller res/drawable klasörüne eklemeyi unutmayalım. 

package com.example.hasibezafer.recyclerview;
import java.util.ArrayList;
/**
 * Created by tchzafer on 21/03/2018.
 */
public class Product {
    private String productName;
    private String productDescription;
    private int imageID;
    public Product() {
    }
    public Product(int imageID, String productName, String productDescription) {
        this.imageID = imageID;
        this.productName = productName;
        this.productDescription = productDescription;
    }
    public int getImageID() {
        return imageID;
    }
    public void setImageID(int imageID) {
        this.imageID = imageID;
    }
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    public String getProductDescription() {
        return productDescription;
    }
    public void setProductDescription(String productDescription) {
        this.productDescription = productDescription;
    }
    public static ArrayList<Product> getData() {
        ArrayList<Product> productList = new ArrayList<Product>();
        int productImages[] = {R.drawable.gelecegiyazanlar, R.drawable.paycell, R.drawable.tvplus,R.drawable.dergilik,R.drawable.bip,R.drawable.gnc,R.drawable.hesabim,R.drawable.sim,R.drawable.lifebox,R.drawable.merhabaumut,R.drawable.yaani,R.drawable.hayalortagim,R.drawable.gollercepte,R.drawable.piri};
        String[] productNames = {"Geleceği Yazanlar", "Paycell", "Tv+","Dergilik","Bip","GNC","Hesabım","Sim","LifeBox","Merhaba Umut","Yaani","Hayal Ortağım","Goller Cepte","Piri"};

        for (int i = 0; i < productImages.length; i++) {
            Product temp = new Product();
            temp.setImageID(productImages[i]);
            temp.setProductName(productNames[i]);
            temp.setProductDescription("Turkcell");

            productList.add(temp);

        }


        return productList;


    }
}

Kodlarımızı inceleyecek olursak, değişkenlerimizi tanımladıktan sonra bu değişkenleri çağırmak ve veri set etmek için “getter ve setter” metodlarını kullandık.

Satırımızı doldurmak için ArrayList<Product> tipinde getData() adında bir method yazıyoruz. ArrayList’imizin bizim oluşturduğumuz Product sınıfı tipinde veri tuttuğuna dikkat edelim. 

int tipinde productImages adında resimlerimizi tutan bir dizi oluşturduk. Resimlerimizi statik olarak drawable klasörüne ekledik. Ve bu dizide resimlerin path bilgisini tuttuk.Daha sonra resim sayısı kadar tüm bilgileri her bir satıra set etme işlemini yapan bir for döngüsü oluşturduk ve listemize ekledik. Methodumuz bize sonuç olarak productList döndü.

4. adımımızda ProductAdapter oluşturacağız.
Bu adıma kadar elimizde listemizin tasarımı, bu listeyi dolduracak verileri tutan bir sınıf var.
Şimdi de hazır olan verilerle satırımızı inflate işlemine geldi. Bunun için MainActivity dosyamızın da bulunduğu java dizinimize ProductAdapter.java adında bir dosya oluşturalım ve kodlarımızı inceleyelim.
 

package com.example.hasibezafer.recyclerview;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by tchzafer on 21/03/2018.
 */

public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.MyViewHolder> {

    ArrayList<Product> mProductList;
    LayoutInflater inflater;

    public ProductAdapter(Context context, ArrayList<Product> products) {
        inflater = LayoutInflater.from(context);
        this.mProductList = products;
    }


    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.item_product_card, parent, false);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Product selectedProduct = mProductList.get(position);
        holder.setData(selectedProduct, position);

    }

    @Override
    public int getItemCount() {
        return mProductList.size();
    }


    class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        TextView productName, productDescription;
        ImageView productImage, deleteproduct;

        public MyViewHolder(View itemView) {
            super(itemView);
            productName = (TextView) itemView.findViewById(R.id.productName);
            productDescription = (TextView) itemView.findViewById(R.id.productDescription);
            productImage = (ImageView) itemView.findViewById(R.id.productImage);
            deleteproduct = (ImageView) itemView.findViewById(R.id.deleteproduct);
            deleteproduct.setOnClickListener(this);

        }

        public void setData(Product selectedProduct, int position) {

            this.productName.setText(selectedProduct.getProductName());
            this.productDescription.setText(selectedProduct.getProductDescription());
            this.productImage.setImageResource(selectedProduct.getImageID());


        }


        @Override
        public void onClick(View v) {


        }

       
    }
}

Kodlarımızı inceleyecek olursak bilmemiz gereken ilk şey Adapter’ımızı RecyclerView.Adapter’dan extend etmek. Bu işlemi yaptığımızda import etmemiz gereken methodları tek tek inceleyelim.

onCreateViewHolder() : Bu method adaptör oluşturulduğunda oluşturduğumuz ViewHolder'ın başlatılması için çağrılır.
onBindViewHolder() : onCreateViewHolder’dan dönen verileri bağlama işlemini gerçekleştirildiği metotdur.
getItemCount() : Listemizin eleman sayısını döndüren metottur.
MyViewHolder(): Her bir satırımızın içinde bulunan bileşenleri tanımlama işleminin yapıldığı metottur.

LayoutInflater sınıfından inflater adında bir nesne tanımlıyoruz. MainActivity sınıfımızda Adapter’ımızdan bir nesne türettiğimizde çalışacak ilk method Constructor olduğu için Adapter içerisinde Constructor’ı tanımlamamız gerekir.Context üzerinden getSystemService ile inflater erişmek için methodumuza parametre olarak Context, ArrayList<> doldurmak içinde Product tipinde listemizi ArrayList<Product> şeklinde parametre olarak yolladık.

MyViewHolder() methodunu inceleyecek olursak burada  path bilgisini inflate() methodunun ilk parametresi olarak vererek View tipinde nesnemizi elde ettik. Oluşturulan bu nesneyi MyViewHolder tipine dönüştürerek holder return ettik.

MyViewHolder içerisinde item_product_layout.xml içerisindeki bileşenleri tanımladık.

onBindViewHolder() methodu içerisinde onCreateViewHolder’dan dönen holder ve position parametre olarak gönderip listenin hangi veri ile dolacağını ve elemana tıklanma olaylarını kontrol edebileceğiz. Bunun içinde setData() adında bir method oluşturarak tıklanılan verinin bilgilerini getter metodu ile alarak setter methodu ile ilgili yere set ediyoruz. 

5. ProductAdapter’ı listemize bağlıyoruz.
Ve son adımımızda listemizi görüntülemek için oluşturmuş olduğumuz adapter’ı MainActivity.java içerisinde listemize bağlıyoruz. Kodlarımızı inceleyelim.
 

package com.example.hasibezafer.recyclerview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = (RecyclerView) findViewById(R.id.recylerview);

        ProductAdapter productAdapter = new ProductAdapter(this, Product.getData());
        recyclerView.setAdapter(productAdapter);

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(linearLayoutManager);

    }
}

Burada adapterımızı listemize bağlamak için setAdapter() kullanıyoruz.
Farklı olarak LinearLayoutManager sınıfından bir nesne üretip listemizin orientation bilgisini set ediyoruz. Bu sayede listemizi yatay, dikey, grid ve staggered şeklinde gösterebiliyoruz.Bu örneğimizde dikeyde listeledik.
Bir sonraki yazımızda OptionsMenu ile tüm Layout biçimlerini set edip, tıklanma ve silme işlemlerini açıklayacağız.
RecyclerView Hizalama ve Silme İşlemi
Bu bölümde elemanları dikey olarak listelediğimiz projemize OptionsMenu ekleyerek; yatay(horizontal), ızgara(grid), zik-zak(staggered) olarak hizalanmasını sağlayacağız. Ve listedeki elemanları eklediğimiz silme butonu yardımı ile silme işlemini gerçekleştireceğiz. 

İlk olarak OptionsMenu oluşturalım.
Bunun için res/menu klasörüne sağ tıklayarak “New/Menu Resource File” seçiyoruz ve layout_menu.xml adında dosyamızı oluşturuyoruz. Buraya iki menü ekliyoruz. Eklemek için kodlarımız şu şekilde:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <item
        android:id="@+id/gridView"
        android:icon="@drawable/ic_grid_two_white"
        android:title="LinearView Horizontal"
        app:showAsAction="always">

    </item>
    <item
        android:id="@+id/linearViewVertical"
        android:icon="@drawable/ic_list_white"
        android:title="LinearView Vertical"
        app:showAsAction="always">

    </item>


</menu>

 

Eklediğimiz ikonların Toolbar üzerinde görünmesi için MainActivity içerisinde gerekli tanımlamamızı yapalım.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.layout_menu, menu);
    return super.onCreateOptionsMenu(menu);
}

Burada onCreateOptionsMenu() metodu ile oluşturmuş olduğumuz layout_menu dosyamızın yolunu belirterek inflate ediyoruz.

Tanımlamamızı da yaptıktan sonra toolbar üzerinde şu şekilde iki ikon eklenmiş oldu.
Eklediğimiz ikonlara tıklanma(click) işlemlerini kontrol etmek
Bu işlem için yararlandığımız metod onOptionsItemSelected() metodudur. Kodlarımızı inceleyerek gerekli açıklamalarımızı yapalım.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
    switch (id) {

        case R.id.linearViewVertical:
            linearLayoutManager = new LinearLayoutManager(this);
            linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
            recyclerView.setLayoutManager(linearLayoutManager);
            break;
        case R.id.gridView:
            GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
            recyclerView.setLayoutManager(gridLayoutManager);
            break;


    }
    return super.onOptionsItemSelected(item);
}
 

Metodumuza parametre olarak menümüzde yer alan item bilgisini gönderdik. 
int tipinde bir değişken oluşturduk ve tıklanan ikonun(item) id bilgisini getItemId() metodu ile alarak bu değişkene atadık.
Artık elimizde hangi ikona tıklandığı bilgisi mevcut. Bu bilgi ile switch-case blogumuzu yazarak ikona tıklandığında yapmak istediğimiz işlemi yazıyoruz.

Listemizin dikey(vertical) şekilde görüntülenmesi için:
LinearLayoutManager sınıfından yararlanıyoruz. Bu sınıftan oluşturduğumuz objemize setOrientation() methodu yardımı ile VERTICAL ya da HORIZONTAL bilgisini ekliyoruz. 

Listemizin ızgara(grid) şeklinde görüntülenmesi için:
GridLayoutManager sınıfından yararlanıyoruz. Izgara sayımızı ikinci parametre olarak metodumuza gönderiyoruz.

LayoutManager yardımı ile oluşturduğumuz bu görünümleri listemize uygulamak için setLayoutManager() metodunu kullanıyoruz. Seçilen item return ederek işlemimizi tanımlıyoruz. Bizim liste elemanlarımızın hepsi aynı boyutta olduğu için zik-zak ve yatay eklemedik. Fakat eklemek isterseniz ilgili kodlar şu şekilde: 

Listemizin zik-zak(staggered) şeklinde görüntülenmesi için:
Zik-zak(staggered) görünümü için liste elemanlarınızın farklı boyutta olması gereklidir. Bu görünüm için menümüze ikon ekleyip StaggeredLayoutManager() sınıfından yararlanabilirsiniz. Gerekli kod parçacığı şu şekilde. 

StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
Burada zik-zak görünümün yatay ya da dikeyde görünümü için VERTICAL HORIZONTAL değişimi yapabilirsiniz.

Listemizin yatay(horizontal) şeklinde görüntülenmesi için:
Yatay(horizontal) görünümü elde etmek gerekli kod parçacığımız şu şekilde.

LinearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);

Silme İşlemi
Listemizden bir elemanı silmek için ProductAdapter içerisinde Overrride edilen onClick() metodu içerisine silme işlemimizi gerçekleştiren deleteProduct() adında bir method tanımlıyoruz. Kodlarımız üzerinden inceleyelim.

@Override
public void onClick(View v) {
    if (v == deleteproduct) {
        deleteproduct(getLayoutPosition());
    }

}

private void deleteproduct(int position) {
    mProductList.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position, mProductList.size());
}
deleteproduct() methodumuz içerisine position bilgisini tutan bir parametre almakta. Bu da listenin hangi elemanını sileceğimiz bilgisini bize sunuyor. 
mProductList adındaki listemiz üzerinden remove() metoduna position bilgisini vererek silme işlemini gerçekleştiriyoruz. 

notifyItemRemoved() : Listedeki elemanın silindiğini listeye bildiren method.

notifyItemRangeChanged(): Eleman silindikten sonra listenin boyutunu(size) güncelleyen method.

Liste elemanları silinirken notifyItemRemoved() methodu ile özel bir animasyon ile silinir. RecyclerView yazımıza burada son veriyoruz.

Yorumlar

Bu blogdaki popüler yayınlar

İç İçe Döngüler

CSS Bir Elemanın Genişliği ve Yüksekliği

JavaScript Dilinde Fonksiyon Çağırma Teknikleri