refactor: 캐릭터 탭 내부에서 사용하는 Adapter 코드를 ViewBinding 코드로 리팩토링

This commit is contained in:
2025-08-04 21:02:05 +09:00
parent b919691689
commit 33bdaa7dbd
6 changed files with 106 additions and 104 deletions

View File

@@ -4,6 +4,5 @@ data class Character(
val id: String, val id: String,
val name: String, val name: String,
val description: String, val description: String,
val imageUrl: String, val imageUrl: String
val ranking: Int? = null // 인기 캐릭터에서만 사용
) )

View File

@@ -1,14 +1,13 @@
package kr.co.vividnext.sodalive.chat.character package kr.co.vividnext.sodalive.chat.character
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R import com.bumptech.glide.Glide
import kr.co.vividnext.sodalive.chat.character.Character import kr.co.vividnext.sodalive.databinding.ItemCharacterBinding
class CharacterAdapter( class CharacterAdapter(
private var characters: List<Character> = emptyList(), private var characters: List<Character> = emptyList(),
@@ -16,46 +15,47 @@ class CharacterAdapter(
private val onCharacterClick: (Character) -> Unit = {} private val onCharacterClick: (Character) -> Unit = {}
) : RecyclerView.Adapter<CharacterAdapter.ViewHolder>() { ) : RecyclerView.Adapter<CharacterAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class ViewHolder(
val ivCharacter: ImageView = itemView.findViewById(R.id.iv_character) private val context: Context,
val tvCharacterName: TextView = itemView.findViewById(R.id.tv_character_name) private val binding: ItemCharacterBinding
val tvCharacterDescription: TextView = itemView.findViewById(R.id.tv_character_description) ) : RecyclerView.ViewHolder(binding.root) {
val llRanking: LinearLayout = itemView.findViewById(R.id.ll_ranking) @SuppressLint("SetTextI18n")
val tvRanking: TextView = itemView.findViewById(R.id.tv_ranking) fun bind(character: Character, index: Int) {
binding.tvCharacterName.text = character.name
binding.tvCharacterDescription.text = character.description
// 순위 표시 여부 결정
if (showRanking) {
binding.llRanking.visibility = View.VISIBLE
binding.tvRanking.text = (index + 1).toString()
} else {
binding.llRanking.visibility = View.GONE
}
Glide.with(context)
.load(character.imageUrl)
.into(binding.ivCharacter)
binding.root.setOnClickListener { onCharacterClick(character) }
}
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
val view = LayoutInflater.from(parent.context) parent.context,
.inflate(R.layout.item_character, parent, false) ItemCharacterBinding.inflate(
return ViewHolder(view) LayoutInflater.from(parent.context),
} parent,
false
)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val character = characters[position] holder.bind(characters[position], index = position)
holder.tvCharacterName.text = character.name
holder.tvCharacterDescription.text = character.description
// 순위 표시 여부 결정
if (showRanking && character.ranking != null) {
holder.llRanking.visibility = View.VISIBLE
holder.tvRanking.text = character.ranking.toString()
} else {
holder.llRanking.visibility = View.GONE
}
// TODO: 이미지 로딩 라이브러리 사용 (Glide, Picasso 등)
// Glide.with(holder.itemView.context)
// .load(character.imageUrl)
// .into(holder.ivCharacter)
holder.itemView.setOnClickListener {
onCharacterClick(character)
}
} }
override fun getItemCount(): Int = characters.size override fun getItemCount(): Int = characters.size
@SuppressLint("NotifyDataSetChanged")
fun updateCharacters(newCharacters: List<Character>) { fun updateCharacters(newCharacters: List<Character>) {
characters = newCharacters characters = newCharacters
notifyDataSetChanged() notifyDataSetChanged()

View File

@@ -72,7 +72,7 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
} }
// 전체보기 버튼 클릭 리스너 // 전체보기 버튼 클릭 리스너
binding.tvFamousCharacterAll.setOnClickListener { binding.tvPopularCharacterAll.setOnClickListener {
// 인기 캐릭터 전체보기 처리 // 인기 캐릭터 전체보기 처리
} }
@@ -106,11 +106,11 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
private fun loadPopularCharacters() { private fun loadPopularCharacters() {
// TODO: 서버에서 인기 캐릭터 데이터 로드 // TODO: 서버에서 인기 캐릭터 데이터 로드
val popularCharacters = listOf( val popularCharacters = listOf(
Character("1", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "", 1), Character("1", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
Character("2", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "", 2), Character("2", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
Character("3", "캐릭터 이름", "#태그#태그#태그", "", 3), Character("3", "캐릭터 이름", "#태그#태그#태그", ""),
Character("4", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "", 4), Character("4", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
Character("5", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "", 5) Character("5", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "")
) )
popularCharacterAdapter.updateCharacters(popularCharacters) popularCharacterAdapter.updateCharacters(popularCharacters)

View File

@@ -1,52 +1,58 @@
package kr.co.vividnext.sodalive.chat.character.curation package kr.co.vividnext.sodalive.chat.character.curation
import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.chat.character.CharacterAdapter
import kr.co.vividnext.sodalive.chat.character.Character import kr.co.vividnext.sodalive.chat.character.Character
import kr.co.vividnext.sodalive.chat.character.curation.CurationSection import kr.co.vividnext.sodalive.chat.character.CharacterAdapter
import kr.co.vividnext.sodalive.databinding.ItemCurationSectionBinding
class CurationSectionAdapter( class CurationSectionAdapter(
private var sections: List<CurationSection> = emptyList(), private var sections: List<CurationSection> = emptyList(),
private val onCharacterClick: (Character) -> Unit = {} private val onCharacterClick: (Character) -> Unit = {}
) : RecyclerView.Adapter<CurationSectionAdapter.ViewHolder>() { ) : RecyclerView.Adapter<CurationSectionAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class ViewHolder(
val tvSectionTitle: TextView = itemView.findViewById(R.id.tv_section_title) private val binding: ItemCurationSectionBinding
val rvCharacters: RecyclerView = itemView.findViewById(R.id.rv_characters) ) : RecyclerView.ViewHolder(binding.root) {
fun bind(section: CurationSection) {
binding.tvSectionTitle.text = section.title
// 캐릭터 리스트 설정
val characterAdapter = CharacterAdapter(
characters = section.characters,
showRanking = false,
onCharacterClick = onCharacterClick
)
binding.rvCharacters.apply {
layoutManager = LinearLayoutManager(
context,
LinearLayoutManager.HORIZONTAL,
false
)
adapter = characterAdapter
}
}
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
val view = LayoutInflater.from(parent.context) ItemCurationSectionBinding.inflate(
.inflate(R.layout.item_curation_section, parent, false) LayoutInflater.from(parent.context),
return ViewHolder(view) parent,
} false
)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val section = sections[position] holder.bind(sections[position])
holder.tvSectionTitle.text = section.title
// 캐릭터 리스트 설정
val characterAdapter = CharacterAdapter(
characters = section.characters,
showRanking = false,
onCharacterClick = onCharacterClick
)
holder.rvCharacters.apply {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
adapter = characterAdapter
}
} }
override fun getItemCount(): Int = sections.size override fun getItemCount(): Int = sections.size
@SuppressLint("NotifyDataSetChanged")
fun updateSections(newSections: List<CurationSection>) { fun updateSections(newSections: List<CurationSection>) {
sections = newSections sections = newSections
notifyDataSetChanged() notifyDataSetChanged()

View File

@@ -1,43 +1,43 @@
package kr.co.vividnext.sodalive.chat.character.recent package kr.co.vividnext.sodalive.chat.character.recent
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R import com.bumptech.glide.Glide
import kr.co.vividnext.sodalive.databinding.ItemRecentCharacterBinding
class RecentCharacterAdapter( class RecentCharacterAdapter(
private var characters: List<RecentCharacter> = emptyList(), private var characters: List<RecentCharacter> = emptyList(),
private val onCharacterClick: (RecentCharacter) -> Unit = {} private val onCharacterClick: (RecentCharacter) -> Unit = {}
) : RecyclerView.Adapter<RecentCharacterAdapter.ViewHolder>() { ) : RecyclerView.Adapter<RecentCharacterAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class ViewHolder(
val ivProfile: ImageView = itemView.findViewById(R.id.iv_profile) private val context: Context,
val tvName: TextView = itemView.findViewById(R.id.tv_name) private val binding: ItemRecentCharacterBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(character: RecentCharacter) {
binding.tvName.text = character.name
Glide.with(context)
.load(character.profileImageUrl)
.into(binding.ivProfile)
binding.root.setOnClickListener { onCharacterClick(character) }
}
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
val view = LayoutInflater.from(parent.context) parent.context,
.inflate(R.layout.item_recent_character, parent, false) ItemRecentCharacterBinding.inflate(
return ViewHolder(view) LayoutInflater.from(parent.context),
} parent,
false
)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val character = characters[position] holder.bind(characters[position])
holder.tvName.text = character.name
// TODO: 이미지 로딩 라이브러리 사용 (Glide, Picasso 등)
// Glide.with(holder.itemView.context)
// .load(character.profileImageUrl)
// .into(holder.ivProfile)
holder.itemView.setOnClickListener {
onCharacterClick(character)
}
} }
override fun getItemCount(): Int = characters.size override fun getItemCount(): Int = characters.size

View File

@@ -105,7 +105,7 @@
android:textSize="24sp" /> android:textSize="24sp" />
<TextView <TextView
android:id="@+id/tv_famous_character_all" android:id="@+id/tv_popular_character_all"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/pretendard_regular" android:fontFamily="@font/pretendard_regular"
@@ -121,8 +121,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingStart="24dp" /> android:paddingHorizontal="24dp" />
</LinearLayout> </LinearLayout>
<!-- 신규 캐릭터 섹션 --> <!-- 신규 캐릭터 섹션 -->
@@ -167,7 +166,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingStart="24dp" /> android:paddingHorizontal="24dp" />
</LinearLayout> </LinearLayout>
@@ -177,7 +176,5 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="24dp" /> android:layout_marginBottom="24dp" />
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>