0️⃣ 왜?
사실 Fragment, TabLayout, RecyclerView는 뗄레야 뗄 수 없는 존재다. 정말 많은 앱에서 이러한 구조로 구현하고 있을테니 이 기회에 확실하게 복습하고 넘어가면 좋다. ViewPager도 함께 쓰면 좋겠지만 우선은 제외하고 설명하겠다. 다른 좋은 포스팅들도 많으니 꼭 함께 참고할 것.
1️⃣ MainActivity
Fragment와 TabLayout 같이 사용하는 핵심 부분! XML 파일은 생략하겠다.
class MainActivity : AppCompatActivity() {
private val binding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
private val fragmentManager: FragmentManager = supportFragmentManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
// 1번
setFragment(Fragment1())
// 2번
binding.tabLayout.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener{
override fun onTabSelected(tab: TabLayout.Tab?) {
when(tab!!.position){
0 -> setFragment(Fragment1())
1 -> setFragment(Fragment2())
}
}
override fun onTabUnselected(tab: TabLayout.Tab?) { }
override fun onTabReselected(tab: TabLayout.Tab?) { }
})
}
// 1-1번
private fun setFragment(fragment: Fragment){
fragmentManager.commit {
replace(R.id.frame_layout, fragment)
setReorderingAllowed(true)
addToBackStack("")
}
}
}
- onCreate 되는 시점에 setFragment함수에 처음 띄워줄 Fragment를 호출하면 된다. 이 작업을 먼저 하지 않으면 초기에 호출되는 Fragment가 없어 빈 화면이 나온다. 밑에서 탭을 눌러야 그제서야 화면이 세팅된다.
- setFragment 함수는 말 그대로 Fragment를 세팅해주는 함수다. replace 메소드가 핵심이다. fragment 위에 stack처럼 새로운 fragment를 쌓는 것이 아니라 replace 해주기 때문이다.
- 탭레이아웃의 addOnTabSelectedListener를 통해서 필요한 함수들을 override 해주면 된다. onTabSelected에서 매개변수로 받아오는 tab의 position은 tab의 inde값이기 때문에 when문에서 Fragment들을 세팅해주면 된다.
2️⃣ Fragment1
Fragment와 RecylcerView를 같이 사용하기 시작! 이번에도 XML 파일은 생략하겠다.
class SearchFragment : Fragment() {
private val binding: FragmentSearchBinding by lazy { FragmentSearchBinding.inflate(layoutInflater) }
// 1번
private lateinit var mainAdapter: MainAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let { }
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
return binding.root //제발 여기 신경 좀 쓰기...
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// 1-1번
mainAdapter = MainAdapter()
// 2번
binding.mainRecyclerView.apply {
layoutManager = GridLayoutManager(context, 2)
adapter = mainAdapter
}
}
companion object {
@JvmStatic
fun newInstance() =
SearchFragment().apply {
arguments = Bundle().apply { }
}
}
}
- mainAdadpter를 lateinit으로 선언해준다.
- onViwCreated 부분에서 꼭 mainAdapter 변수에 값을 할당해주어야 한다. lateinit으로 할당을 지연했기 때문이다.
- binding.mainRecylcerView의 layoutManager에 값을 할당해준다. 나같은 경우엔 GridLayoutManager를 사용했지만 일반적인 LinearLayoutManager를 사용해도 된다. 그리고 선언해둔 mainAdapter 또한 adapter에 할당해준다.
그리고 꼭 기억해둘 것! 나는 매번 onCreateView에서 return 값을 binding.root로 바꾸는 것을 까먹는다. 이걸 해주지 않으면 보여지는 화면 자체가 달라지니 꼭 하자.
3️⃣ MainAdapter
Fragment와 RecylcerView를 같이 사용하기 마무리! 역시 XML 파일은 생략하겠다.
class MainAdapter: RecyclerView.Adapter<MainAdapter.Holder>() {
interface ItemClick {
fun onClick(view: View, position: Int)
fun onLongClick(view: View, position: Int)
}
// 1번
inner class Holder(private val binding: MainRecylcerViewListBinding) : RecyclerView.ViewHolder(binding.root) {
val image = binding.ivItemImage
val title = binding.tvItemTitle
val date = binding.tvItemDate
}
// 2번
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding = MainRecylcerViewListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Holder(binding)
}
// 3번
override fun onBindViewHolder(holder: Holder, position: Int) {
with(holder){
// image.setImageResource()
title.text = "제목 $position"
date.text = "2024-08-05 20:00:00"
}
}
// 4번
override fun getItemCount(): Int {
// 리스트 총개수 반환
return 10
}
}
- Holder를 작성하는 부분이 가장 중요하다. xml로 작성해둔 UI 중 데이터를 바인딩 해야되는 값들을 변수로 선언하는 과정이다. UI만 재사용하는 것이지 데이터는 값이 꾸준히 바뀌어야하기 때문이다.
- onCreateViewHolder에서 inner class로 생성한 Holder에 binding 값을 넣어준다.
- onBindViewHolder는 실제로 변화하는 데이터값을 바인딩 해주는 핵심 부분이다! 다만 나는 UI가 정상적으로 출력되는 것을 눈으로 확인하고 싶어 고정값을 넣어뒀을 뿐이다. 나중에 직접 데이터를 바인딩하게 되면 이 곳에서 집중적으로 작업해주면 된다.
- 마지막 getItemCount에서 Int값을 리턴해주지 않으면 바인딩을 완료 했어도 데이터가 출력되지 않는다. 나는 간단하게 10개만 출력했다.
그럼 다음과 같은 결과값이 나온다.
나는 헤매느라고 정말 어렵게 했는데 막상 정리해놓고 보니 또 어렵지 않다. 까먹지 않고 다음에는 잘 하기...
(Button Color를 지정해줬는데 안 바뀐다... 내일 고쳐야 할 것.)
다음에는 실제로 데이터를 바인딩 하는 값을 포스팅하도록 하겠다!
'Android' 카테고리의 다른 글
Android에서 CustomDialog 만들기 (0) | 2024.08.27 |
---|---|
Android의 4대 구성요소 알아보기 (0) | 2024.08.14 |
Android에서 Lottie Animation 적용하기 (0) | 2024.07.04 |
Android에서 원형 ImageView 만들기 (2) | 2024.07.04 |
Android란? (0) | 2024.06.21 |