관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[안드로이드] 리사이클러뷰(RecyclerVeiw) xml 뷰 여러개 사용하는 법 (뷰홀더 2개 이상) 본문

안드로이드/자바 & Previous

[안드로이드] 리사이클러뷰(RecyclerVeiw) xml 뷰 여러개 사용하는 법 (뷰홀더 2개 이상)

막무가내막내 2019. 5. 28. 21:30
728x90

 

리사이클러뷰를 사용하다가 하나의 뷰가 아닌 다른 형태로 된 여러가지 뷰를 사용하고 싶을 때가 있다.

예를들어 카카오톡 같이 상대의 채팅은 왼쪽에 가고 사진과 이름이 보이게하고 나의 채팅은 이미지는 안보이고 채팅내용만 보이게하고 오른쪽 정렬이 되게끔 하고 싶은...?

 

그래서 오늘은 리사이클러뷰에서 여러 가지 뷰를 사용해서 만드는법에 대해 포스팅 해볼려고한다.

 

들어가기에 앞서 나는 뷰를 이렇게2개를 만들었다. ( 2는 오른쪽으로 정렬된 내가채팅칠 경우 띄워줄 화면이고 1은 상대의 채팅을 띄어줄 왼쪽으로 정렬된 화면이다.)

 

$ 참고로 이 글을 읽는 분들은 대부분 채팅과 같은 두 개 이상의 종류를 가진 리사이클러뷰가 필요하신 분들일텐데 디자인은 가볍게 보시고 뷰홀더 쪽 구현만 봐도 어떻게 구현해야할지 감은 오실거에요 :)

 

[ChatMessage1의 xml]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/chatmessage_item_linear"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="10dp"
    android:padding="3dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:gravity="center_vertical">

        <de.hdodenhof.circleimageview.CircleImageView xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/chatmessage_iv_profile"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_gravity="top"
            android:src="@drawable/com_facebook_profile_picture_blank_square"
            app:civ_border_color="#FF000000"
            app:civ_border_width="1dp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:gravity="center_vertical"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/chatmessage_tv_nickname"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="5dp"
                    android:text="닉네임"
                    android:textColor="@color/black"
                    android:textSize="15dp"
                    android:textStyle="bold" />


            </LinearLayout>

            <TextView
                android:id="@+id/chatmessage_tv_message"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/message_input"
                android:maxLength="150"
                android:maxLines="15"
                android:padding="10dp"
                android:text="메세지 내용"
                android:textColor="@color/black"
                android:textSize="15dp" />
            <TextView
                android:id="@+id/chatmessage_tv_date"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="2019-04-30 12:30" />
        </LinearLayout>
    </LinearLayout>


</LinearLayout>

 

 

[ChatMessage2]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/chatmessage_item_linear"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="10dp"
    android:padding="3dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:orientation="vertical">


            <TextView
                android:id="@+id/chatmessage2_tv_message"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="right"
                android:layout_marginRight="10dp"
                android:background="@drawable/message_input"
                android:maxLength="150"
                android:maxLines="15"
                android:padding="10dp"
                android:text="메세지 내용"
                android:textColor="@color/black"
                android:textSize="15dp" />

            <TextView
                android:id="@+id/chatmessage2_tv_date"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_gravity="right"
                android:text="2019-04-30 12:30" />
        </LinearLayout>
    </LinearLayout>


</LinearLayout>

 

 

 

 

 

이렇게 두개의 xml을 만들었고 어댑터 코드에 대해 살펴보려한다.

 

[먼저 예시를 채팅들은점을 기억하자. 내 아이디인 경우는 오른쪽뷰 , 아닌 경우는 왼쪽 뷰]

 

xml을 여러개 사용할려면 ,

우선 getItemViewType() 을 꼭 override해줘야하고 필요하다.

이것을 어떻게 구현하냐면은 getItemViewType()에서 비교해주고 뷰 종류를 2가지 사용할거면 경우에따라 두가지분류로 리턴해주면 된다.

따라서 여기서는 내 메세지인 경우는 0을 리턴하고 상대방거면 1을 리턴했다. 0은 왼쪽채팅, 1은 오른쪽 채팅역할을 할거다.

 @Override
    public int getItemViewType(int position) {
        ChatMessage chatMessage = items.get(position);
        Log.d("FFFFFF", "겟아이템뷰타입 : " + chatMessage.getuId());
        Log.d("FFFFFF", "겟아이템뷰타입 내 토큰 : " + mProfileUid);
        if (chatMessage.getuId().equals(mProfileUid)) { // 내 아이디인 경우 오른쪽뷰로 분기 (0)
            return 0;
        } else { // 왼쪽뷰 (1)
            return 1;
        }
    }

 

 

그 후 onCreateViewHolder() 에서 getItemViewType 에서 나눴던 것처럼 뷰타입번호에 리턴값에 따라 각각에 알맞은 뷰에 inflate해주면 된다. 난 0 ,1 로 리턴했었으니 다음과 같이 switch문을 분기하였다.

 @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        View view;
        switch (viewType) {
            case 0:
                Log.d("FFFF", "온크리트뷰홀더 :" + viewType);
                Log.d("FFFF", "온크리트뷰홀더 : 0인 경우");
                view = LayoutInflater.from(viewGroup.getContext())
                        .inflate(R.layout.item_chatmessage2, viewGroup, false);
                return new ChatMessageViewHolder2(view);
            case 1:
                Log.d("FFFF", "온크리트뷰홀더 :" + viewType);
                Log.d("FFFF", "온크리트뷰홀더 : 1인 경우");
                view = LayoutInflater.from(viewGroup.getContext())
                        .inflate(R.layout.item_chatmessage, viewGroup, false);
                return new ChatMessageViewHolder(view);
        }
        view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.item_chatmessage, viewGroup, false);
        return new ChatMessageViewHolder(view);
    }

 

 

그리고 두가지 종류의 xml 뷰를 사용할거라면 뷰홀더도 두가지를 갖고 각각 알맞게 코드를 작성해줘야한다.

//뷰들을 바인딩 해줍니다.
    public class ChatMessageViewHolder extends RecyclerView.ViewHolder {
        CircleImageView photoCircleImageView;
        TextView nickNameTextView;
        TextView dateTextView;
        TextView messageTextView;
        LinearLayout linearLayout;

        public ChatMessageViewHolder(@NonNull final View itemView) {
            super(itemView);
            photoCircleImageView = itemView.findViewById(R.id.chatmessage_iv_profile);
            nickNameTextView = itemView.findViewById(R.id.chatmessage_tv_nickname);
            dateTextView = itemView.findViewById(R.id.chatmessage_tv_date);
            messageTextView = itemView.findViewById(R.id.chatmessage_tv_message);
            linearLayout = itemView.findViewById(R.id.chatmessage_item_linear);
        }
    }

    //뷰들을 바인딩 해줍니다.
    public class ChatMessageViewHolder2 extends RecyclerView.ViewHolder {

        TextView messageTextView2;
        TextView dateTextView2;

        public ChatMessageViewHolder2(@NonNull final View itemView) {
            super(itemView);
            messageTextView2 = itemView.findViewById(R.id.chatmessage2_tv_message);
            dateTextView2 = itemView.findViewById(R.id.chatmessage2_tv_date);
        }
    }

 

 

그리고 마지막으로 onBindViewHolder에서 알맞게 값을 구분해서 맞는 홀더에 세팅해주면된다. 나같은 경우는 uid값으로 비교해서했는데 holder instanceof (내가만든 뷰홀더) 를 사용해서 비교해서 넣어줄 수도 있다. 후자를 추천한다. :) 

 @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int i) {
        final ChatMessage model = items.get(i);
        Log.d("FFFFF", model.getMessage());
        Log.d("FFFFF", model.getDates());
        if (model.getuId().equals(mProfileUid)) { //내 메세지인 경우
            ChatMessageViewHolder2 holder2 = (ChatMessageViewHolder2) holder;
            holder2.dateTextView2.setText(model.getDates());
            holder2.messageTextView2.setText(model.getMessage());

        } else {
            ChatMessageViewHolder holder1 = (ChatMessageViewHolder) holder;
            holder1.nickNameTextView.setText(model.getNickName());
            if (model.getImage().equals("basic") || model.getImage().equals("")) { //프로필사진이 없는경우
                holder1.photoCircleImageView.setImageResource(R.drawable.com_facebook_profile_picture_blank_square);
            } else {
                Glide.with(context).load(model.getImage()).into(holder1.photoCircleImageView);
            }
            holder1.dateTextView.setText(model.getDates());
            holder1.messageTextView.setText(model.getMessage());
        }
    }

 

이 밖에 RecyclerView.Adapter 클래스 제네릭 부분을 <RecyclerView.ViewHolder>로 바꾸고 좀 다른부분들이 있을텐데  전체코드로 첨부한다.

package com.mtjinse.myapplication.activity.adapters;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.google.firebase.auth.FirebaseAuth;
import com.mtjinse.myapplication.R;
import com.mtjinse.myapplication.activity.models.ChatMessage;

import java.util.ArrayList;

import de.hdodenhof.circleimageview.CircleImageView;

public class ChatMessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    Context context;
    ArrayList<ChatMessage> items = new ArrayList<ChatMessage>();
    private String mProfileUid = FirebaseAuth.getInstance().getCurrentUser().getUid(); //내 uid

    public ChatMessageAdapter(ArrayList<ChatMessage> items, Context context) {
        this.context = context;
        addItems(items);
    }


    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        View view;
        switch (viewType) {
            case 0:
                Log.d("FFFF", "온크리트뷰홀더 :" + viewType);
                Log.d("FFFF", "온크리트뷰홀더 : 0인 경우");
                view = LayoutInflater.from(viewGroup.getContext())
                        .inflate(R.layout.item_chatmessage2, viewGroup, false);
                return new ChatMessageViewHolder2(view);
            case 1:
                Log.d("FFFF", "온크리트뷰홀더 :" + viewType);
                Log.d("FFFF", "온크리트뷰홀더 : 1인 경우");
                view = LayoutInflater.from(viewGroup.getContext())
                        .inflate(R.layout.item_chatmessage, viewGroup, false);
                return new ChatMessageViewHolder(view);
        }
        view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.item_chatmessage, viewGroup, false);
        return new ChatMessageViewHolder(view);
    }


    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int i) {
        final ChatMessage model = items.get(i);
        Log.d("FFFFF", model.getMessage());
        Log.d("FFFFF", model.getDates());
        if (model.getuId().equals(mProfileUid)) { //내 메세지인 경우
            ChatMessageViewHolder2 holder2 = (ChatMessageViewHolder2) holder;
            holder2.dateTextView2.setText(model.getDates());
            holder2.messageTextView2.setText(model.getMessage());
        } else {
            ChatMessageViewHolder holder1 = (ChatMessageViewHolder) holder;
            holder1.nickNameTextView.setText(model.getNickName());
            if (model.getImage().equals("basic") || model.getImage().equals("")) { //프로필사진이 없는경우
                holder1.photoCircleImageView.setImageResource(R.drawable.com_facebook_profile_picture_blank_square);
            } else {
                Glide.with(context).load(model.getImage()).into(holder1.photoCircleImageView);
            }
            holder1.dateTextView.setText(model.getDates());
            holder1.messageTextView.setText(model.getMessage());
        }
    }

    @Override
    public int getItemViewType(int position) {
        ChatMessage chatMessage = items.get(position);
        Log.d("FFFFFF", "겟아이템뷰타입 : " + chatMessage.getuId());
        Log.d("FFFFFF", "겟아이템뷰타입 내 토큰 : " + mProfileUid);
        if (chatMessage.getuId().equals(mProfileUid)) {
            return 0;
        } else {
            return 1;
        }
    }

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


    //뷰들을 바인딩 해줍니다.
    public class ChatMessageViewHolder extends RecyclerView.ViewHolder {
        CircleImageView photoCircleImageView;
        TextView nickNameTextView;
        TextView dateTextView;
        TextView messageTextView;
        LinearLayout linearLayout;

        public ChatMessageViewHolder(@NonNull final View itemView) {
            super(itemView);
            photoCircleImageView = itemView.findViewById(R.id.chatmessage_iv_profile);
            nickNameTextView = itemView.findViewById(R.id.chatmessage_tv_nickname);
            dateTextView = itemView.findViewById(R.id.chatmessage_tv_date);
            messageTextView = itemView.findViewById(R.id.chatmessage_tv_message);
            linearLayout = itemView.findViewById(R.id.chatmessage_item_linear);
        }
    }

    //뷰들을 바인딩 해줍니다.
    public class ChatMessageViewHolder2 extends RecyclerView.ViewHolder {

        TextView messageTextView2;
        TextView dateTextView2;

        public ChatMessageViewHolder2(@NonNull final View itemView) {
            super(itemView);
            messageTextView2 = itemView.findViewById(R.id.chatmessage2_tv_message);
            dateTextView2 = itemView.findViewById(R.id.chatmessage2_tv_date);
        }
    }

    //아이템을 추가해주고싶을때 이거쓰면됨
    public void addItem(ChatMessage item) {
        items.add(item);
    }

    //한꺼번에 추가해주고싶을떄
    public void addItems(ArrayList<ChatMessage> items) {
        this.items = items;
    }

    //아이템 전부 삭제
    public void clear() {
        items.clear();
    }
}

 

이상 안드로이드 리사이클러뷰 여러개 뷰 사용하는 방법에 대한 포스팅을 마치겠습니다.

 

댓글과 공감은 큰 힘이됩니다. !

728x90
Comments