[Android] 동적 RecyclerView와 정적 RecyclerView 연결하기
[상황]
버튼을 나타낼 가로 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를 만드는 중 :(