리스트 ui까지 만들어짐을 확인했으니, 이제 다시 디테일 페이지로 진입하는 부분을 건드릴 차례다.
이때, 클릭 이벤트 생성에 앞서, 디테일 페이지에서는 해당 포스트의 주인, 즉 다이어리를 쓴 본인일 경우 수정이 가능해야 할 것이며, 댓글 작성/삭제 역시 가능해야 할 것이다. 이를 위해서는
- 디테일 페이지 접속자가 포스트 작성인인가
- 댓글 작업을 하려는 포스트의 고유값이 무엇인가
위에 대한 최소한의 처리가 필요하다. 이를 위하여 Diary
모델에 val id: String
과 val account: String
두 가지 속성을 추가해주었다. account
는 로그인 한 계정정보와 비교할 것이고, id
는 포스트 등록시 UUID를 생성하여 부여, 댓글 등을 이와 매칭시켜 추후에 조회, 불러올 것이다.
이제 본격적으로 클릭 이벤트를 추상화 한 인터페이스를 만들어준 후, ListFragment
에서 이를 상속 받아 처리 후 DiaryListAdapter
에 인자로 넘겨줄 것이다.
우선, function이라는 이름의 패키지를 생성 후 OnClickInterface
라는 이름의 인터페이스를 만들어 onClick
함수를 추가해주었다.
OnClickInterface.kt
interface OnClickInterface {
fun onClick(_id: String)
}
ListFragment
에 오버라이딩 시킨다.
ListFragment.kt
class ListFragment : Fragment(), View.OnClickListener, OnClickInterface {
...
override fun onClick(_id: String) {
TODO("Not yet implemented")
}
}
이전에 만들어주었던 함수 toDetail()
이 있다. 기존에는 아래와 같이 생겼다.
private fun toDetail() {
val action = ListFragmentDirections.listToDetail()
Navigation.findNavController(requireActivity(), R.id.main_container)
.navigate(action)
}
이젠 다이어리의 id를 매개로 할 것이니, 인자로서 id를 추가해준다.
toDetail(_id: String)
그러면 오버라이드 한 onClick(_id: String)
의 TODO 부분은 toDetail(_id)
가 될 것이다.
어댑터에서 클릭 이벤트가 필요한 것이니, 자, 어댑터에 인자로 인터페이스를 추가해주자. (혹시 View.OnCLickListener
를 상속받았다면 지워주도록 하자. 대체할 것이다.)
bind()
함수 내부에 클릭리스너를 추가해준다. 나는 itemView
를 사용할 것이다.
itemView.setOnClickListener { clickInterface.onClick(item.id) }
자, 이제 ListFragment
에서 테스트를 위해 부여했던 어댑터를 기억하는지? 아래와 같이 생겼었다.
private fun initTestList() {
val testList = listOf(
Diary.TEST(), Diary.TEST(), Diary.TEST(), Diary.TEST(), Diary.TEST())
listRecycler.adapter = DiaryListAdapter(testList)
listRecycler.adapter?.notifyDataSetChanged()
}
에러가 뜬다. DiaryListAdapter
의 인자로 OnClickInterface
가 추가되었기 때문이다. ListFragment
가 해당 인터페이스를 상속받았으니 this
로 추가만 해주면, 이제 해당 함수를 활용할 수 있다.
또한 인자로 받은 인터페이스의 함수를 실행하는데, 해당 함수는 ListFragment
에서 선언한 함수 그 자체다. 이렇게 Fragment를 인자로 처리하지 않고 함수를 사용할 수 있게 되었다.
아직 toDetail(_id: String)
함수의 _id를 활용하지 않았다. Navigation 상에서 해당 인자를 argument로 보내주는 절차가 필요하다.
main_nav
로 돌아가서, DetailFragment
를 선택한 후 우측 창 Arguments
옆의 플러스 버튼을 눌러 인자를 추가하자. 이후 list_to_detail
액션을 클릭해보면 Argument가 생성된 것을 볼 수 있다.
자, 이제 FragmentList
의 toDetail(_id: String)
의 인자를 활용하면 아래와 같이 구성할 수 있다.
private fun toDetail(_id: String) {
val action = ListFragmentDirections.listToDetail(_id)
Navigation.findNavController(requireActivity(), R.id.main_container)
.navigate(action)
}
이제 보낼 준비는 끝났으니, 받기만 하면 된다. DetailFragment
에 private lateinit var postId: String
변수를 추가해준 후, onCreateView
에서 인플레이팅을 하기 전에 arguments 처리를 해준다.
만약 DetailFragmentArgs
(규칙은 해당Fragment+Args. 내가 지정한 이름이 아니다.) 가 뜨지 않는다면 빌드를 다시 해줘보자. 아마 제대로 뜰 것이다.
DetailFragment.kt
class DetailFragment : Fragment() {
...
private lateinit var postId: String
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val myArgs: DetailFragmentArgs by navArgs()
postId = myArgs.diaryId
return inflater.inflate(R.layout.detail_fragment, container, false)
}
}
좋아. 예상대로 받아졌는지 확인해보자. action 설정할 때 id의 디폴트 값을 "" 으로 지정해주었다. (받아올 id가 아직 없음) 이에 onViewCreated
에서 아래와 같이 토스트를 띄우도록 처리하였다.
if (postId.isEmpty()) {
Toast.makeText(requireContext(), "Id is empty", Toast.LENGTH_SHORT).show()
}
결과는 아래와 같이 성공적이다.
예상 가능하겠지만, 상술하였던 계정 정보로 포스트를 쓴 본인인지 아닌지를 체크할 것이라 했기에, 로그인 -> 리스트에도 계정 정보를 (필요하다면 암호화 하여) 넘길 것이며, 리스트 -> 디테일 에서도 해당 정보가 필요하게 될 것이다.
이는 기능적인 부분이니 일단은 차치하기로 하고, UI 구성을 계속하도록 하자.
'개발일기' 카테고리의 다른 글
8월 한달 토이 프로젝트를 해보자! -07 : submenu (0) | 2022.08.09 |
---|---|
8월 한달 토이 프로젝트를 해보자! -06 : AppBar (0) | 2022.08.09 |
8월 한달 토이 프로젝트를 해보자! -04 : List UI (0) | 2022.08.09 |
8월 한달 토이 프로젝트를 해보자! -03 : LogIn UI (0) | 2022.08.08 |
8월 한달 토이 프로젝트를 해보자! -02 : Navigation (0) | 2022.08.08 |