Android App

recyclerView in Android Studio

YunSeong 2021. 8. 2. 13:15
728x90
반응형

 

RecyclerView

https://youtu.be/kNq9w1_nhL4

일단 recyclerView는 여러 정보들을 item으로 묶어서 각각 표시해주는 그런 것 같다. 예를 들어서 받은 이메일들이 위아래로 쭉 정렬돼있는 것 등을 구현할 때 사용되는 거 같다.

 

 

 

recyclerView를 사용하기 위해서 build.gradle (:app)에 dependencies {}에

implementation 'androidx.recyclerview:recyclerview:1.2.1' 을 추가해서 그 토대를 만들어줬다. 

 

1 메인 activity layout 만들기 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:scrollbarFadeDuration="0"
    android:scrollbarSize="5dp"
    android:scrollbarThumbVertical="@android:color/darker_gray"
    android:scrollbars="vertical">
</androidx.recyclerview.widget.RecyclerView>
 
<Button
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/btn_add"
    android:layout_weight="8"
    android:text="추가"/>
cs

recyclerview를 위한 위젯을 만들고 (1~10)

Button을 만들어서 recyclerview에 item들을 추가할 수 있게 했다. (12~17)

 

2 item layout 만들기 

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
<?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">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/iv_profile"
            android:src="@mipmap/ic_launcher" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:gravity="center_vertical">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="mandu"
                android:id="@+id/tv_name"/>
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="예에에ㅔ"
                android:id="@+id/tv_content"/>
        </LinearLayout>
    </LinearLayout>
</LinearLayout>
cs

그 결과로 밑의 사진과 같은 결과를 만들었다. 

 


 

3 MainData 즉 Data를 쉽게 저장하는 class 만들기

1
2
3
4
5
6
7
8
9
10
11
12
public MainData(int iv_profile, String tv_name, String tv_content) {
    this.iv_profile = iv_profile;
    this.tv_name = tv_name;
    this.tv_content = tv_content;
}
public int getIv_profile() {
    return iv_profile;
}
public void setIv_profile(int iv_profile) {
    this.iv_profile = iv_profile;
}
                ...
cs

1~5 이 class를 객체화할 때 세 가지의 정보를 parameter로 받아서 저장한다.

6~11에서 get.~~~, set~~~ 함수를 통해서 정보를 반환하거나 저장한다. 다른 정보에 대해서도 똑같은 함수를 만들었다. 

 

 


 

4 adapter 만들기

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
private ArrayList<MainData> arrayList;
 
public MainAdapter(ArrayList<MainData> arrayList) { // 이 객체를 생성할 때 arrayList를 받아오게한다. 
    this.arrayList = arrayList;
}
 
@NonNull
@org.jetbrains.annotations.NotNull
@Override // 아까만든 item layout을 이용해서 정보를 담을 ViewHolder을 만든다. 그 viewHolder은 CustomViewHolder이라는 이름으로 저 밑에서 정의한다. 
public MainAdapter.CustomViewHolder onCreateViewHolder(@NonNull @org.jetbrains.annotations.NotNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
 
    CustomViewHolder holder = new CustomViewHolder(view);
 
    return holder;
}
 
@Override  //holder 안의 데이터를 실질적으로 저장한다.
public void onBindViewHolder(@NonNull @org.jetbrains.annotations.NotNull MainAdapter.CustomViewHolder holder, int position) {
    holder.iv_profile.setImageResource(arrayList.get(position).getIv_profile()); //arrayList에서 받아온 정보를 holder에 저장한다.
    holder.tv_name.setText(arrayList.get(position).getTv_name());
    holder.tv_content.setText(arrayList.get(position).getTv_content());
 
    holder.itemView.setTag(position); 
    
    holder.itemView.setOnClickListener(new View.OnClickListener() { //터치를 했을 때 toast를 뜨게 만든다. 
        @Override
        public void onClick(View view) {
            String curName = holder.tv_name.getText().toString();
            Toast.makeText(view.getContext(), curName, Toast.LENGTH_SHORT).show();
        }
    });
 
    holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { //길게 눌렀을 때 밑에 구현 remove()함수를 실행시킨다. 
        @Override
        public boolean onLongClick(View view) {
 
            remove(holder.getAdapterPosition());
 
            return true;
        }
    });
}
 
@Override 
public int getItemCount() { // arrayList의 원소 갯수를 반환한다. 오류를 막기위해 arrayList가 null일 때는 0을 반환한다.
    return (null != arrayList ? arrayList.size() : 0);
}
 
public void remove(int position) { //position에 있는 원소를 제거한다. 오류 가능성이 높은 작업이기에 try catch문으로 방지한다. 
    try {
        arrayList.remove(position);
        notifyItemRemoved(position); //새로 고침
    } catch (IndexOutOfBoundsException ex) {
        ex.printStackTrace();
    }
}
 
public class CustomViewHolder extends RecyclerView.ViewHolder { //ViewHoldet을 정의한다. 
 
    protected ImageView iv_profile;
    protected TextView tv_name;
    protected TextView tv_content;
 
    public CustomViewHolder(@NonNull @NotNull View itemView) { // 이 class를 객체화된 View인 itemView를 parameter로 받고 그의 위젯들을 연결해준다. 
        super(itemView);
        this.iv_profile = (ImageView) itemView.findViewById(R.id.iv_profile);
        this.tv_name = (TextView) itemView.findViewById(R.id.tv_name);
        this.tv_content = (TextView) itemView.findViewById(R.id.tv_content);
    }
}
cs

이 class는 RecyclerView.Adapter<MainAdapter.CustomViewHolder>을 상속한다.   

adapter에 꼭 구현되어야 할 것은

먼저 onCreateViewHolder()을 이용해서 viewHolder을 만들어서 반환해야 한다. (7~16)

그 holder의 정의는 따로 class를 만들어서 할 수도 있다. holder은 LayoutInflater을 이용해서 layout xml파일을

View 객체로 만들어서 그 객체의 저장할 데이터들을 변수로 만들고 View객체의 위젯에 연결해줘야 한다. (59~71) 

그 후에는 onBindViewHolder()을 이용해서 holder에 정보를 저장한다던가 상호작용을 정의해준다거나 하는 것을 해야 한다. (18~43)

그리고 getItemCount() 함수를 정의해서 item의 수를 반환하게 해야 한다. (45~48)

arrayList()로 정보를 전달받고 저장하는 것이 필수는 아닌 것 같지만 편하기에 보통 그렇게 쓰는 것 같다. 그렇기에 

className()으로 생성자를 정의해서 parameter로 arrayList를 받아오는 것도 중요한 것 같다. (3~5)

 

그리고 부가적인 것들로는 remove() 함수 정도인 것 같다. 

 

 


 

 

5 MainActivity class 만들기

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
recyclerView = (RecyclerView)findViewById(R.id.rv); //만들어놓은 위젯이랑 연결
linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
 
arrayList = new ArrayList<>(); //배열 만들기 
 
mainAdapter = new MainAdapter(arrayList); //adapter 객체화
recyclerView.setAdapter(mainAdapter); //위젯에 adapter 설정
 
Button btn_add = (Button)findViewById(R.id.btn_add); //버튼 눌렀을 때 이벤트
btn_add.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        MainData mainData = new MainData(R.mipmap.ic_launcher, "mandu""예에에ㅔ"); //MainData의 형태로 정보를 저장
        arrayList.add(mainData); //배열에 정보 추가
        mainAdapter.notifyDataSetChanged(); //새로고침 (적용)     
    }
});
cs

2 앞에서 만들었던 recyclerView 위젯을 변수에 저장해줬다. 

3~4 그리고 각각의 item들을 어떤 식으로 나열할지 정하기 위해서 linearLayoutManager을 만들고 recyclerView에 추가해준다.  (defealt값이 vertical인 것이고 바꾸고 싶다면 linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL) 이런 식으로 바꾸면 된다.)

6~9 adapter을 만들기 위해서 배열을 만들고 아까 만든 adapter class를 객체화해서 변수에 저장해준다. 그리고 그것을 recyclerView에 추가해준다. 

11~19 버튼을 눌렀을 때 이벤트를 설정해줬다. 아까 만든 mainData class를 이용해서 정보를 저장해주고 그것을 배열에 넣어준다. 그 배열에 추가한 것을 적용하기 위해서 mainAdapter을 새로고침 해준다. 

 

 

 

 

그렇게 하면 밑의 사진과 같이 추가 버튼을 누르면 item들이 하나씩 늘어나고 item을 오래 누르면 그 item은 없어질 것이다. 그리고 저 item에 다른 정보를 넣고 싶다면 바로 위의 코드에서 MainData class를 객체화하는 부분에서 그 원하는 정보를 넣는다면 적용될 것이다. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
반응형