С выходом новой версии 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.

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