Я делаю простое приложение, которое содержит список таймеров и позволяет пользователю прокручивать эти таймеры через ViewPager.Здесь действуют принципы Компонента архитектуры Android: ViewModel хранит состояние приложения, а Fragments / Activities просто обрабатывают взаимодействия с пользовательским интерфейсом.
В этом случае были созданы пользовательские ViewPager и FragmentStatePagerAdapter.Мой вопрос: Каков наилучший способ заставить ViewPager / адаптер реагировать на изменения в ViewModel?
Текущий код ниже работает нормально, но есть ли лучший способ сделать это?В настоящее время и ViewPager, и Adapter требуют ссылки на ViewModel, и это противоречит тому, что MVVM должен реализовать.
ViewPager
class VerticalTimerViewPager(context: Context, attributeSet: AttributeSet): ViewPager(context, attributeSet){
var homeViewModel: HomeViewModel?=null
init {
setPageTransformer(true, VerticalPageTransformer())
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
ev ?: return false
val intercepted = super.onInterceptTouchEvent(swapXYOnMotionEvent(ev))
swapXYOnMotionEvent(ev)
return intercepted
}
override fun onTouchEvent(ev: MotionEvent?): Boolean {
homeViewModel ?: throwNoViewModelException()
when(ev?.action){
MotionEvent.ACTION_DOWN -> homeViewModel?.onSwipeDown()
MotionEvent.ACTION_UP -> homeViewModel?.onSwipeUp()
}
return super.onTouchEvent(swapXYOnMotionEvent(ev ?: return false))
}
private fun swapXYOnMotionEvent(motionEvent: MotionEvent): MotionEvent{
with(motionEvent){
val newX = (y/height)*width
val newY = (x/width) * height
setLocation(newX, newY)
}
return motionEvent
}
private fun throwNoViewModelException():Boolean{
throw RuntimeException("${this.javaClass.simpleName}: HomeViewModel must be set by setting the variable homeViewModel")
}
}
FragmentStatePagerAdapter
class VerticalTimerViewPager(context: Context, attributeSet: AttributeSet): ViewPager(context, attributeSet){
var homeViewModel: HomeViewModel?=null
init {
setPageTransformer(true, VerticalPageTransformer())
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
ev ?: return false
val intercepted = super.onInterceptTouchEvent(swapXYOnMotionEvent(ev))
swapXYOnMotionEvent(ev)
return intercepted
}
override fun onTouchEvent(ev: MotionEvent?): Boolean {
homeViewModel ?: throwNoViewModelException()
when(ev?.action){
MotionEvent.ACTION_DOWN -> homeViewModel?.onSwipeDown()
MotionEvent.ACTION_UP -> homeViewModel?.onSwipeUp()
}
return super.onTouchEvent(swapXYOnMotionEvent(ev ?: return false))
}
private fun swapXYOnMotionEvent(motionEvent: MotionEvent): MotionEvent{
with(motionEvent){
val newX = (y/height)*width
val newY = (x/width) * height
setLocation(newX, newY)
}
return motionEvent
}
private fun throwNoViewModelException():Boolean{
throw RuntimeException("${this.javaClass.simpleName}: HomeViewModel must be set by setting the variable homeViewModel")
}
}
Метод экземпляра вызван в Activity onCreate ()
private fun setupPagerAdapter() {
val pagerAdapter = TimerSlidePagerAdapter(viewModel = viewModel, fragmentManager = supportFragmentManager)
with(pager){
adapter = pagerAdapter
homeViewModel = viewModel
}
}