Как использовать RecyclerView в Android


С выходом новой версии Android и привнесением в мир нового течения Material Design-а, появились и обновлённые, более современные версии старых вьюшек. Одно из таких обновлений затронуло и привычны вид отображения списка - ListView, на замену которого пришёл более быстрый и многофункциональный RecyclerView.




Главным отличием RecyclerView является создания всех элементов списка единожды, в отличии от ListView, где каждая View в списке создавалась отдельно для каждого из элементов списка, что в свою очередь приводило к огромному использованию памяти при создании достаточно больших списков.


Как начать работать с RecyclerView.


Для начала необходимо подключить библиотеку RecyclerView. Сделать это можно либо прописав зависимости в Gradle файл, либо же нажав кнопку F4 на нашем проекте и перейдя в вкладку "Dependencies". Так же подключим библиотеку CardView, так как элементы списка будем отображать в виде карточек и библиотеку Picasso, с помощью которой подгрузим изображения.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.android.support:cardview-v7:21.0.3'
    compile 'com.android.support:recyclerview-v7:21.0.3'
    compile 'com.squareup.picasso:picasso:2.3.2'
}



Теперь создадим отображение нашего списка, поместив в layout  активности наш RecyclerView.
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:tag="main activity layout container"
    tools:context=".MainActivity"
    >
    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        />
</LinearLayout>


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


hero_card.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:tag="cards main container"  >
    <android.support.v7.widget.CardView
        android:id="@+id/perfume_card"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="2dp"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="7dp"
        android:layout_marginRight="7dp"
        card_view:cardElevation="5dp">
       <RelativeLayout
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <ImageView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:id="@+id/image"
               android:background="@drawable/ic_launcher"/>
           <TextView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="Капитан Америка"
               android:id="@+id/hero_name"
               android:layout_alignParentTop="true"
               android:layout_centerHorizontal="true" />
           <TextView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="DC UNIVERSE"
               android:id="@+id/hero_universe"
               android:layout_below="@+id/hero_name"
               android:layout_centerHorizontal="true" />
           </RelativeLayout>
        </android.support.v7.widget.CardView>
    </RelativeLayout>

card_view:cardElevation="5dp" - Новый параметр в Material Design, указывающий на высоту на которую поднимается элемент, по сути размер тени, которую он откидывает.


Далее нам потребуется создать модель, для хранения наших данных. Для этого создадим класс HeroData.java и поместим туда нижеприведённый код, который содержит наши данные и геттеры для их дальнейшего получения. Создадим класс HeroData.java :


package com.awesomedevelop.recyclerview;

/**
 * Created by AwesomeDevelop on 30.01.2015.
 */
public class HeroData {
    String name;
    String image;
    String universe;


    public HeroData(String name, String universe, String image) {
        this.name = name;
        this.universe = universe;
        this.image = image;
    }


    public String getName() {return name;}
    public String getUniverse(){return universe;}
    public String getImage() {return image;}

}



Создавать элементы списка нам будет наш кастомный адаптер, который будет создавать представление элементов для всего списка сразу, а не для для каждого по отдельности и работа с которым не отличается от работы с кастомными адаптерами при использовании ListView.
HeroAdapter.java

package com.awesomedevelop.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 com.squareup.picasso.Picasso;

import java.util.ArrayList;

/**
 * Created by Taras on 30.01.2015.
 */
public class HeroAdapter extends RecyclerView.Adapter {

    private ArrayList heroDataSet;
    public Context mContext;
    private int lastPosition = -1;
    public static class MyViewHolder extends RecyclerView.ViewHolder  {
        TextView textName;
        TextView textUniverse;
        ImageView imageHero;

        public MyViewHolder(View itemView){
            super (itemView);
            this.imageHero = (ImageView)itemView.findViewById(R.id.image);
            this.textName = (TextView)itemView.findViewById(R.id.hero_name);
            this.textUniverse = (TextView)itemView.findViewById(R.id.hero_universe);
        }
    }



    public HeroAdapter(Context context, ArrayList heroes){
        this.heroDataSet= heroes;
        mContext=context;
    }


    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent,
                                           int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.hero_card, parent, false);
        MyViewHolder myViewHolder = new MyViewHolder(view);

        return myViewHolder;
    }




    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int listPosition) {

        final TextView textViewName = holder.textName;
        final TextView textViewUniverse = holder.textUniverse;
        ImageView imageViewHero = holder.imageHero;
        textViewName.setText(heroDataSet.get(listPosition).getName());
        textViewUniverse.setText(heroDataSet.get(listPosition).getUniverse());

        String src = heroDataSet.get(listPosition).getImage();
        Picasso.with(mContext)
                .load("file:///android_asset/images/"+src+".jpg")
                .resize(300, 300)
                .into(imageViewHero);
    }

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

}


В данном примере используются изображения, хранящиеся в папке асетов, но использовать можно (по необходимости) любое расположение. Например если используя библиотеку Picasso вы укажете путь к онлайновому расположению изображений, они будут подгружаться только для тех элементов списка, которые будут отображены на экране в данный момент, а не для всего списка сразу  при его построении.


Теперь нам осталось только заполнить наш массив данных и передать его адаптеру. Выполняем это в активности, которая будет отображать список, в данном случае MainActivity.java


package com.awesomedevelop.recyclerview;

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

import java.util.ArrayList;


public class MainActivity extends ActionBarActivity {
    private static ArrayList heroes;
    private static RecyclerView recyclerView;
    private RecyclerView.LayoutManager layoutManager;
    private static RecyclerView.Adapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView)findViewById(R.id.my_recycler_view);
        recyclerView.setHasFixedSize(true);
        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);

        fetchHeroes(); //Заполняем массив 
        adapter = new HeroAdapter(MainActivity.this,heroes); //Инициализируем наш адаптер
        recyclerView.setAdapter(adapter);   // Устанавливаем адаптер

    }

 //Заполняем массив 
    public void fetchHeroes(){
        heroes = new ArrayList();

        heroes.add(new HeroData("Зелёный Фонарь","DC comics","greenlantern"));
        heroes.add(new HeroData("Джокер","DC comics","joker"));
        heroes.add(new HeroData("Джона Хекс","DC comics","jonah-hex"));
        heroes.add(new HeroData("Папа Миднайт","DC comics","glav"));
        heroes.add(new HeroData("Ворона","DC comics","raven"));
        heroes.add(new HeroData("Чёрная Вдова","Marvel","glavnaya"));
        heroes.add(new HeroData("Капитан Америка","Marvel","cap_america"));
        heroes.add(new HeroData("Космический Халк","Marvel","cosmic_hulk"));
        heroes.add(new HeroData("Призрачный Гонщик","Marvel","ghost_rider"));


    }





    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Использование RecyclerView значительно улучшает работу со списками, помимо оптимизации использования памяти его использование позволяет создавать более сложные элементы списка, которые могут быть абсолютно любыми, вплоть до создания полноценных экранов в виде элементов списка.

Проект на github.

Share on Google Plus

Автор Unknown

Android разработчик и Google-фил. В рабочее время пишу код, в свободное - его читаю. Google+

Комментариев нет:

Отправить комментарий