-
-
Save FaithDeveloper/d98b40681dacc2467e7f0d139691496e to your computer and use it in GitHub Desktop.
Line ViewPager2 Indicator Decoration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.test.recyclerpagersnap | |
/** | |
* reference : https://github.com/bleeding182/recyclerviewItemDecorations/blob/master/app/src/main/java/com/github/bleeding182/recyclerviewdecorations/viewpager/LinePagerIndicatorDecoration.java | |
*/ | |
import android.content.res.Resources | |
import android.graphics.* | |
import android.util.Log | |
import android.view.View | |
import android.view.animation.AccelerateDecelerateInterpolator | |
import android.view.animation.Interpolator | |
import androidx.recyclerview.widget.LinearLayoutManager | |
import androidx.recyclerview.widget.RecyclerView | |
import androidx.recyclerview.widget.RecyclerView.ItemDecoration | |
class LinePagerIndicatorDecoration : ItemDecoration() { | |
private val colorActive = -0x1 | |
private val colorInactive = Color.parseColor("#22000000") | |
// private val colorInactive = 0x1 | |
/** | |
* Height of the space the indicator takes up at the bottom of the view. | |
*/ | |
private val indicatorHeight = (DP * 32).toInt() | |
/** | |
* Indicator stroke width. | |
*/ | |
private val mIndicatorStrokeWidth = DP * 2 | |
/** | |
* Indicator width. | |
*/ | |
private val indicatorItemLength = DP * 100 | |
/** | |
* Padding between indicators. | |
*/ | |
private val indicatorItemPadding = DP * 0 | |
/** | |
* Padding bottom indicators. | |
*/ | |
private val indicatorItemBottomPadding = DP * 32 | |
/** | |
* Some more natural animation interpolation | |
*/ | |
private val mInterpolator: Interpolator = AccelerateDecelerateInterpolator() | |
private val mPaint = Paint() | |
init { | |
mPaint.strokeCap= Paint.Cap.ROUND | |
mPaint.strokeWidth= mIndicatorStrokeWidth | |
mPaint.style= Paint.Style.STROKE | |
mPaint.isAntiAlias= true | |
} | |
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { | |
super.onDrawOver(c, parent, state) | |
val itemCount = parent.adapter?.itemCount?: return | |
// center horizontally, calculate width and subtract half from center | |
val totalLength = indicatorItemLength * itemCount | |
val paddingBetweenItems = 0.coerceAtLeast(itemCount - 1) * indicatorItemPadding | |
val indicatorTotalWidth = totalLength + paddingBetweenItems | |
val indicatorStartX = (parent.width- indicatorTotalWidth) / 2f | |
// center vertically in the allotted space | |
val indicatorPosY = parent.height- indicatorItemBottomPadding | |
drawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount) | |
// find active page (which should be highlighted) | |
val layoutManager = parent.layoutManageras? LinearLayoutManager ?: return | |
val activePosition = layoutManager.findFirstVisibleItemPosition() | |
if (activePosition == RecyclerView.NO_POSITION) { | |
return | |
} | |
// find offset of active page (if the user is scrolling) | |
val activeChild = layoutManager.findViewByPosition(activePosition) ?: return | |
val left = activeChild.left | |
val width = activeChild.width | |
// on swipe the active item will be positioned from [-width, 0] | |
// interpolate offset for smooth animation | |
val progress = mInterpolator.getInterpolation(left * -1 / width.toFloat()) | |
drawHighlights(c, indicatorStartX, indicatorPosY, activePosition, progress, itemCount) | |
} | |
private fun drawLine(startPosX: Float, endPosX:Float, startPosY: Float, endPosY: Float){ | |
val path = Path() | |
path.moveTo(startPosX, startPosY) | |
} | |
private fun drawInactiveIndicators(c: Canvas, indicatorStartX: Float, indicatorPosY: Float, itemCount: Int) { | |
mPaint.color= colorInactive | |
val path = Path() | |
path.moveTo(indicatorStartX, indicatorPosY) | |
// width of item indicator including padding | |
val itemWidth = indicatorItemLength + indicatorItemPadding | |
// val itemWidth = indicatorItemLength | |
var start = indicatorStartX | |
for (i in 0untilitemCount) { | |
// draw the line for every item | |
path.lineTo(start + indicatorItemLength, indicatorPosY) | |
start += itemWidth | |
} | |
c.drawPath(path, mPaint) | |
} | |
private fun drawHighlights( | |
c: Canvas, indicatorStartX: Float, indicatorPosY: Float, | |
highlightPosition: Int, progress: Float, itemCount: Int | |
) { | |
mPaint.color= colorActive | |
val path = Path() | |
// // width of item indicator including padding | |
val itemWidth = indicatorItemLength + indicatorItemPadding | |
Log.d("@@@@", "progress $progress") | |
if (progress == 0f) { | |
// no swipe, draw a normal indicator | |
val highlightStart = indicatorStartX + itemWidth * highlightPosition | |
path.moveTo(highlightStart, indicatorPosY) | |
path.lineTo(highlightStart + indicatorItemLength, indicatorPosY) | |
c.drawPath(path, mPaint) | |
} else { | |
var highlightStart = indicatorStartX + itemWidth * highlightPosition | |
// calculate partial highlight | |
val partialLength = indicatorItemLength * progress | |
path.moveTo(highlightStart + partialLength, indicatorPosY) | |
path.lineTo(highlightStart + indicatorItemLength, indicatorPosY) | |
c.drawPath(path, mPaint) | |
// draw the highlight overlapping to the next item as well | |
if (highlightPosition < itemCount - 1) { | |
highlightStart += itemWidth | |
// c.drawLine( | |
// highlightStart, indicatorPosY, | |
// highlightStart + partialLength, indicatorPosY, mPaint | |
// ) | |
path.moveTo(highlightStart, indicatorPosY) | |
path.lineTo(highlightStart + partialLength, indicatorPosY) | |
c.drawPath(path, mPaint) | |
} | |
} | |
} | |
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { | |
super.getItemOffsets(outRect, view, parent, state) | |
outRect.bottom = indicatorHeight | |
} | |
companion object { | |
private val DP = Resources.getSystem().displayMetrics.density | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment