๋ชฝ๋กฑํ ๋ ธ๋๋ฐ, ์ค์ ๋ก ๋ง์ฝ์ ์ทจํ ์ฑ ๊ฐ์ฌ๋ฅผ ์ ์๋ค๊ณ ํ๋ค์.
์ ๊ฐ ์งํํ ๊ณผ์ ๋ 2๊ฐ์ง์ ๋๋ค. ์ฒซ ๋ฒ์งธ๋ ListAdapter์ Multi ViewType์ ์ด์ฉํ RecyclerView์ด๊ณ ,
๋ ๋ฒ์งธ๋ ์ธ๋ก/๊ฐ๋ก ๋ชจ๋์ ๋ฐ๋ฅธ ํ๋๊ทธ๋จผํธ ๋ณํ์ ๋๋ค.
package com.android.nbc_c_assignment1.challenge4_1
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.android.nbc_login.databinding.LayoutContactListFavoriteBinding
import com.android.nbc_login.databinding.LayoutContactListNormalBinding
enum class ViewType {
NORMAL, FAVORITE
}
class ContactListAdapter(private val viewModel: ContactListViewModel) : ListAdapter<ContactListData, RecyclerView.ViewHolder>(
ContractListDiffCallback()
) {
// fun initList() {
// val list = viewModel.getList()
// if (list != null) {
// val partition = list.partition { it.isFavorite }
// favoriteList = partition.first
// normalList = partition.second
// }
// }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val viewHolder: RecyclerView.ViewHolder
when(viewType) {
ViewType.NORMAL.ordinal -> {
val binding = LayoutContactListNormalBinding.inflate(LayoutInflater.from(parent.context), parent, false)
viewHolder = NormalViewHolder(binding)
}
else -> {
val binding = LayoutContactListFavoriteBinding.inflate(LayoutInflater.from(parent.context), parent, false)
viewHolder = FavoriteViewHolder(binding)
}
}
println("$viewHolder $viewType")
return viewHolder
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder) {
is NormalViewHolder -> holder.bind(viewModel, position, itemLongClick)
is FavoriteViewHolder -> holder.bind(viewModel, position, itemLongClick)
}
}
override fun getItemViewType(position: Int): Int {
println("h $position ${viewModel.getList()?.get(position)?.isFavorite}")
return if (viewModel.getList()?.get(position)?.isFavorite == true) ViewType.FAVORITE.ordinal else ViewType.NORMAL.ordinal
}
override fun getItemCount(): Int = viewModel.getList()!!.size
override fun getItemId(position: Int): Long = position.toLong()
interface ItemClick {
fun onClick()
}
var itemLongClick: ItemClick? = null
}
class ContactListAdapter(private val viewModel: ContactListViewModel) : ListAdapter<ContactListData, RecyclerView.ViewHolder>(
ContractListDiffCallback()
)
์ค๋์ ์ผ๋จ ์ฝ๋๋ฅผ ๊ฐ๋จํ๊ฒ ์ค๋ช ๋ง ํ๊ณ , ๋ด์ผ ๋ณต์ตํ๊ณ ์ ๋ฆฌํ ์ ์๋๋ก ํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ ListAdapter<๋ฐ์ดํฐ, ๋ทฐํ๋>(DiffCallback)๋ฅผ ์์๋ฐ์ต๋๋ค.
์ฌ๊ธฐ์ ๋ฐ์ดํฐ๋ ๋ฐ์ดํฐ ํด๋์ค๋ฅผ ๋ฃ์ด์ฃผ๋ฉด ๋๋๋ฐ, ๋ค์ํ ๋ฐ์ดํฐ ํด๋์ค๋ฅผ ์ธ ๋ sealed class๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์ข์ต๋๋ค.
override fun getItemViewType(position: Int): Int {
println("h $position ${viewModel.getList()?.get(position)?.isFavorite}")
return if (viewModel.getList()?.get(position)?.isFavorite == true) ViewType.FAVORITE.ordinal else ViewType.NORMAL.ordinal
}
๋จผ์ viewType์ ์ง์ ํด์ค์ผ ํฉ๋๋ค.
์ ๊ฐ์ ๊ฒฝ์ฐ๋ ์ฆ๊ฒจ์ฐพ๊ธฐ๋ฅผ ๊ตฌํํ๊ธฐ์, ๋ฐ์ดํฐ ํด๋์ค ์์ ๊ฐ๋ง ๊ฐ์ง๊ณ ๋ทฐํ์ ์ ๋๋ ์คฌ์ต๋๋ค.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val viewHolder: RecyclerView.ViewHolder
when(viewType) {
ViewType.NORMAL.ordinal -> {
val binding = LayoutContactListNormalBinding.inflate(LayoutInflater.from(parent.context), parent, false)
viewHolder = NormalViewHolder(binding)
}
else -> {
val binding = LayoutContactListFavoriteBinding.inflate(LayoutInflater.from(parent.context), parent, false)
viewHolder = FavoriteViewHolder(binding)
}
}
println("$viewHolder $viewType")
return viewHolder
}
์ดํ, ์ด ๋ทฐํ์ ์ ๋ฐ๋ผ ์ด๋ค ๋ทฐํ๋๋ฅผ ์ง์ ํด์ค์ง๋ฅผ ์ค์ ํด์ค๋๋ค.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder) {
is NormalViewHolder -> holder.bind(viewModel, position, itemLongClick)
is FavoriteViewHolder -> holder.bind(viewModel, position, itemLongClick)
}
}
๋ง์ง๋ง์ผ๋ก, ๋ทฐํ๋์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ค์ ๋ฐ์ธ๋ฉํด์ค๋๋ค.
์ผ๋จ ๊ตฌ์กฐ๋ ์ด๋ ๊ฒ ๋ผ ์๊ณ , ํ๋ํ๋ ์์ธํ ์ค๋ช ๋ค์ ๋ด์ผ ๊ฐ๋ฅํ๊ฒ ์ด์ฌํ ๋ณต์ตํด์ค๊ฒ ์ต๋๋ค...!
์๋๋ก์ด๋ ์คํ๋์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ธ๋ก ๋ชจ๋๋ฅผ ์ง์ํ๊ณ , ๊ฐ๋ก ๋ชจ๋๋ ์๋์ ์ผ๋ก ์ธ๋ก ๋ชจ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์ด์ค๋๋ค.
์ด๋, ๊ฐ๋ก ๋ชจ๋๋ฅผ ์ํ๋ ๋๋ก ๋ฐ๊ฟ ์ ์์ต๋๋ค.
layout์ ๊ฐ๋ก ๋ชจ๋๋ฅผ activity์ xml ๋ช ์ ๋์ผํ๊ฒ ๋ง๋ค๊ณ , ๋๋ ํ ๋ฆฌ ์ด๋ฆ์ layout-land์ผ๋ก ์ง์ ํด์ฃผ๋ฉด ๋ฉ๋๋ค.
ํ๋๊ทธ๋จผํธ์ ๊ฒฝ์ฐ, ๊ฐ๋ก, ์ธ๋ก์์ ์ด๋ค id๋ฅผ ์ธ์ง, ์ด๋ค ์ชฝ์ ์ด๋ค ํ๋๊ทธ๋จผํธ๋ฅผ ๋ถ์ผ์ง๋ ๋ฌ๋ผ์ง ์ ์๊ธฐ์,
ํ์ฌ ์ํ๊ฐ ๊ฐ๋ก์ธ์ง ์ธ๋ก์ธ์ง ํ์ ํ ์ ์๋ ์ฝ๋๊ฐ ํ์ํฉ๋๋ค.
์ด๋ ํ์ํ ๊ฒ Configuration์ ๋๋ค.
val config = Resources.getSystem().configuration
fun setFragment(config: Configuration, isClick: Boolean = false) {
if( config.orientation == Configuration.ORIENTATION_PORTRAIT ) {
if(!isClick) {
supportFragmentManager.commit {
replace(R.id.fragment, titleFragment)
setReorderingAllowed(true)
addToBackStack("title")
}
} else {
supportFragmentManager.commit {
replace(R.id.fragment, detailFragment)
setReorderingAllowed(true)
addToBackStack("detail")
}
}
} else if ( config.orientation == Configuration.ORIENTATION_LANDSCAPE ) {
supportFragmentManager.commit {
setReorderingAllowed(true)
replace(R.id.fragment_title, titleFragment)
replace(R.id.fragment_detail, detailFragment)
}
}
}
Configuration์ Resources.getSystem().configuration์ผ๋ก ๊ฐ์ ธ์ค๊ฑฐ๋, resources.configuration์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
์ฌ๊ธฐ์ orientation์ด๋ผ๋ ๋ ์์ ๊ฐ์ด ORIENTATION_PORTRAIT(์ธ๋ก)์ธ์ง LANDSCAPE(๊ฐ๋ก)์ธ์ง ์์๋ด์
๋น๊ตํด์ฃผ๋ฉด ๋๊ฒ ์ต๋๋ค.
๊ฐค๋ญ์ Z Flip์ ์จ๋ณด์ ๋ถ๋ค์ด ์์ผ์๋ฉด, ์นด๋ฉ๋ผ๋ฅผ ํค๊ณ , ๋ฐ์ฏค ์ ์ผ๋ฉด ์นด๋ฉ๋ผ ์ฑ์ด ๋ฌ๋ผ์ง๋ ๊ฑธ ์์ค ํ ๋ฐ์.
๊ทธ๋ ๋ค๋ ๊ฑด, ์ด๊ฑธ ์ง์ํ๋ค๋ ๋ป์ด ๋ ๊ฑฐ๋ผ๋ ์๊ฐ์ ํ๋ฒ ์ฐพ์๋ดค์ต๋๋ค.
๊ณต์ ๋ฌธ์ - Jetpack WindowManager
์ฌ์ค ์ด๊ฒ๋ ๊ตฌํํด๋ณด๊ณ ์ถ์๋๋ฐ, ์ด์ฉ๋ค๋ณด๋ ์๊ฐ์ด ์์ด์ ์๋ฎฌ๋ ์ดํฐ๋ฐ์ ๋ชป ์ฐพ์์ต๋๋ค.
๊ณต์ ๋ฌธ์ - ์๋ฎฌ๋ ์ดํฐ ์ถ์ ๋ ธํธ 30.0.26
์ฌ๊ธฐ์ ์ ํ config.ini๋ฅผ ๊ธฐ์กด์ ์๋ฎฌ๋ ์ดํฐ์ config.ini์ ์ถ๊ฐ๋ก ์ ์ด์ฃผ๋ฉด ๋ฌด๋ ค ์ ์ฌ Z Flip์ ๋ง๋ค ์ ์์ต๋๋ค.
์ด๊ฒ ๊ณผ์ ๋ ์๋์ง๋ง, ๋ญ๊ฐ ๋ง๋ค์ด๋ณด๊ณ ์ถ์ด์ ์ฐพ์๋ณด๊ฒ ๋์ต๋๋ค.
์๊ฐ์ด ๋จ์ผ๋ฉด ๊ผญ ํ์ฉํด๋ณด๊ณ ์ถ๋ค์.
๋ด์ผ์ ๋ ํฌ์งํ ๋ฆฌ ํจํด์ ๋ทฐ ๋ชจ๋ธ์ ์ ์ฉ์์ผ ๋ณด๊ณ ,
RecyclerView ListAdapter, ViewType์ ๋ณต์ตํ๊ณ ...
์ฝ๋ฃจํด์ ๊ณต๋ถํ๊ณ .....
ํด๋๋ธ ํ๋ฉด์ ๋ํ ๊ฒ๋ ๊ณต๋ถํด๋ณด๊ณ .........................
ํ ๊ฒ ๋ง๋ค์.
๋.