일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- glide
- 동적 링크
- component
- 안드로이드광고
- android daum map
- 안드로이드 카카오 지도
- 안드로이드
- android kakao map
- 클린 아키텍처
- dynamiclink
- 애드몹광고
- thread
- RecyclerView
- Android
- 애드몹배너
- 젯팩컴포즈
- 파이어베이스
- ImageView
- Android 애드몹
- android 지도
- Clean Architecture
- 컴포넌트
- 선언형UI
- 다이나믹 링크
- 아키텍처
- 안드로이드컴포즈
- JetpackCompose
- Firebase
- 안드로이드 라이브러리
- HTTP
- Today
- Total
코딩스토리
[Android/안드로이드] 하나의 아답타로 여러개의 RecyclerView만들기/ RecyclerView Adapter 재사용 본문
[Android/안드로이드] 하나의 아답타로 여러개의 RecyclerView만들기/ RecyclerView Adapter 재사용
라크라꾸 2019. 12. 22. 23:46이번 시간에는 하나의 Adapter를 재사용하면서 여러개의 RecyclerView를 만들어 보겠습니다.
다음과같이 RecyclerView레이아웃을 만들 때 Adapter가 모듈로 정리되어있지 않을 경우라면 왼쪽에 있는 Adapter와 오른쪽에 있는 Adapter, 총 2개의 Adapter가 생겨날 것입니다. 규모가 작은 프로젝트의 경우 여러개 만든다고 해도 유지보수하기 수월하겠지만, 규모가 커질수록, RecyclerView를 많이 사용하게 된다면 Adapter의 양이 어마어마해져 유지보수를 하는데 어려움을 겪을 수 있습니다.
이번 시간에는 Adapter를 모듈화시키면서 유지보수하기 쉽고, 코드도 간결하도록 여러개의 Adapter클래스를 하나로 줄여보도록 하겠습니다.
상속받을 상위 클래스 생성
모듈화를 시키기 위해서 우선 RecyclerView.ViewHolder를 상속받는 MyItemView클래스와 Serializable를 상속받는 MyItem클래스를 생성해줍니다.
MyItem.java
package com.example.recyclerviewtest;
import java.io.Serializable;
public class MyItem implements Serializable {
}
MyItemView.java
package com.example.recyclerviewtest;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class MyItemView extends RecyclerView.ViewHolder {
public MyItemView(@NonNull View itemView) {
super(itemView);
}
}
모듈화를 시키기 위해서는 클래스타입을 일치시켜 줘야 하기 때문에 Data부분에서는 상위 클래스로 MyItem을, ViewHolder부분에서는 상위클래스로 MyItemView로 지정해줘 타입을 일치시켜줍니다.
Data
DataMovie.java
package com.example.recyclerviewtest;
public class DataMovie extends MyItem{
int image;
String title;
public DataMovie(int image, String title){
this.image = image;
this.title = title;
}
public int getImage() {
return image;
}
public void setImage(int image) {
this.image = image;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
Enum클래스 생성
MovieCase.java
package com.example.recyclerviewtest;
public enum MovieCase {
SMALL,LARGE
}
이미지를 크게 보여줄 ViewHolder인지, 작게 보여줄 ViewHolder인지 구분하기 위해서 Enum클래스로 타입을 생성해줍니다.
EventListener
이전시간에 사용했던 RecyclerView접기/펼치기 기능을 사용하기 위해 리스너를 구현해줍니다.
package com.example.recyclerviewtest;
public interface OnViewHolderItemClickListener {
void onViewHolderItemClick();
}
ViewHolder 생성
ViewHolderMovieLarge.java
package com.example.recyclerviewtest;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
public class ViewHolderMovieLarge extends MyItemView {
TextView tv_movie_title;
ImageView iv_movie;
DataMovie data;
public ViewHolderMovieLarge(@NonNull View itemView) {
super(itemView);
iv_movie = itemView.findViewById(R.id.iv_movie);
tv_movie_title = itemView.findViewById(R.id.tv_movie_title);
}
public void onBind(MyItem data){
this.data = (DataMovie) data;
tv_movie_title.setText(this.data.getTitle());
iv_movie.setImageResource(this.data.getImage());
}
}
ViewHolderMovieSmall.java
package com.example.recyclerviewtest;
import android.animation.ValueAnimator;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
public class ViewHolderMovieSmall extends MyItemView {
TextView tv_movie_title;
ImageView iv_movie,iv_movie2;
LinearLayout linearlayout;
OnViewHolderItemClickListener onViewHolderItemClickListener;
DataMovie data;
public ViewHolderMovieSmall(@NonNull View itemView) {
super(itemView);
iv_movie = itemView.findViewById(R.id.iv_movie);
tv_movie_title = itemView.findViewById(R.id.tv_movie_title);
iv_movie2 = itemView.findViewById(R.id.iv_movie2);
linearlayout = itemView.findViewById(R.id.linearlayout);
linearlayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onViewHolderItemClickListener.onViewHolderItemClick();
}
});
}
public void onBind(MyItem data, Boolean isSelect){
this.data = (DataMovie) data;
tv_movie_title.setText(this.data.getTitle());
iv_movie.setImageResource(this.data.getImage());
iv_movie2.setImageResource(this.data.getImage());
changeVisibility(isSelect);
}
private void changeVisibility(final boolean isExpanded) {
// ValueAnimator.ofInt(int... values)는 View가 변할 값을 지정, 인자는 int 배열
ValueAnimator va = isExpanded ? ValueAnimator.ofInt(0, iv_movie2.getHeight()) : ValueAnimator.ofInt(iv_movie2.getHeight(), 0);
// Animation이 실행되는 시간, n/1000초
va.setDuration(500);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// imageView의 높이 변경
iv_movie2.requestLayout();
// imageView가 실제로 사라지게하는 부분
iv_movie2.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
}
});
// Animation start
va.start();
}
public void setOnViewHolderItemClickListener(OnViewHolderItemClickListener onViewHolderItemClickListener) {
this.onViewHolderItemClickListener = onViewHolderItemClickListener;
}
}
Adapter 모듈화
RecyclerVierAdapter.java
package com.example.recyclerviewtest;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
public class RecyclerVierAdapter extends RecyclerView.Adapter<MyItemView> {
// adapter에 들어갈 list 입니다.
private ArrayList<MyItem> listData = new ArrayList<>();
// Item의 클릭 상태를 저장할 array 객체
private SparseBooleanArray selectedItems = new SparseBooleanArray();
// 직전에 클릭됐던 Item의 position
private int prePosition = -1;
private MovieCase sel_type;
public RecyclerVierAdapter(MovieCase sel_type){
this.sel_type = sel_type;
}
@NonNull
@Override
public MyItemView onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view;
if(sel_type == MovieCase.LARGE){
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_movie_large, parent, false);
return new ViewHolderMovieLarge(view);
} else if(sel_type == MovieCase.SMALL){
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_movie_small, parent, false);
return new ViewHolderMovieSmall(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull MyItemView holder, final int position) {
if(holder instanceof ViewHolderMovieLarge){
ViewHolderMovieLarge viewHolderMovieLarge = (ViewHolderMovieLarge)holder;
viewHolderMovieLarge.onBind(listData.get(position));
} else if(holder instanceof ViewHolderMovieSmall){
ViewHolderMovieSmall viewHolderMovieSmall = (ViewHolderMovieSmall)holder;
viewHolderMovieSmall.onBind(listData.get(position),selectedItems.get(position));
viewHolderMovieSmall.setOnViewHolderItemClickListener(new OnViewHolderItemClickListener() {
@Override
public void onViewHolderItemClick() {
if (selectedItems.get(position)) {
// 펼쳐진 Item을 클릭 시
selectedItems.delete(position);
} else {
// 직전의 클릭됐던 Item의 클릭상태를 지움
selectedItems.delete(prePosition);
// 클릭한 Item의 position을 저장
selectedItems.put(position, true);
}
// 해당 포지션의 변화를 알림
if (prePosition != -1) notifyItemChanged(prePosition);
notifyItemChanged(position);
// 클릭된 position 저장
prePosition = position;
}
});
}
}
@Override
public int getItemCount() {
return listData.size();
}
void addItem(MyItem data) {
// 외부에서 item을 추가시킬 함수입니다.
listData.add(data);
}
}
MovieCase를 통해 큰 이미지로 보여줄 것인지, 작은 이미지로 보여줄것인지를 생성자를 통해서 대입을 해줍니다.
onCreateViewHolder에서 어떤 뷰로 보여줄 것인지 분기를 해줍니다.
Adapter 연결
이제 Activity에 Adapter를 연결해줍니다.
ActivityMovieLarge.java
package com.example.recyclerviewtest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class ActivityMovieLarge extends AppCompatActivity {
RecyclerVierAdapter adapter_large;
RecyclerView recyclerView;
Button btn_finish;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_large);
init();
getData();
}
private void init(){
recyclerView = findViewById(R.id.recyclerView);
btn_finish = findViewById(R.id.btn_finish);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
adapter_large = new RecyclerVierAdapter(MovieCase.LARGE);
recyclerView.setAdapter(adapter_large);
btn_finish.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private void getData(){
DataMovie data = new DataMovie(R.drawable.iron_man, "아이언맨");
adapter_large.addItem(data);
data = new DataMovie(R.drawable.spider_man, "스파이더맨");
adapter_large.addItem(data);
data = new DataMovie(R.drawable.black_panther, "블랙팬서");
adapter_large.addItem(data);
data = new DataMovie(R.drawable.doctor, "닥터스트레인지");
adapter_large.addItem(data);
data = new DataMovie(R.drawable.hulk, "헐크");
adapter_large.addItem(data);
data = new DataMovie(R.drawable.thor, "토르");
adapter_large.addItem(data);
}
}
MainActivity.java
package com.example.recyclerviewtest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
RecyclerVierAdapter adapter_small;
RecyclerView recyclerView;
Button btn_show_large;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
getData();
}
private void init(){
recyclerView = findViewById(R.id.recyclerView);
btn_show_large = findViewById(R.id.btn_show_large);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
adapter_small = new RecyclerVierAdapter(MovieCase.SMALL);
recyclerView.setAdapter(adapter_small);
btn_show_large.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getBaseContext(),ActivityMovieLarge.class);
startActivity(intent);
}
});
}
private void getData(){
DataMovie data = new DataMovie(R.drawable.iron_man, "아이언맨");
adapter_small.addItem(data);
data = new DataMovie(R.drawable.spider_man, "스파이더맨");
adapter_small.addItem(data);
data = new DataMovie(R.drawable.black_panther, "블랙팬서");
adapter_small.addItem(data);
data = new DataMovie(R.drawable.doctor, "닥터스트레인지");
adapter_small.addItem(data);
data = new DataMovie(R.drawable.hulk, "헐크");
adapter_small.addItem(data);
data = new DataMovie(R.drawable.thor, "토르");
adapter_small.addItem(data);
}
}
아답타를 생성할 때
RecyclerVierAdapter adapter = new RecyclerVierAdapter(MovieCase.xxx);
이 부분을 통해 어떻게 분기될 것인지에 대해 지정을 해줍니다.
레이아웃
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_show_large"
android:text="크게보기"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
activity_movie_large.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".ActivityMovieLarge">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_finish"
android:text="종료"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
item_movie_large.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_movie"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="250dp"/>
<TextView
android:paddingLeft="20dp"
android:layout_gravity="center"
android:gravity="center"
android:textSize="16dp"
android:id="@+id/tv_movie_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
item_movie_small.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linearlayout"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_movie"
android:scaleType="centerCrop"
android:layout_width="100dp"
android:layout_height="80dp"/>
<TextView
android:paddingLeft="20dp"
android:layout_gravity="center"
android:gravity="center"
android:textSize="16dp"
android:id="@+id/tv_movie_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<ImageView
android:id="@+id/iv_movie2"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="250dp"/>
</LinearLayout>
이처럼 Adapter를 모듈화를 하게 되면 하나의 Adapter를 가지고 여러개의 RecyclerView를 생성할 수 있습니다.
궁금하신점이나 잘못된점이 있다면 댓글로 남겨주시면 답변달아드리겠습니다~~
'Android > 유용한 기술' 카테고리의 다른 글
[Android/안드로이드]ViewPager2 사용하기 (5) | 2019.12.25 |
---|---|
[Android/안드로이드]RecyclerView 화면깜빡임 현상 방지 (0) | 2019.12.23 |
[Android/안드로이드] Expandable RecyclerView 접기/펼치기(아코디언) (20) | 2019.12.20 |
[Android/안드로이드] RecyclerView(리사이클러뷰) 뷰 재활용하기 (0) | 2019.12.19 |
[Android/안드로이드] 페이스북로그인 버튼 커스텀/Facebook Login Button Custom (0) | 2019.12.18 |