본문 바로가기

[TIL][내일배움캠프]

[내일배움캠프][TIL] 24.02.14 (수) - 팀 프로젝트(심화) : 앱 완성도 높이기

1. 팀 프로젝트(심화)

 

어제는 가장 큰 과제 중 하나였던 네이버 백과사전 API를 연결하는 데에 성공하였다.

 

오늘은 이제 완성도를 끌어올리기 위해서 디테일적인 부분들을 많이 다듬었다.

 

 

네이버 태그 <b>, </b> 삭제

 

네이버에서는 패시지 정보에서 검색어와 일치하는 부분은 <b> 태그로 감싸는 특이점이 있다.

이 때문에 파일을 받아와서 그대로 실행하면 <b>, </b>가 그대로 출력되는 문제점이 생긴다.

변경 전

 

이런 식으로 말이다.

따라서 이 <b> 태그를 없애는 과정을 거쳐야 한다.

 

나는 Adapter에서 직접적으로 replace를 사용하여 고쳤다.

holder.tvtitle.text = items[position].title.replace("<b>", "").replace("</b>", "")
holder.tvdesc.text = items[position].description.replace("<b>", "").replace("</b>", "")

 

변경 후

음, 훨씬 깔끔해졌다.

 

 

백과사전 ViewPager2로 변환

 

그 다음에에는 백과사전 UI를 한 번 다듬어봤다.

 

현재 검색 결과 화면은 RecyclerView로 만들어서 넘길 때 한 페이지씩 넘어가는 게 아니라 스르륵- 넘어가서 보기 어색하다.

 

그렇다면 어떻게 ViewPager2로 바꿀까?

간단하다.

 

fragment_search_result.xml

<androidx.viewpager2.widget.ViewPager2
	android:id="@+id/search_dictionary"
	android:layout_width="0dp"
	android:layout_height="200dp"
	android:layout_margin="40dp"
	android:background="@drawable/ic_viewpager_background"
	android:orientation="horizontal"
	app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
	app:layout_constraintBottom_toTopOf="@id/linear_search"
	app:layout_constraintEnd_toEndOf="parent"
	app:layout_constraintStart_toStartOf="parent"
	app:layout_constraintTop_toTopOf="@id/layout_search_result" />

 

여기서 androidx 옆에 적혀 있던 RecyclerView를 Viewpager2로 바꿨다.

 

그리고 화살표도 작동시키기 위해서 다음의 코드를 추가시켜봤다,

 

SearchResultFragment.kt

    private fun initViewPagerButton() {
        with(binding) {
            imgArrowBack.setOnClickListener {
                val current = searchDictionary.currentItem

                searchDictionary.setCurrentItem(current - 1, true)
                if (current == 0) {
                    binding.searchDictionary.setCurrentItem(
                        dictionaryAdapter.itemCount - 1,
                        true
                    )
                }
            }

            imgArrowForword.setOnClickListener {
                val current = searchDictionary.currentItem

                searchDictionary.setCurrentItem(current + 1, true)
                if (current == dictionaryAdapter.itemCount - 1) {
                    binding.searchDictionary.setCurrentItem(0, true)
                }
            }
        }
    }

 

 

 

아주 깔끔하게 잘 넘어감을 볼 수 있다.

 

 

Bottom Navigaton 숨기기

 

다음으로는 검색 결과 화면에서 Bottom Navigation을 숨기는 기능을 구현해보고자 한다.

 

onCreateView에는

        //Bottom Navigation 숨기기
        val mainActivity = activity as MainActivity
        mainActivity.hideBottomNavigation(true)

 

이걸 쓰고,

 

onDestroyView에는

    override fun onDestroyView() {
        super.onDestroyView()

        val mainActivity = activity as MainActivity
        mainActivity.hideBottomNavigation(false)
    }

 

이걸 썼다.

 

참고로, hideBottomNavigation 함수는

    fun hideBottomNavigation (state:Boolean) {
        if(state) binding.navMain.visibility = View.GONE
        else binding.navMain.visibility= View.VISIBLE
    }

이런 식으로 true이면 안 보이도록, false이면 보이도록 설정해두었다.

 

 

 

 

 

영상 클릭 시 상세 화면으로 넘어가기

 

드디어 유튜브 API가 연결이 되어서, 이제는 영상을 클릭하면 상세 화면으로 넘어가는 걸 구현하였다.

 

SearchResultFragment.kt

    private fun initVideoRecyclerView(videos: List<YoutubeVideo>) {
        videoAdapter = SearchResultAdapter(videos)
        binding.reSearchVideo.adapter = videoAdapter

        videoAdapter.videoClick = object : SearchResultAdapter.VideoClick {
            override fun onClick(item: YoutubeVideo, position: Int) {
                val detailFragment = VideoDetailFragment.newInstance(item)

                requireActivity().supportFragmentManager.beginTransaction().apply {
                    replace(R.id.main_frame, detailFragment)
                    setReorderingAllowed(true)
                    addToBackStack(null)
                }.commit()
            }
        }
    }

 

VideoDetailFragment.kt

   companion object {
        private const val ARG_VIDEO = "argVideo"

        fun newInstance(youtubeVideo: YoutubeVideo) =
            VideoDetailFragment().apply {
                arguments = Bundle().apply {
                    putParcelable(ARG_VIDEO, youtubeVideo)
                }
            }

    }
    private val videoData: YoutubeVideo
        get() = requireArguments().getParcelable<YoutubeVideo>(ARG_VIDEO) as YoutubeVideo
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentVideoDetailBinding.inflate(inflater, container, false)

        initVideo()

        return binding.root
    }


	private fun initVideo() {
        with(binding) {
            tvDetailTitle.text = videoData.title
            tvDateDetail.text = videoData.publishedAt
            Glide.with(this@VideoDetailFragment)
                .load(videoData.thumbnail)
                .into(imgDetailVideo)
        }
    }