Custom Adapter를 사용하여 RecyclerView를 구현하는 방법을 설명합니다.  


최초작성 2018. 7. 23

최종작성 2019. 8. 22




실행화면입니다.  데이터 추가 버튼을 눌러주면 아이템이 RecyclerView에 추가됩니다.




화면 크기보다 많은 데이터가 추가되면 오른쪽에 스크롤바를 항상 보여주도록 했습니다. 

관련 코드는  activity_main.xml에서 다음 두 줄 입니다. 


        android:scrollbarFadeDuration="0"
        android:scrollbarSize="5dp"






1. build.gradle (Module: app)

RecyclerView를 사용하려면  build.gradle에 androidx.recyclerview:recyclerview를 추가해야 합니다. 

추가 후 오른쪽 위에 보이는 Sync Now를 클릭해야 프로젝트에 반영 됩니다. 



dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}




2. activity_main.xml

레이아웃에 RecyclerView와 버튼을 추가했습니다.

버튼은 누를 때 마다 RecyclerView에 아이템이 추가되도록 하기 위해 사용됩니다.




<?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="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview_main_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintVertical_weight="9"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/button_main_insert"
        android:scrollbarFadeDuration="0"
        android:scrollbarSize="5dp"
        android:scrollbarThumbVertical="@android:color/darker_gray"
        android:scrollbars="vertical"/>

    <Button
        android:id="@+id/button_main_insert"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintVertical_weight="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/recyclerview_main_list"
        android:text="데이터 추가"/>

</androidx.constraintlayout.widget.ConstraintLayout>



3. item_list.xml

layout 폴더에 추가합니다. RecyclerView의 한 줄에 세 개의 컬럼을 보여주기 위해 사용됩니다.


 


<?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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/id_listitem"
        android:layout_width="0dp"
        app:layout_constraintHorizontal_weight="1"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/english_listitem"
        app:layout_constraintHorizontal_chainStyle="spread"
        android:padding="5dp"
        android:textAlignment="center"
        android:text="123"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/english_listitem"
        android:layout_width="0dp"
        app:layout_constraintHorizontal_weight="2"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="@id/id_listitem"
        app:layout_constraintRight_toLeftOf="@id/korean_listitem"
        android:padding="5dp"
        android:layout_margin="10dp"
        android:textAlignment="center"
        android:text="english"
        android:textStyle="bold"/>


    <TextView
        android:id="@+id/korean_listitem"
        android:layout_width="0dp"
        app:layout_constraintHorizontal_weight="2"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toRightOf="@id/english_listitem"
        android:padding="5dp"
        android:layout_margin="10dp"
        android:textAlignment="center"
        android:text="phone"
        android:textStyle="bold" />

</androidx.constraintlayout.widget.ConstraintLayout>




4. Dictionary.java

RecyclerView의 한 줄에 보여줄 데이터를 클래스로 선언합니다. item_list.xml에서 정의한 TextView 개수에 맞추어야 합니다. 




예제에서는 다음 3가지 데이터를 사용합니다. 


package com.tistory.webnautes.userecyclerview;

public class Dictionary {
   
    private String id;
    private String English;
    private String Korean;
}




Getter, Setter 메소드, 생성자 메소드를 생성하는 방법을 설명합니다.


변수 선언 아래쪽 줄에 생성된 코드가 입력되도록 해당 위치에서 마우스 우클릭하여 보이는 메뉴에서 Generate를 선택합니다.





바로 보이는 메뉴에서 Getter and Setter를 선택합니다.




Ctrl 키를 누른채 마우스 왼쪽 버튼으로 항목을 모두 선택합니다.




Getter, Setter 메소드가 추가되었습니다.


package com.tistory.webnautes.userecyclerview;

public class Dictionary {

    private String id;
    private String English;
    private String Korean;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getEnglish() {
        return English;
    }

    public void setEnglish(String english) {
        English = english;
    }

    public String getKorean() {
        return Korean;
    }

    public void setKorean(String korean) {
        Korean = korean;
    }
}




코드가 입력될 위치에서 마우스 우클릭하여 보이는 메뉴에서 Generate를 선택합니다. 그리고 바로 보이는 메뉴에서 Constructor를 선택합니다.





항목 3개를 모두 선택하고 OK버튼을 클릭합니다.





생성자가 추가되었습니다.


package com.tistory.webnautes.userecyclerview;

public class Dictionary {

    private String id;
    private String English;
    private String Korean;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getEnglish() {
        return English;
    }

    public void setEnglish(String english) {
        English = english;
    }

    public String getKorean() {
        return Korean;
    }

    public void setKorean(String korean) {
        Korean = korean;
    }

    public Dictionary(String id, String english, String korean) {
        this.id = id;
        English = english;
        Korean = korean;
    }
}




5. CustomAdapter.java

ArrayList에 있는 Dictionary 클래스 타입의 데이터를 RecyclerView에 보여주는 처리를 합니다. 


package com.tistory.webnautes.endlessloading;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;


public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> {

    private ArrayList<Dictionary> mList;

    public class CustomViewHolder extends RecyclerView.ViewHolder {
        protected TextView id;
        protected TextView english;
        protected TextView korean;


        public CustomViewHolder(View view) {
            super(view);
            this.id = (TextView) view.findViewById(R.id.id_listitem);
            this.english = (TextView) view.findViewById(R.id.english_listitem);
            this.korean = (TextView) view.findViewById(R.id.korean_listitem);
        }
    }


    public CustomAdapter(ArrayList<Dictionary> list) {
        this.mList = list;
    }



    @Override
    public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.item_list, viewGroup, false);

        CustomViewHolder viewHolder = new CustomViewHolder(view);

        return viewHolder;
    }



    @Override
    public void onBindViewHolder(@NonNull CustomViewHolder viewholder, int position) {

        viewholder.id.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25);
        viewholder.english.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25);
        viewholder.korean.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25);

        viewholder.id.setGravity(Gravity.CENTER);
        viewholder.english.setGravity(Gravity.CENTER);
        viewholder.korean.setGravity(Gravity.CENTER);



        viewholder.id.setText(mList.get(position).getId());
        viewholder.english.setText(mList.get(position).getEnglish());
        viewholder.korean.setText(mList.get(position).getKorean());
    }

    @Override
    public int getItemCount() {
        return (null != mList ? mList.size() : 0);
    }

}




6. MainActivity.java

package com.tistory.webnautes.endlessloading;


import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import java.util.ArrayList;


public class MainActivity extends AppCompatActivity {

    private ArrayList<Dictionary> mArrayList;
    private CustomAdapter mAdapter;
    private int count = -1;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);



        RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview_main_list);
        LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLinearLayoutManager);


        mArrayList = new ArrayList<>();

        mAdapter = new CustomAdapter( mArrayList);
        mRecyclerView.setAdapter(mAdapter);


        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
                mLinearLayoutManager.getOrientation());
        mRecyclerView.addItemDecoration(dividerItemDecoration);



        Button buttonInsert = (Button)findViewById(R.id.button_main_insert);
        buttonInsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                count++;

                Dictionary data = new Dictionary(count+"","Apple" + count, "사과" + count);

                //mArrayList.add(0, dict); //RecyclerView의 첫 줄에 삽입
                mArrayList.add(data); // RecyclerView의 마지막 줄에 삽입

                mAdapter.notifyDataSetChanged();             }
        });

    }

}






관련 포스트 


Android RecyclerView 아이템 클릭 이벤트 구현

https://webnautes.tistory.com/1300



Android RecyclerView에 데이터를 추가/편집/삭제하는 예제

https://webnautes.tistory.com/1222





포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

유튜브 구독하기

  1. hj 2018.10.26 14:37

    자세한 리뷰 감사합니다.

    정말 많은도움되었습니다.

  2. HAMZZI 2018.12.25 16:07

    도움 많이 받고 갑니다~ 감사합니다!

  3. 2019.04.05 16:18

    실습 예제 따라했습니다.
    똑같이 따라했는데, 데이터 추가 버튼누르면 여러개 데이터가 추가 되지않고,
    0 apple0 사과0
    만 화면에 추가되고 버튼 계속 눌러도 데이터 추가가 되지 않네요..ㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.04.05 16:35 신고

      입력하다가 문제가 발생한 듯합니다.
      로그캣에서 에러를 찾아보세요.

  4. Candykick 2019.08.08 23:34

    좋은 정보 감사합니다. 쉽게 따라할 수 있네요.

  5. 햄찌 2019.09.29 15:15

    좋은 정보 감사합니다.
    안드로이드 이제 막 시작했는데 덕분에 많은 도움되었습니다.

    다름이 아니라 궁금한게 있어서 그러는데 3.item_list.xml 로 파일명이 지정되어 있는데,
    5. CustomAdapter.java 부분에서는
    View view = LayoutInflater.from(viewGroup.getContext())
    .inflate(R.layout.list_item, viewGroup, false);
    로 R.layout.list_item로 지정되어 있었습니다.

    실행하려고 하니 CustomAdapter.java의 list_item부분이 빨간줄이 떠서 R.layout.list_item이름을 위에서 명명하신 item_list로 변경을 하니깐 잘 돌아갔었는데, 저 부분이 위에 작성하신대로 해도 되는건지 여쭤보려합니다. 감사합니다.

  6. ㅈㅇㅅ 2019.12.13 19:15

    안드로이드X 이전버젼의 자료도 구할 수 있나요?

  7. 닻별 2019.12.19 18:59

    리사이클러뷰... 여러번 따라해 봤는데...제일 설명을 잘 해 놓으신거 같아요... 너무 감사드려요^^
    나옵니다

  8. 지나가던 핵초보개발자 2019.12.20 15:55

    와 왠만하면 댓글 안다는데 너무너무 훌륭한 글입니다. 와 진심 최고!!!

  9. ㅈㅇㅅ 2019.12.20 17:52

    getItemcount() 메소드는 어떤 역할을 해주나요? "리사이클러뷰내에서 아이템의 개수를 반환한다." 라고 여러 블로그에서 보긴했는데 솔직히 잘 와닿지않습니다. 늘 도움이 되주셔서 감사합니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.20 19:51 신고

      실제로 데이터가 저장되는 ArrayList타입의 mList에 있는 아이템개수를 리턴합니다. 똑같은 설명이려나요^^;

  10. 123 2019.12.30 16:57

    좋은 자료 감사합니다.
    혹시 여기에 sharedredpreference를 사용하려면 어떤식으로 해야되는지 알수있을까요??
    두가지를 같이 하려니까 잘안되네요...
    참고로 이예제말고 나머지 두개 예제도 하나에 구현은해놨습니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.30 17:03 신고

      다른 액티비티로 넘어갈때 저장하고 돌아오면.값을.다시.불러온다고 생각하면 됩니다.

  11. 123 2019.12.30 17:07

    그러면 adapter에서 저장을해야되나요 메인액티비티에 저장을 해야되나요
    불러오는건 메인에 하면 될거같긴한데...

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.30 18:37 신고

      sharedredpreference는 액티비티간에 이동시 화면에 입력된값을 유지할때 사용됩니다. 어댑터는 화면에.보여지는 부분이 아니라서 상관없습니다

  12. 123 2019.12.30 19:01

    답변감사합니다. 배열을 shared로 저장하려고하는데 string이나 int값이 아니라 arraylist<data>라서 문제가 생깁니다. 혹시 좋은 방법있을까요? JASON사용하려고합니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.30 20:35 신고

      링크를 참고하세요

      https://codechacha.com/ko/sharedpref_arraylist/

    • 123 2019.12.31 18:18

      댓글감사합니다.
      gson사용해서 해봤는데 로드 저장 위치문제 때문이지 모르겠는데 이것저것 해봐도 계속 오류가 떠서 앱이 안켜지거나 데이터추가가안됩니다. 메인에넣어야되는지 어뎁터에 넣어야되는지도 모르겠네요...

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.31 20:06 신고

      아니면 sqlite에 저장하는 방법은 어떨까.싶네요

  13. 청주야자수 2020.02.19 23:35

    adater에서 customviewholder 와 ItemViewHolder 는 무슨차이가있는지요?

+ Recent posts