안드로이드의 RecyclerView는 앱에서 관리되는 데이터 집합을 화면에 유연하게 표시할 때 사용되는 뷰 그룹(View Group)입니다.
1. RecyclerView 구현
구현 예제는 포스팅 초입에 봤던 이미지처럼 영화 포스터를 포함한 영화 리스트를 보여주는 예제를 RecyclerView를 통해 구현하는 예제입니다.
1.1 외부 라이브러리 추가
▼ build.gradle 파일에 RecyclerView와 CardView를 사용하기 위해 위와 같이 라이브러리를 추가합니다.
1.2 메인 액티비티 레이아웃 리소스
<?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=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
▼ 메인 화면을 표시하기 위한 레이아웃 리소스에 RecyclerView를 배치한 형태입니다.
1.3 데이터 클래스 정의
package com.springsthursday.recyclerviewblog;
public class Movie {
private int imageResourceID;
private String movieTitle;
private String movieGrade;
public Movie(int id, String title, String grade)
{
this.imageResourceID = id;
this.movieTitle = title;
this.movieGrade = grade;
}
public int getImageResourceID() {
return imageResourceID;
}
public String getMovieTitle() {
return movieTitle;
}
public String getMovieGrade() {
return movieGrade;
}
public void setImageResourceID(int imageResourceID) {
this.imageResourceID = imageResourceID;
}
public void setMovieTitle(String movieTitle) {
this.movieTitle = movieTitle;
}
public void setMovieGrade(String movieGrade) {
this.movieGrade = movieGrade;
}
}
▼ 리스트의 한 개의 데이터 항목을 표현하기 위해 영화 정보를 담는 Movie Class입니다. 3개의 멤버 변수를 가지며 각각 영화 Poster의 ResourceID와 영화 제목 그리고 영화 관람등급에 관한 데이터를 담습니다. 생성자 함수를 통해 각 데이터를 입력받으며 각 멤버 변수에 대한 getter/setter 함수를 구현한 형태입니다.
1.4 RecyclerView에 데이터 표시를 위한 레이아웃 리소스
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:id="@+id/cardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
app:cardCornerRadius="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:layout_toRightOf="@id/imageView2"
android:text="TextView" />
<TextView
android:id="@+id/grade"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="-76dp"
android:layout_toRightOf="@id/imageView2"
android:text="TextView" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="100dp"
android:layout_height="100dp"
android:adjustViewBounds="true"
app:srcCompat="@mipmap/ic_launcher" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</android.support.constraint.ConstraintLayout>
▼ List의 한 항목을 표현하기 위한 XML 레이아웃 리소스입니다. 좀 더 이쁘게(?) 표현하기 위해 CardView 아래에 위젯들을 배치한 형태이며 영화 포스터와 제목 그리고 등급을 표현하기 위해 ImageView와 TextView를 배치하였습니다.
1.5 Adapter 구현
public class MyAdapter extends RecyclerView.Adapter<ViewHolder> {
private ArrayList<Movie> myDataList = null;
MyAdapter(ArrayList<Movie> dataList)
{
myDataList = dataList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
Context context = parent.getContext();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//전개자(Inflater)를 통해 얻은 참조 객체를 통해 뷰홀더 객체 생성
View view = inflater.inflate(R.layout.recyclerview_layout, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position)
{
//ViewHolder가 관리하는 View에 position에 해당하는 데이터 바인딩
viewHolder.imageView.setImageResource( myDataList.get(position).getImageResourceID());
viewHolder.title.setText(myDataList.get(position).getMovieTitle());
viewHolder.grade.setText(myDataList.get(position).getMovieGrade());
}
@Override
public int getItemCount()
{
//Adapter가 관리하는 전체 데이터 개수 반환
return myDataList.size();
}
}
ListView가 그렇듯 RecyclerView 역시 데이터 집합을 리스트로 표현하기 위해 데이터 집합을 관리하고 뷰(View)를 생성하는 어댑터(Adapter)가 필요합니다. RecyclerView.Adapter를 상속받는 클래스를 정의해야 하며 아래에 3개의 함수를 반드시 재정의해야 합니다.
재정의함수 | 설명 |
onCreateViewHoler(ViewGroup parent, int viewType) | 아이템 뷰를 관리하는 ViewHolder 객체 생성 |
onBindViewHolder(ViewHolder viewHolder, int position) | position에 해당하는 데이터를 ViewHolder가 관리하는 View에 바인딩(Binding) |
getItemCount() | Adapter가 관리하고 있는 데이터 집합의 전체 개수를 리턴 |
▼ 해당 클래스의 생성자 함수에서는 RecyclerView에 표시하기 위한 데이터 집합에 해당하는 ArrayList를 넘겨줍니다. ArrayList에 담기는 데이터 Type은 앞서 정의한 Movie Class입니다.
1.6 ViewHolder 구현
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
TextView title;
TextView grade;
ViewHolder(View itemView)
{
super(itemView);
imageView = itemView.findViewById(R.id.imageView2);
title = itemView.findViewById(R.id.title);
grade = itemView.findViewById(R.id.grade);
}
}
▼ RecyclerView.ViewHolder를 상속받는 ViewHolder 클래스를 정의합니다. 생성자 함수를 통해 넘어오는 View로부터 각 위젯의 참조를 얻어 멤버 변수로 가지고 있습니다.
1.7 RecyclerView에 Adapter 및 LayoutManager 등록
public class MainActivity extends AppCompatActivity {
private ArrayList<Movie> dataList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.InitializeData();
RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
LinearLayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL,false);
recyclerView.setLayoutManager(manager); // LayoutManager 등록
recyclerView.setAdapter(new MyAdapter(dataList)); // Adapter 등록
}
public void InitializeData()
{
dataList = new ArrayList<>();
dataList.add(new Movie(R.drawable.image1,"어벤져스", "12세관람가"));
dataList.add(new Movie(R.drawable.image2,"미션임파서블", "15세관람가"));
dataList.add(new Movie(R.drawable.image3,"아쿠아맨", "12세관람가"));
}
}
▼ onCreate()에서는 InitializeData() 함수를 호출하여 Adapter에 넘겨줄 데이터 집합을 생성합니다.
▼ RecyclerView의 강점 중 하나인 List에 각 항목을 나열하는 방식을 LayoutManager를 통해 지정 가능하다는 점입니다. 예로 리스트를 수평 방향으로 나열할 것인지 수직 방향으로 나열할 것인지 또는 격자(Grid) 무늬 형태로 나열할 것인지를 LayoutManager를 통해 쉽게 지정이 가능합니다. 예제에서는 수직 방향으로 나열하도록 구현하였습니다.
1.8 수직 방향으로 아이템 표시하기
LinearLayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,false);
▼ 위 예제에서 LinearLayoutManager 객체를 생성할 때 생성자 함수의 두 번째 인자를 위 형태로 변경합니다.