ANDROID/Android 개발 이슈 & 해결

[Android] 동적 RecyclerView와 정적 RecyclerView 연결하기

주 녕 2021. 3. 21. 15:56
반응형

[상황]

버튼을 나타낼 가로 RecyclerView(정적)메세지를 나타낼 세로 RecyclerView(동적)가 있음

== 버튼 RecyclerView에서 한 버튼을 누르면 해당 버튼이 가지고 있는 텍스트를 메세지 RecyclerView에서 나타냄

 

크롭한 화면 일부

 

화면.xml

  • recycler_chatting_chats : 메세지 RecyclerView (동적)
  • recycler_chatting_msg_btn : 버튼 RecyclerView (정적)

[새로 알게 된 것]

android:clipToPadding = "false" : 스크롤 영역은 유지한 채로 여백을 줄 수 있음

일반 padding 속성을 주면 RecyclerView가 보여지는 영역 자체가 줄어든다. 하지만 clipToPadding을 사용하면 스크롤 내부에 padding을 주는 것이기 때문에 스크롤을 끝까지 민 상태에서 여백을 주고 싶을 때 사용하는 속성이다. 좀 더 이해하기 쉽게 말하자면, 위의 크롭한 화면 일부에서 버튼 RecyclerView를 왼쪽으로 밀면 paddingLeft 속성에 따라 RecyclerView 내부 내용이 잘려서 보이는 것이 아니라 스크롤과 함께 밀려가는 것을 볼 수 있다.

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_chatting_chats"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:orientation="vertical"
    android:layout_marginLeft="30dp"
    android:layout_marginRight="30dp"
    app:layout_constraintTop_toBottomOf="@id/img_chatting_characters"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintBottom_toTopOf="@id/recycler_chatting_msg_btn"/>
    
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_chatting_msg_btn"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="16dp"
    android:paddingLeft="8dp"
    android:clipToPadding="false"
    android:orientation="horizontal"
    app:layout_constraintTop_toBottomOf="@id/recycler_chatting_chats"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"/>

 

버튼 item.xml

현재 오른쪽 margin값을 8dp로 넣었다.

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <Button
        android:id="@+id/btn_item_chatting_msg"
        android:layout_width="wrap_content"
        android:text="배고파요."
        android:textColor="@drawable/btn_text_blue_to_white"
        android:layout_marginRight="8dp"
        style="@style/BUTTON_SUB"
        android:stateListAnimator="@null"/>
</LinearLayout>

 

메세지 item.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="16dp"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/text_item_chatting_nickname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="익명의 고라니 : "
        android:textColor="@color/colorCourtNavy"
        android:textStyle="bold"
        android:textSize="15dp"/>
    <TextView
        android:id="@+id/text_item_chatting_chat"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="메세지입니다."
        android:textColor="@color/colorBlack"
        android:textSize="15dp"/>
</LinearLayout>

 

버튼 RecyclerView 어댑터.kt

버튼을 클릭했을 때의 액션은 채팅 화면 클래스에서 구현해준다. 따라서 메세지 버튼 클릭 인터페이스로 구현해둔다.

class ChattingMsgBtnAdapter(val context: Context, private val messages: ArrayList<String>)
: RecyclerView.Adapter<ChattingMsgBtnAdapter.MsgViewHolder>() {

    // 메세지 클릭 인터페이스
    interface MessageClickListener{
        fun onMessageClick(view: View, position: Int)
    }
    private lateinit var messageClick: MessageClickListener
    fun setMessageClickListener(msgClick: MessageClickListener) {
        this.messageClick = msgClick
    }

    // 메세지 RecyclerView 연결
    inner class MsgViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
        val messageBtn = itemView.findViewById<Button>(R.id.btn_item_chatting_msg)
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MsgViewHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.item_chatting_msg, parent, false)
        return MsgViewHolder(v)
    }
    override fun onBindViewHolder(holder: MsgViewHolder, position: Int) {
        holder.messageBtn.text = messages[position]
        holder.messageBtn.setOnClickListener {
            messageClick.onMessageClick(it, position)
        }
    }
    override fun getItemCount(): Int = messages.size
}

 

메세지 RecyclerView 어댑터.kt

이곳에서는 메세지를 띄우기만 하면 된다!

class ChattingChatAdpater(val chatList: ArrayList<Chat>): RecyclerView.Adapter<ChattingChatAdpater.ChatHolder>() {
    inner class ChatHolder(itemView: View): RecyclerView.ViewHolder(itemView){
        val nickname = itemView?.findViewById<TextView>(R.id.text_item_chatting_nickname)
        val chat = itemView?.findViewById<TextView>(R.id.text_item_chatting_chat)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.item_chatting_chat, parent, false)
        return ChatHolder(v)
    }
    override fun getItemCount(): Int = if(chatList == null) 0 else chatList.size
    override fun onBindViewHolder(holder: ChatHolder, position: Int) {
        holder.nickname.text = "멋쟁이 고라니 : "
        holder.chat.text = chatList[position].chatMessage
    }
}
//data class Chat(val nickname: String, val chatMessage: String)
data class Chat(val chatMessage: String)

 

채팅 화면 클래스

onMessageClick에서 버튼 RecyclerView 어댑터의 클릭 인터페이스의 메소드를 구현해준다.

버튼을 클릭하면 메세지 RecyclerView의 데이터가 추가되면서 데이터를 갱신해서 띄워주어야 한다. 따라서 버튼을 클릭하면 chatAdpater, 즉 메세지 RecyclerView의 어댑터를 notifyDatasetChanged()를 이용하여 갱신한다.

class ChattingActivity : AppCompatActivity() {

    private lateinit var binding: ActivityChattingBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_chatting)

        binding = ActivityChattingBinding.inflate(layoutInflater)
        setContentView(binding.root)

        //--채팅 RecyclerView-----------------------------------------------------------------------
        val chats = ArrayList<Chat>()
        val chatAdpater = ChattingChatAdpater(chats)
        binding.recyclerChattingChats.adapter = chatAdpater
        binding.recyclerChattingChats.layoutManager = LinearLayoutManager(this)


        //--메세지 RecyclerView----------------------------------------------------------------------
        // 보낼 메세지 String 리스트
        var messages: ArrayList<String> = arrayListOf(
            "안녕하세요~", "뭐 먹을까요?", "배고파요!", "식사합니다!", "빨리 고릅시다~", "시작해요!" )

        // 메세지 RecyclerView Adapter
        val msgAdapter = ChattingMsgBtnAdapter(applicationContext, messages)
        msgAdapter.setMessageClickListener(object: ChattingMsgBtnAdapter.MessageClickListener{
            override fun onMessageClick(view: View, position: Int) {
                Toast.makeText(applicationContext, messages[position], Toast.LENGTH_SHORT).show()
                chats.add(Chat(messages[position])) // 추후 닉네임 수정
                chatAdpater.notifyDataSetChanged()
                Log.d("채팅 크기", chats.size.toString())
            }
        })
        binding.recyclerChattingMsgBtn.adapter = msgAdapter
        binding.recyclerChattingMsgBtn.layoutManager = LinearLayoutManager(this).also{
            it.orientation = LinearLayoutManager.HORIZONTAL // 가로 RecyclerView
        }
        
    }
}

 

개발 중에 디자인이 바껴서 없어진 코드이지만 나중에 도움이 될까 싶어 남겨본다.

지금은 또 달라진 UI를 만드는 중 :(

반응형