봄이 와도... 코딩을 할 것이고... 여름이 와도... 안드로이드 스튜디오를 켤 거야...
오늘은 숙련 주차 강의, 과제, 챌린지반 과제를 진행하면서 배운 내용들을 복습 및 정리하면서 TIL을 작성하겠습니다.
OnBackPressedCallBack은 뒤로 가기 버튼에 대한 콜백을 다룰 수 있는 추상 클래스입니다.
해당 클래스는 handleOnBackPressed() 라는 추상 메소드를 갖고 있고, 프로그래머는 이를 구현하면 됩니다.
이후, Activity의 onBackPressedDispatcher.addCallback(this, callback) 으로 작성한 콜백을 넣어주면 됩니다.
만약, Fragment라면, requireActivity().getOnBackPressedDispatcher.addCallback(this, callback) 해주면 됩니다.
AlphaAnimation은 객체의 알파 레벨을 제어하는 애니메이션입니다.
여기서 알파 레벨이란, RGBA에서 Alpha로, 투명도를 뜻합니다. 그렇기에, 단순한 페이드 인-아웃 작업에 유용합니다.
val floatingFadeInAnimation = AlphaAnimation(0f, 1f).apply { duration = 500 }
위의 코드는 투명도가 0% -> 100%로 변하는 애니메이션을 만들어줍니다. duration으로 시간도 정할 수 있습니다.
이후, 이 애니메이션을 아래처럼 시작할 수 있습니다.
binding.btnFloating.isVisible = true
binding.btnFloating.startAnimation(floatingFadeInAnimation)
여러 앱에서 사용하는 내리면 점점 사라지는 툴바도 현재 스크롤 위치로 float 값을 계산하면, AlphaAnimation으로 구현할 수 있을 것 같습니다.
addOnScrollListener 는 리사이클러뷰의 스크롤 상태를 다룰 수 있는 OnScrollListener를 등록합니다.
이후, RecyclerView에 달린 리스너는 clearOnScrollListener로 지울 수 있습니다.
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
println("$dy ${recycler.computeVerticalScrollOffset()}")
if(recycler.computeVerticalScrollOffset() > 0 && !binding.btnFloating.isVisible) {
binding.btnFloating.isVisible = true
binding.btnFloating.startAnimation(floatingFadeInAnimation)
}
else if(recycler.computeVerticalScrollOffset() == 0) {
binding.btnFloating.isVisible = false
binding.btnFloating.startAnimation(floatingFadeOutAnimation)
}
}
})
먼저 addOnScrollListener의 인자로 RecyclerView.OnScrollListener를 상속하는 객체를 만들어,
추상 클래스의 추상 메소드인 onScrolled를 오버라이드하면 됩니다.
여기서 dx, dy는 각각 x, y의 변한 값이고, 이를 활용해 움직임을 파악할 수 있습니다.
또한 리사이클러뷰의 computeVerticalScrollOffset() 함수로는 스크롤의 현재 절대적인 높이를 구할 수도 있습니다.
OnScrollListener는 dx, dy의 변화를 확인하고 그에 따라 onScrolled를 진행하는 옵저버 패턴으로 보입니다.
프래그먼트는 액티비티에 종속적인 존재로, 액티비티 여러 개를 쓰는 대신,
프래그먼트 여러 개를 액티비티에 붙이는 식으로 구성할 수 있습니다.
val fragment = FirstFragment.newInstance("아 1")
setFragment(fragment)
private fun setFragment(frag: Fragment) {
supportFragmentManager.commit {
replace(R.id.fragment, frag)
setReorderingAllowed(true)
addToBackStack("")
}
}
위 코드처럼, setFragment 함수를 작성해줬습니다.
먼저 Activity의 fragmentManager인 supportFragmentManager를 불러와 commit { }으로
transaction을 열어줬고, 그 안에서 작업을 진행했습니다.
replace는 쌓인 프래그먼트를 전부 없애고 해당 프래그먼트로 교체해줍니다.
추가적으로, 여기에는 없지만, add는 프래그먼트를 쌓고, 맨 위 remove는 프래그먼트를 없앱니다.
이후, setReorderingAllowed(true)를 지정해 재정렬을 허용하고, addToBackStack("")으로 백 스택을 쌓아줍니다.
setReorderingAllowed(true)로 설정하면, 불필요한 프래그먼트가 생성돼도 그걸 생략하고 최적화된 루트로 프래그먼트를 진행합니다.
여기서 아직 설명하지 않은 addToBackStack은 백 스택에 프래그먼트를 쌓아둘 수 있습니다.
이 백 스택은 화면을 따로 띄우진 않고, pause된 상태의 프래그먼트를 뒤에 스택으로 쌓아둡니다.
popBackStack을 통해 이를 위에서부터 불러오거나, 이름을 지정해 그 부분을 pop할 수도 있습니다.
이는, 뒤로 가기를 눌렀을 때 유용하게 사용할 수 있습니다.
뒤로 가기를 누르게 되면, popBackStack의 효과를 내고, 백 스택에 있는 프래그먼트들을 pop하게 됩니다.
추가적으로 attach, detach와 show, hide도 있습니다.
먼저, add의 경우, onAttach로 시작해, onResume까지의 생명주기를 타고,
remove의 경우, onPause로 시작해, onDetach까지의 생명주기를 타는데,
attach의 경우는 onViewCreated부터 시작해, onResume까지 타고,
detach의 경우는 onPause부터 시작해, onDestroyView까지 타게 됩니다.
즉, 완전히 사라지는 것은 아니고 잠시 붙였다 뗐다 하는 식입니다.
show와 hide는 단순히 모양만 감추는 형태입니다.
제가 현재 알고 있는 데이터 전달 방법에 대해서만 적겠습니다.
프래그먼트를 생성하면, newInstance라는 static을 달고 있는 공동 객체가 존재합니다.
이 newInstance는 파라미터 하나를 받고,
해당 파라미터를 argument = Bundle()에 putString(ARG_PARAM1, 값) 한 것을 넣어 전달받을 수 있습니다.
이것은 데이터를 전달받을 때 사용하는 방식입니다.
데이터를 전달할 때도 이 newInstance를 사용하면 됩니다.
프래그먼트를 옮기기 전에 newInstance(값) 을 넣어주기만 하면, 쉽게 값을 전달할 수 있습니다.
프래그먼트에서 액티비티로 값을 전달하는 방식은, 이전에도 사용하던 interface를 구현하는 방식입니다.
그리고 마지막으로, 기본 프래그먼트의 순서는 newInstance(스태틱 타입이라) -> onCreate -> onCreateView -> onViewCreated 입니다.

프래그먼트의 생명주기가 약간 다르니까 헷갈리네요.
내일도 복습을 할 것 같습니다.
챌린지반에서 배운 ListAdapter와 DiffUtil을 위주로 공부하고,
챌린지반 과제를 마친 후에, 나머지 공부를 더 할 것 같습니다.
끝.