<정리> 챌린지반 과제2 - 1
지금까지 회원가입 페이지에서 계속 덮어쓰던 과제가 마무리되고 드디어 새로운 과제가 시작되었다.
이번 과제는 회사 채용과제의 느낌을 가지고 있는 과제였고 처음으로 할 건 레이아웃을 짜는 거였다.
이전까지 했던 것들을 복습하는 느낌이었기에 레이아웃 짜는 건 금방이었다.
여기서 정리해볼건 만든 레이아웃을 화면에 띄울 때 했던 코드들이다.
[깃허브]
https://github.com/heesoo-park/ChallengeRecruitAssignment/tree/master
1. 데이터 클래스 생성
가장 먼저 데이터 클래스를 만들었다.
Todo 앱을 만드는 것이기에 필요한 제목, 내용, 북마크 여부를 넣어서 만들었다.
data class Todo(
val title: String,
val description: String,
var isBookmarked: Boolean
)
2. 리사이클러뷰 어댑터 만들기
다음으로는 프래그먼트에 들어갈 리사이클러뷰 어댑터를 만들었다.
메인 액티비티 안에 뷰페이저 안에 프래그먼트 2개가 들어가는 형태의 앱이기 때문에 이거부터 시작했다.
두 프래그먼트가 동일한 형태를 가지지만 따로 어댑터를 만들었다.
이후의 유지보수를 위해서 그랬다.
class TodoAdapter(val dataList: ArrayList<Todo>):
RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
inner class TodoViewHolder(private val binding: TodoItemBinding): RecyclerView.ViewHolder(binding.root) {
val title = binding.tvTodoItemTitle
val description = binding.tvTodoItemDescription
var isBookmarked = binding.switchTodoItemBookmark
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
return TodoViewHolder(TodoItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun getItemCount(): Int {
return dataList.size
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
holder.title.text = dataList[position].title
holder.description.text = dataList[position].description
holder.isBookmarked.isChecked = dataList[position].isBookmarked
}
}
리사이클러뷰 아이템의 뷰바인딩을 뷰홀더로 받아서 데이터를 아이템에 세팅하도록 했다.
Todo 리스트와 Bookmark 리스트 어댑터는 동일하다.
3. 프래그먼트에 리사이클러뷰 연결
리사이클러뷰 아이템이 들어갈 데이터는 더미데이터를 이용해서 했다.
또한 뷰바인딩을 사용했다.
class TodoFragment : Fragment() {
private var _binding: FragmentTodoBinding? = null
private val binding get() = _binding
private val dummyData: ArrayList<Todo>
get() = arrayListOf(
Todo(
"title 0",
"description 0",
false
),
Todo(
"title 1",
"description 1",
false
),
Todo(
"title 2",
"description 2",
false
),
)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentTodoBinding.inflate(inflater, container, false)
return binding?.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val adapter = TodoAdapter(dummyData)
binding?.rvTodo?.adapter = adapter
binding?.rvTodo?.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL,false)
}
}
Bookmark 프래그먼트로 동일하다.
4. 뷰페이저 어댑터 생성
프래그먼트를 생성하고 자연스럽게 전환해주는 뷰페이저의 어댑터를 만들었다.
FragmentStateAdapter를 상속받고 getItemCount와 createFragment를 오버라이딩해줬다.
class ViewPagerAdapter(fragmentActivity: FragmentActivity): FragmentStateAdapter(fragmentActivity) {
override fun getItemCount(): Int {
return 2
}
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> TodoFragment()
else -> BookmarkFragment()
}
}
}
5. 뷰페이저와 탭레이아웃 연결
이제 메인 액티비티에서 뷰페이저에 어댑터를 연결하고 뷰페이저와 탭레이아웃을 연결하도록 했다.
탭 아이템의 이름은 레이아웃 xml에서 정해주지 않고 TabLayoutMediator를 사용해서 정해줬다.
val adapter = ViewPagerAdapter(this)
binding.viewPagerMain.adapter = adapter
TabLayoutMediator(binding.tabLayoutMain, binding.viewPagerMain) { tab, pos ->
when (pos) {
0 -> tab.text = "Todo"
1 -> tab.text = "Bookmark"
}
}.attach()
attach() 안 붙이면 화면에 탭 아이템 텍스트가 뜨지 않는다.
6. 플로팅 액션 버튼 설정
플로팅 액션 버튼이 Todo 화면에서만 뜨도록 OnPageChangeCallback 함수의 onPageSelected메서드를 오버라이딩했다.
binding.viewPagerMain.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
when (position) {
0 -> {
binding.fabMainAdd.isVisible = true
}
else -> {
binding.fabMainAdd.isVisible = false
}
}
}
})
7. 액티비티 상단 뒤로가기 버튼 설정
플로팅 액션 버튼을 눌러 이동할 수 있는 Todo 등록 액티비티에서 상단 툴바의 뒤로가기 버튼을 누를 때 현재 액티비티가 종료되도록 구현했다.
관련세팅도 해줬다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
setSupportActionBar(binding.tbRegisterTodo)
supportActionBar?.setDisplayShowTitleEnabled(false)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
finish()
}
}
return super.onOptionsItemSelected(item)
}