일일 회고
우선 내가 맡아서 할 기능들은 얼추 된 것 같다. 이제 합쳐보면서 잘돌아가는 지 확인해보고 데이터 전달을 진행하면 될 것 같다.
내일 병원예약이 있어 빠르게 진행을 해보았다.
내일 갔다와서 팀원들과 코드를 합치는 시간을 가져보기로 하였다.
오늘의 키워드
- GitHub 이슈관리
- RecyclerView multi view type
- TabLayout 커스텀 아이콘
- TabLayout 동작 정의
- RecyclerView ItemTouchHelper
Github 이슈관리
매니저님이 주신 자료로 팀 협업 시 이슈관리를 진행하던 도중 pull request를 할 때 이슈가 자동으로 닫히지 않는 현상이 있었다.
검색을 해보니 합쳐질 base branch가 default branch가 아니면 이슈가 자동적으로 닫히지 않는다고 하였다.
그래서 우선 default branch를 dev branch로 바꾸고 pull request를 해보았는데 이슈가 자동으로 닫히는 것을 확인하였다.
일단 팀 회의 후 dev를 default branch로 두고 dev가 완성되면 추후에 다시 default branch를 main으로 바꾸어 작업하기로 결정했다.
''공식 문서 왈" -
When you merge a linked pull request into the default branch of a repository, its linked issue is automatically closed. For more information about the default branch, see "Changing the default branch."
Recylcler View Multi View Type
하나의 리사이클러뷰에 여러가지 뷰타입을 지정한다.
먼저, 데이터에 뷰타입을 구분할 변수를 추가한다.
@Parcelize
data class CallingObject (
val id: String,
@DrawableRes val imgId: Int,
val name: String,
val mobileNumber: String,
val email: String,
val snsAddress: String,
var mbti: String = "",
var nickName: String = "",
var blogAddress: String = "",
var isLiked: Boolean = false,
val type: Int /// 뷰타입
): Parcelable
그 후, 데이터에 구분할 뷰타입을 넣는다.
이제 리사이클러뷰 어댑터가 중요한데, 뷰 타입에 따라 뷰홀더가 달라지므로 뷰홀더를 뷰타입의 갯수에 맞게 선언해준다.
그리고 onCreateViewHolder()와 onBindViewHolder()에서도 뷰타입에 따른 분기 처리를 해준다.
그리고 마지막으로 getItemViewType 메서드를 오버라이드하여 아이템의 뷰타입을 지정해준다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when(viewType) {
ViewType.LEFT_POSITION -> {
ContactListLeftViewHolder(
ItemCallInfoBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
ViewType.RIGHT_POSITION -> {
ContactListRightViewHolder(
ItemCallInfoReversedBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
else -> throw RuntimeException("disable view type")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = list[position]
when(item.type) {
ViewType.LEFT_POSITION -> (holder as ContactListLeftViewHolder).bind(item)
ViewType.RIGHT_POSITION -> (holder as ContactListRightViewHolder).bind(item)
}
}
override fun getItemViewType(position: Int): Int {
return list[position].type
}
TabLayout 커스텀 아이콘
TabLayout에 기본적으로 들어가는 아이콘이 아닌 다른아이콘(크기 조절등)을 하려면 커스텀하게 아이콘을 넣어주어야한다.
val iconList = intArrayOf(R.drawable.icon_home, R.drawable.icon_book, R.drawable.icon_call)
for (i in iconList.indices) {
val view = layoutInflater.inflate(R.layout.tab_icon, null)
val tab = tabLayout.getTabAt(i)
view.findViewById<ImageView>(R.id.tab_icon_image_view)
.setBackgroundResource(iconList[i])
if (tab != null)
tab.customView = view
}
아이콘 리스트를 순회하면서 직접 view를 만들어 tab에 직접 아이콘에 넣는 방식이다.
TabLayout 동작 정의
우선, ViewPager로 화면이동을 구현하였지만, TabLayout을 직접 클릭하여 탭을 이동할 수 있을 것이다.
그 동작을 정의하지 않아 구현하였다.
TabLayout의 addOnTabSelectedListener를 구현하면 된다.
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
// 탭이 선택 되었을 때
override fun onTabSelected(tab: TabLayout.Tab?) {
when (tab?.position) {
0 -> {
viewPager.isVisible = true
viewPager.setCurrentItem(0, false)
}
1 -> viewPager.setCurrentItem(1, false)
2 -> viewPager.setCurrentItem(2, false)
}
}
// 탭이 선택되지 않은 상태로 변경 되었을 때
override fun onTabUnselected(tab: TabLayout.Tab?) = Unit
// 이미 선택된 탭이 다시 선택 되었을 때
override fun onTabReselected(tab: TabLayout.Tab?) {
when (tab?.position) {
0 -> {
viewPager.isVisible = true
viewPager.setCurrentItem(0, false)
}
}
}
})
각 오버라이드 메서드 내에서 tab에 대한 ID나 Position으로 동작을 정의 할 수 있다.
RecylcerView ItemTouchHelper
RecylclerView에서 각 아이템을 터치했을 때의 동작을 정의해 줄 수 있다 (ex) swipe)
먼저, ItemTouchHelper를 상속받는 클래스를 만든다.
여기서는 왼쪽으로 Swipe되는 helper를 만들었다.
onChildDraw에서 Swipe시 Item 뒤에 보일 뷰들을 직접 그려준다.
abstract class SwipeToEditCallback(private val context: Context) :
ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
private val editIcon = ContextCompat.getDrawable(context, R.drawable.icon_color_call)
private val intrinsicWidth = editIcon!!.intrinsicWidth
private val intrinsicHeight = editIcon!!.intrinsicHeight
private val clearPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onChildDraw(
c: Canvas,
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
val itemView = viewHolder.itemView
val itemHeight = itemView.bottom - itemView.top
val isCanceled = dX == 0f && !isCurrentlyActive
if (isCanceled) {
clearCanvas(
c,
itemView.left + dX,
itemView.top.toFloat(),
itemView.left.toFloat(),
itemView.bottom.toFloat()
)
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
return
}
// Calculate position of edit icon
val editIconTop = itemView.top + (itemHeight - intrinsicHeight) / 2
val editIconLeft = itemView.left + itemHeight - intrinsicWidth
val editIconRight = itemView.left + itemHeight
val editIconBottom = editIconTop + intrinsicHeight
// Draw the icon
editIcon!!.setBounds(editIconLeft, editIconTop, editIconRight, editIconBottom)
editIcon.draw(c)
}
private fun clearCanvas(c: Canvas?, left: Float, top: Float, right: Float, bottom: Float) {
c?.drawRect(left, top, right, bottom, clearPaint)
}
}
val callSwipeHandler = object : SwipeToEditCallback(requireActivity()) {
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val activity =
mainActivity.findViewById<ViewPager2>(R.id.view_pager)
val bundle = Bundle().apply {
putParcelable("model", mainAdapter.list[viewHolder.adapterPosition])
}
activity.setCurrentItem(2, true)
parentFragmentManager.setFragmentResult("callObject", bundle)
}
}
val callSwipeHelper = ItemTouchHelper(callSwipeHandler)
callSwipeHelper.attachToRecyclerView(mainRecyclerView)
구현한 Helper를 객체로 만들고 , attachToRecyclerView 메서드를 통해 RecyclerView에 붙인다.
'내일배움캠프 7기 > TIL' 카테고리의 다른 글
내일배움캠프 7기 Android TIL 39일차 (2023.09.07) (0) | 2023.09.07 |
---|---|
내일배움캠프 7기 Android TIL 38일차 (2023.09.06) (1) | 2023.09.06 |
내일배움캠프 7기 Android TIL 36일차 (2023.09.04) (0) | 2023.09.04 |
내일배움캠프 7기 Android TIL 35일차 (2023.09.01) (0) | 2023.09.01 |
내일배움캠프 7기 Android TIL 34일차 (2023.08.31) (0) | 2023.08.31 |