뷰페이저 안에 특정 리사이클러뷰가 있는 부분에 다른 탭으로 넘어가지 않도록 뷰페이저의 움직임의 비활성화가 필요했습니다.
해당 샘플 코드는 메인액티비티 안에서 리사이클러뷰를 프래그먼트에 한거지만
해서 한거지만
프래그먼트안에 프래그먼트는 Include로 표현 한 것은
ViewPager가 터치되면 해당 터치 이벤트의 x, y 좌표를 가져와서 이 좌표가 특정 RecyclerView의 영역 내에 있는지 확인하고 뷰페이저 기능을 비활성하고 터치가 끝나면 스와이프 기능을 다시 활성화 하는 걸로 해서 깃허브에 주석으로 처리해서 넣었지만
샘플에는 액티비티에 뷰페이저는 인터페이스를 설정하고 onScroll 메서드를 호출하는지 결정하고 리사이클러뷰가 스크롤 되는 동안 뷰페이저의 스와이프를 비활성화 합니다.
MainActivity.kt
class MainActivity : AppCompatActivity(), OnRecyclerViewScrollListener {
private lateinit var binding: ActivityMainBinding
private var viewPagerFragment: ViewPagerFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.viewPager.adapter = ViewPagerAdapter(supportFragmentManager)
binding.tabLayout.setupWithViewPager(binding.viewPager)
binding.tabLayout.getTabAt(0)?.text = "뷰페이저"
binding.tabLayout.getTabAt(1)?.text = "프래그먼트"
}
override fun onScroll(isScrolling: Boolean) {
binding.viewPager.isSwipeEnabled = !isScrolling
}
fun disableSwipe() {
binding.viewPager.isSwipeEnabled = false
}
fun enableSwipe() {
binding.viewPager.isSwipeEnabled = true
}
}
onScroll
인터페이스의 콜백 메서드로, 리사이클러뷰가 스크롤될 때 호출되며, 리사이클러뷰가 스크롤되고 있으면 뷰페이저의 스와이프를 비활성화하고, 스크롤되고 있지 않으면 뷰페이저의 스와이프를 활성화 함
disableSwipe
, enableSwipe
이 두 메서드는 뷰페이저의 스와이프를 비활성화하거나 활성화하는 기능이며
메서드들은 리사이클러뷰가 스크롤될 때 뷰페이저의 스와이프를 제어하는 데 사용
ViewPagerFragment.kt
class ViewPagerFragment : BaseFragment<FragmentViewpagerBinding>(R.layout.fragment_viewpager) {
private var scrollListener: OnRecyclerViewScrollListener? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val top: Array<Int> = arrayOf(
R.drawable.first,
R.drawable.second,
R.drawable.qwe
)
val bottom: Array<Int> = arrayOf(
R.drawable.ujm,
R.drawable.fifth,
R.drawable.asd
)
// 상단
val topAdapter = TopAdapter(top)
binding.TopRecyclerViewId.adapter = topAdapter
binding.TopRecyclerViewId.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
// 하단
val bottomAdapter = BottomAdapter(bottom)
binding.BottomRecyclerViewId.adapter = bottomAdapter
binding.BottomRecyclerViewId.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
binding.TopRecyclerViewId.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
// RecyclerView가 스크롤 중일 때 ViewPager의 스와이프를 비활성
if (newState != RecyclerView.SCROLL_STATE_IDLE) {
(activity as? MainActivity)?.disableSwipe()
} else {
// RecyclerView가 스크롤되지 않는 경우 ViewPager의 스와이프를 활성화
(activity as? MainActivity)?.enableSwipe()
}
}
})
}
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is OnRecyclerViewScrollListener) {
scrollListener = context
}
}
override fun onDetach() {
super.onDetach()
scrollListener = null
}
}
scrollListener
addOnScrollListener
메서드 내에서 RecyclerView가 스크롤 중일 때 ViewPager의 스와이프를 비활성해서 스와이프를 방지하고 RecyclerView를 스크롤 되지 않으면 뷰페이저의 스와이프가 다시 활성화 합니다.
onAttach
프래그먼트가 액티비티에 연결될 때 호출되는 콜백 메서드이며 여기서 액티비티가 OnRecyclerViewScrollListener 인터페이스를 구현하고 있다면, scrollListener 변수에 액티비티의 참조를 저장
onDetach
프래그먼트가 액티비티에서 분리될 때 호출되는 콜백 메서드이며 여기서 scrollListener 변수를 null로 설정하여 참조를 제거
ViewPager.Adapter
class ViewPagerAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
private val fragments = listOf(
ViewPagerFragment(),
SecondFragment()
)
override fun getItem(position: Int): Fragment {
return fragments[position]
}
override fun getCount(): Int {
return fragments.size
}
}
깃허브 : https://github.com/GEUN-TAE-KIM/DisableRecycerView_ViewPager_Sample.git