С выходом новой версии 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 ArrayListheroes; 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.
Комментариев нет:
Отправить комментарий