Kwaang Tech

Contact App 본문

Dev/ToyProject

Contact App

콰앙 2023. 9. 13. 23:53

프로젝트를 시작하기 전에, 이렇게 먼저 약속을 정한 후에, 전체적인 테마를 잡기 위해 Color & Style을 지정 한 후, 대락적인 UIFigma에 그려 본 후 프로젝트를 진행했다.

 

역할분담

노션에 칸반보드를 이용하여 진행사항을 체크하면서 진행했습니다.

 

 

제가 맡은 역할은 <<<< 와 같습니다.

이번 프로젝트에서는 커스텀하는 방법을 연구해서,

거기에 집중하느라 제가 맡은기능과, 하고싶은 기능까지 하고,

팀원이 원하는 디자인을 만들어내는데 집중 한거 같습니다.

Splash Screen도 마지막에 수정 하였습니다.

 

 

 

 

 

 

ViewPager2와 TapLayout을 사용하여, contact 와 myPage Fragment 화면을 왔다 갔다 하게 만들었습니다.

xml로는 TabLayout 선택된 탭 디자인(탭을 눌렀을 때 버튼모양처럼 보이게 하는것)이 제 능력으로는 표현이 안되어서, 새로운 방법을 찾아 탭 레이아웃을 디자인했습니다.

 private fun setupTabs() {
        // Font 가져오기
        val typeface = ResourcesCompat.getFont(this, R.font.komi)

        // 탭 선택 리스너 설정
        binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
            // 클릭 되었을 때
            override fun onTabSelected(tab: TabLayout.Tab?) {
                val customView = tab?.customView
                val tabBinding = TabItemBinding.bind(customView!!)
                when (tab?.position) {
                    0 -> tabBinding.tabIcon.setImageResource(R.drawable.clicked_contact)
                    1 -> tabBinding.tabIcon.setImageResource(R.drawable.clicked_user)
                }
                tabBinding.tabTxt.typeface = Typeface.create(typeface, Typeface.BOLD)
                tabBinding.tabTxt.setTextColor(
                    ResourcesCompat.getColor(
                        resources,
                        R.color.white,
                        null
                    )
                )
            }

            // 클릭 안 되었을 때
            override fun onTabUnselected(tab: TabLayout.Tab?) {
                val customView = tab?.customView
                val tabBinding = TabItemBinding.bind(customView!!)
                when (tab?.position) {
                    0 -> tabBinding.tabIcon.setImageResource(R.drawable.unclicked_contact)

                    1 -> tabBinding.tabIcon.setImageResource(R.drawable.unclicked_user)
                }
                tabBinding.tabTxt.typeface = Typeface.create(typeface, Typeface.NORMAL)
                tabBinding.tabTxt.setTextColor(
                    ResourcesCompat.getColor(
                        resources,
                        R.color.black,
                        null
                    )
                )
            }

            override fun onTabReselected(tab: TabLayout.Tab?) {}
        })

기존의 Swipe는 ViewHolder로 아이템을 밀어주면서 스와이프가 되는 형식이다. 우리가 원하는 디자인은 아이템은 고정이 된 상태에서 아이템 자체에서 변화를 주고 싶었다.

오른쪽에서 왼쪽 스와이프는 뷰페이저에서 사용하고 있기에, 왼쪽에서 오른쪽으로 하는 방향만 전화걸기 기능을 추가 하여 주었다.

 

class ItemTouchHelperCallback(
    dragDirs: Int,
    swipeDirs: Int,
    private val onSwiped: (Int) -> Unit,
    private val isGridMode: Boolean
) : ItemTouchHelper.SimpleCallback(if (isGridMode) 0 else dragDirs, if (isGridMode) 0 else swipeDirs) {

    var onSwipeListener: ((Float, RecyclerView.ViewHolder) -> Unit)? = null
    var onSwipe: ((Float, Int) -> Unit)? = null
    override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean = false

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        onSwiped(viewHolder.adapterPosition)
    }

    // 스와이프 디자인
    override fun onChildDraw(
        c: Canvas,
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        dX: Float, dY: Float,
        actionState: Int,
        isCurrentlyActive: Boolean
    ) {
        val itemView = viewHolder.itemView
        val background = itemView.findViewById<View>(R.id.swipeBackground) ?: return

        // 그리드뷰 에선 스와이프 디자인을 그리지 않음

        val layoutParams = background.layoutParams

        // 스와이프 네모 뷰 그림
        layoutParams?.apply {
            width = if (dX > 0) {
                dX.toInt()
            } else {
                0
            }
            background.layoutParams = this
        }
    }
}
// ItemTouchHelper 추가
        val swipeDirection = if (isGridMode) 0 else ItemTouchHelper.RIGHT
        val touchHelperCallback = ItemTouchHelperCallback(
            0,
            if (isGridMode) 0 else ItemTouchHelper.RIGHT,
            { position ->
                callPhoneNumber(requireActivity(), contactItems[position].phoneNumber)
                contactAdapter.notifyItemChanged(position)
            },
            isGridMode
        ).apply {
            onSwipeListener = { dX, viewHolder ->
                swipeDx = dX
                swipePosition = viewHolder.adapterPosition
                binding.RVArea.invalidateItemDecorations()
            }
        }

아이템은 고정시킨채, 기존 아이템 뷰에다가, 새로운 view 위에다 올려서, 스와이프 한 x값 만큼 뷰를 그려주는 형식으로 만들어주었다. Canvas 방식으로 처음에 시도 하였으나, Canvas에서는 z값 조절이 되지 않아서, 스와이프 디자인이 아이템을 덮지 못하였다. Canvas가 z값 조절이 안된다는 걸 몰랐을때, Canvas로 그리는 방법을 시도 하느라 엄청난 시간을 투자를 했었다....

 


 

프로젝트 시작 전에 나름의 룰을 계획적으로 짜고 시작 했음에도 팀원이 짠 코드에 내 코드를 붙이는 작업이 까다로웠다. 아이디 값 하나도 구분하기 어려워서 처음엔 팀원이 한 코드를 쫓고 쫓아서 알아보는 과정이 길었다. 나름의 규칙을 정하고 갔지만, 너무 대충 지었다는 생각을 작업하면서 느꼈다.
혼자 열심히 공부하는 것도 중요하지만, 협업의 경험을 많이 쌓는것도 중요하다는 것을 다시 한번 느끼는 한주다.

 


Application Version

  • minSdk 28
  • targetSdk 33

기술스택

  • Language - kotlin
  • IDE - Android Studio

https://github.com/KyungHwa0/contact

반응형