Notice
Recent Posts
«   2025/02   »
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
Tags more
관리 메뉴

MyWorld

[Android : Java] RecyclerView 만들기 본문

Android 앱 개발 (Java)

[Android : Java] RecyclerView 만들기

vBest 2021. 6. 3. 11:55

리사이클러뷰 만드는 방법을 소개해보려 한다. 

다음은 내 프로젝트에서 사용한 예제이다. 참고로 보면 될 거다.

1. 리사이클러뷰 안의 item.xml 을 먼저 만든다.

item_product.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="wrap_content"
    android:elevation="8dp"
    android:paddingBottom="32dp"
    android:layout_marginHorizontal="10dp">

    <ImageView
        android:id="@+id/iv_product"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:background="@drawable/round"
        tools:src="@drawable/ecobag" />


    <ImageView
        android:id="@+id/iv_favorite"
        android:layout_width="34dp"
        android:layout_height="32dp"
        android:layout_margin="4dp"
        android:layout_marginStart="320dp"
        android:layout_marginTop="16dp"
        android:background="?android:attr/selectableItemBackgroundBorderless"
        android:src="@drawable/ic_baseline_favorite_border_24"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:layout_marginLeft="0dp"
        android:id="@+id/tv_name"
        style="@style/nanumExtraBoldTextViewStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/iv_product"
        tools:text="에코백"
        android:textSize="14dp"
        android:maxLines="1"
        android:ellipsize="end"
        android:layout_marginTop="8dp"
        android:textColor="#323232" />

    <TextView
        android:layout_marginLeft="0dp"
        android:id="@+id/tv_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_name"
        tools:text="2,0000원"
        style="@style/nanumExtraBoldTextViewStyle"
        android:textSize="11dp"
        android:layout_marginTop="5dp"
        android:textColor="@color/red"
        android:layout_marginBottom="9dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

리사이클러뷰의 아이템 xml

2. 위의 item을 리사이클러뷰에 달아준다.

<androidx.recyclerview.widget.RecyclerView
        android:paddingHorizontal="10dp"
        android:clipToPadding="true"
        tools:background="#000000"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/rv_product"
        tools:listitem="@layout/item_product"
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
        app:spanCount="2"/>

layoutManager를 Grid로 정하고 spanCount를 2로 정해서 2줄로 보이게 만들었다.

리사이클러뷰에 item 레이아웃을 적용

레이아웃 디자인이 완료되었다면 이제 코드를 작성해야 한다.

리사이클러뷰를 사용하기 위해선 Adapter가 필요하다.

3. Adapter를 만들어준다. 

어댑터를 만들기 위해 Java class를 만들어 준다.

extends 부분을 직접 작성하면 빨간 에러가 뜰 텐데 옵션키와 엔터키를 눌러 에러를 차근차근 고치면 어댑터의 틀이 자동으로 완성된다. 

 

(1) 아이템 뷰 연결

onCreateViewHolder에서 바인딩으로 1번에서 작성한 item.xml 을 연결해주었다.

return new ViewHolder(binding)을 작성 후 binding에서 빨간색 오류가 뜨는 것을 옵션 엔터로 고쳐준다.

 

ViewHolder 내부 클래스에서도 바인딩 1, 바인딩 2로 주석 처리한 부분을 작성해주어야 뷰 연결이 끝난다.

 

(2) 어댑터를 호출하는 액티비티나 프래그먼트의 데이터를 받아오기 위해 필요한 파라미터를 가지는 생성자를 만든다.

나는 ProductData의 데이터들을 ArrayList로 받아왔다. 뷰를 클릭 시 원하는 대로 동작하게 해주는 interface의 listener도 넘겨받아오도록 만들었다.

- 인터페이스 정의 필요 : 여기선 아이템 누를 때와 찜 누르는 걸로 만들었다 

 

(3) getItemCount()는 받아온 데이터 크기와 같아서 return datas.size()로 작성했다.

 

(4) onBindViewHolder에서 holder.bind(holder, datas.get(position)) 을 만들어주면 bind에 빨간 에러가 뜨는데 옵션 엔터로 ViewHolder 내부 클래스 안에 bind 메소드를 생성하면 된다.

 

bind안에서는 가져온 ProductData의 정보를 차례로 item.xml의 위젯에 연결해준다. 코드로 뷰에 정보를 넣는 부분인 것이다. 이런 식으로 같은 아이템 틀 안에 서로 다른 정보를 여러 개 넣어서 리사이클러뷰를 만들 수 있게 된다. 

 

어댑터 부분 설명은 끝났다.

다음으로 recylerview위젯을 갖는 액티비티나 프래그먼트에서 어떻게 어댑터와 연결되는지 설명하겠다.

 

ProductlistAdpater.java

public class ProductlistAdpater extends RecyclerView.Adapter<ProductlistAdpater.ViewHolder> { //어댑터

    Context mContext;
    ArrayList<ProductData> datas;
    ProductInterface listener;

    //인터페이스 
    public interface ProductInterface{
        void onItemClick(ProductData data);
        void onFavoriteClick(ProductData data, int position);
    }

	//사용할 생성자
    public ProductlistAdpater(Context mContext, ArrayList<ProductData> datas, ProductInterface listener) {
        this.mContext = mContext;
        this.datas = datas;
        this.listener = listener;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { //어댑터에서 바인딩 쓰는 법
        ItemProductBinding binding = ItemProductBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
        return new ViewHolder(binding); 
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.bind(holder ,datas.get(position));
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {

        ItemProductBinding binding; //바인딩1

        public ViewHolder(ItemProductBinding binding) {
            super(binding.getRoot());
            this.binding = binding; //바인딩2
        }

        public void bind(ViewHolder holder, final ProductData productData) {
        
            try{
                Glide.with(holder.itemView.getContext())
                        .load(productData.getUrls().get(0))
                        .error(R.mipmap.ic_launcher)
                        .thumbnail(Glide.with(holder.itemView.getContext()).load(R.drawable.loading_products)) //로딩 이미지에 gif 넣는 법
                        .apply(RequestOptions.bitmapTransform(new RoundedCorners(20))) //라운드를 줄 수 있다
                        .into(binding.ivProduct);
            }catch (Exception e){
                Glide.with(holder.itemView.getContext())
                        .load(R.drawable.swuri_2)
                        .error(R.mipmap.ic_launcher)
                        .placeholder(R.drawable.loading_example)//
                        .apply(RequestOptions.bitmapTransform(new RoundedCorners(20)))
                        .into(binding.ivProduct);
            }

            binding.tvName.setText(productData.getName());
            binding.tvPrice.setText(
                    new DecimalFormat("###,###,###,###")
                            .format(productData.getPrice()) + "원"
            );

            //리사이 클러뷰의 찜
            if (productData.isInWishlist()){
                 binding.ivFavorite.setImageResource(R.drawable.ic_baseline_favorite_24);
            }else{
                binding.ivFavorite.setImageResource(R.drawable.ic_baseline_favorite_border_24);
            }
            
            //리사이클러뷰의 찜 버튼을 클릭할 때
            binding.ivFavorite.setOnClickListener(v -> {
                listener.onFavoriteClick(productData, getAdapterPosition());
            });

            //리사이클러뷰의 아이템 뷰들을 각각 클릭할 때 나오는 창
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    listener.onItemClick(productData);
                }
            });

        }
    }
}

4. 리사이클러뷰와 어댑터 연결

리사이클러뷰를 사용할 액티비티나 프래그먼트에서 setRv() 메소드를 만들어준다.

리사이클러뷰의 id로 setRvLayoutManager로 레이아웃을 정해주고 

setAdapter로 3번의 어댑터를 연결해준다. 생성자로 인터페이스도 받아가서

리스너에 인터페이스를 구현해서 넘겨주어야 한다.

 	private void setRv() { //받아온 걸로 리사이클러뷰 셋
 
        // 찜과 아이템 클릭을 처리하기 위해 인터페이스를 구현 
        ProductlistAdpater.ProductInterface listener = new ProductlistAdpater.ProductInterface() {
            @Override
            public void onItemClick(ProductData data) {
                itemClick(data);
            }

            @Override
            public void onFavoriteClick(ProductData data, int position) {
                favoriteClick(data, position);
            }
        };

        binding.rvProduct.setLayoutManager(new GridLayoutManager(getContext(), 2));
        binding.rvProduct.setAdapter(new ProductlistAdpater(getContext(), datas, listener));
    }

    private void favoriteClick(ProductData data, int position) {
    	//찜 눌릴 때 DB 업데이트
    }

    private void itemClick(ProductData data) {
        //상품 상세로 이동 activity
		...
    }

 

이제 리사이클러뷰를 만들기 위한 작업이 모두 끝났다.

 

 

꽤 복잡해서 여러 번 연습해야 한다. 자바 코드보다 코틀린이 더 간단하다고 하니 이제 막 안드로이드 개발을 시작했다면 코틀린으로 배우는 걸 추천한다.