Closed mboudraa closed 2 years ago
I managed to write an extension but refreshDots
being protected and DotsIndicator
not being open I can't actually add this extension in my code without modifying the library
private fun DotsIndicator.attachToRecyclerView(recyclerView: RecyclerView, snapHelper: PagerSnapHelper) {
if (recyclerView.adapter == null) {
throw IllegalStateException("You have to set an adapter to the recyccler view before initializing the dots indicator !")
}
if (recyclerView.layoutManager == null) {
throw IllegalStateException("You have to set a layout manager to the recyccler view before initializing the dots indicator !")
}
val adapter = recyclerView.adapter!!
val layoutManager = recyclerView.layoutManager!!
recyclerView.adapter!!.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
refreshDots()
}
})
pager = object : BaseDotsIndicator.Pager {
var onScrollListener: RecyclerView.OnScrollListener? = null
override val isNotEmpty: Boolean
get() = adapter.itemCount > 0
override val currentItem: Int
get() = layoutManager.getPosition(snapHelper.findSnapView(layoutManager)!!)
override val isEmpty: Boolean
get() = adapter.itemCount == 0
override val count: Int
get() = adapter.itemCount
override fun setCurrentItem(item: Int, smoothScroll: Boolean) {
if (smoothScroll) {
recyclerView.smoothScrollToPosition(item)
} else {
recyclerView.scrollToPosition(item)
}
}
override fun removeOnPageChangeListener() {
onScrollListener?.let(recyclerView::removeOnScrollListener)
}
override fun addOnPageChangeListener(
onPageChangeListenerHelper: OnPageChangeListenerHelper
) {
onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val snapPosition = layoutManager.getPosition(snapHelper.findSnapView(layoutManager)!!)
onPageChangeListenerHelper.onPageScrolled(snapPosition, dx.toFloat())
}
}
recyclerView.addOnScrollListener(onScrollListener!!)
}
}
refreshDots()
}
Hello @mboudraa I started to implement your changes on the develop
branch (look RecyclerAttacher
class), but there is a lot of bugs using recycler with snap helper
I pause this for the moment, feel free to open a pull request on the project to make it work
onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val snapPosition = layoutManager.getPosition(snapHelper.findSnapView(layoutManager)!!)
onPageChangeListenerHelper.onPageScrolled(snapPosition, dx.toFloat())
}
}
this would only work if the items are full-page, they were completely broken for me
I broke a whole lot of things so this is not PR-able, but in a horizontal recycler view, I did this to make it work:
override fun addOnPageChangeListener(
onPageChangeListenerHelper: OnPageChangeListenerHelper
) {
onScrollListener = object : RecyclerView.OnScrollListener() {
private var currentDx = initialDx
private var currentPosition: Int? = null
override fun onScrolled(attachable: RecyclerView, dx: Int, dy: Int) {
this.currentDx += dx
val view = snapHelper.findSnapView(attachable.layoutManager)
if (view != null) {
val width = view.width
if (currentPosition == null && initialDx > width) {
setCurrentItem(max(this.currentDx / width, count), false) // reset
}
val newPosition = this.currentDx / width
this.currentPosition = newPosition
onPageChangeListenerHelper.onPageScrolled(
newPosition,
try {
(this.currentDx % width).toFloat() / width
} catch (e: ArithmeticException) {
0f
}
)
}
}
}
attachable.addOnScrollListener(onScrollListener!!)
}
}
}
i also tried. this code working fine for me(see the recyclerAttacher in repo and tried to make it work). but animation not working for worm indicator, as for this to work base class has to change which is internal in the library.
fun BaseDotsIndicator.attachToRecyclerView(recyclerView: RecyclerView, snapHelper: SnapHelper) {
RecyclerAttacher(snapHelper).setup(this, recyclerView)
}
class RecyclerAttacher(private val snapHelper: SnapHelper) {
fun setup(dotsIndicator: BaseDotsIndicator, recyclerView: RecyclerView) {
val adapter = recyclerView.adapter ?: throw IllegalStateException(
"Please set an adapter to the recyclerview before initializing the dots indicator"
)
adapter.registerAdapterDataObserver(OnChangedAdapterDataObserver(onChange = {
dotsIndicator.post { dotsIndicator.refreshDots() }
}))
val pager = RecyclerViewDotsPager(recyclerView, snapHelper)
dotsIndicator.pager = pager
dotsIndicator.refreshDots()
}
}
class OnChangedAdapterDataObserver(private val onChange: () -> Unit) :
RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
onChange()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
super.onItemRangeChanged(positionStart, itemCount)
onChange()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
super.onItemRangeChanged(positionStart, itemCount, payload)
onChange()
}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
super.onItemRangeInserted(positionStart, itemCount)
onChange()
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
super.onItemRangeRemoved(positionStart, itemCount)
onChange()
}
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
super.onItemRangeMoved(fromPosition, toPosition, itemCount)
onChange()
}
}
class RecyclerViewDotsPager(val recyclerView: RecyclerView, val snapHelper: SnapHelper) :
BaseDotsIndicator.Pager {
private var mScrollListener: RecyclerView.OnScrollListener? = null
override val count: Int
get() = recyclerView.adapter?.itemCount ?: 0
override val currentItem: Int
get() = snapHelper.findSnapView(recyclerView.layoutManager)?.let {
recyclerView.layoutManager?.getPosition(it)
} ?: 0
override val isEmpty: Boolean get() = count == 0
override val isNotEmpty: Boolean get() = !isEmpty
override fun addOnPageChangeListener(onPageChangeListenerHelper: OnPageChangeListenerHelper) {
mScrollListener = object : RecyclerView.OnScrollListener() {
var mScrolled: Boolean = false
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE && mScrolled) {
mScrolled = false
snapHelper.findSnapView(recyclerView.layoutManager)
?.let { recyclerView.layoutManager?.getPosition(it) }
?.let { snapPosition ->
onPageChangeListenerHelper.onPageScrolled(snapPosition, 0F)
}
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (dx != 0 || dy != 0) {
mScrolled = true
}
}
}
recyclerView.addOnScrollListener(mScrollListener!!)
}
override fun removeOnPageChangeListener() {
mScrollListener?.let(recyclerView::removeOnScrollListener)
}
override fun setCurrentItem(item: Int, smoothScroll: Boolean) {
if (smoothScroll) {
recyclerView.smoothScrollToPosition(item)
} else {
recyclerView.scrollToPosition(item)
}
}
}
VIewpaging can also be achieved very easily with a recyclerview and a PagerSnapHelper. Using a recyclerview allows for more customization as viewpager2 enforce the children to be the width and height of the viewpager