Created
April 30, 2019 18:38
-
-
Save neslaram/cce7010d670b4d1ba87ba097c1882164 to your computer and use it in GitHub Desktop.
This file contains hidden or 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.greenmountainenergy.gme.custom | |
| import android.content.res.Resources | |
| import android.graphics.Canvas | |
| import android.graphics.Paint | |
| import android.graphics.Rect | |
| import android.support.v7.widget.LinearLayoutManager | |
| import android.support.v7.widget.RecyclerView | |
| import android.view.View | |
| import android.view.animation.AccelerateDecelerateInterpolator | |
| class CirclePagerIndicatorDecoration : RecyclerView.ItemDecoration() { | |
| private val colorActive = 0xFF545455.toInt() | |
| private val colorInactive = 0x33000000 | |
| /** | |
| * Height of the space the indicator takes up at the bottom of the view. | |
| */ | |
| private val mIndicatorHeight = (DP * 32).toInt() | |
| /** | |
| * Indicator stroke width. | |
| */ | |
| private val mIndicatorStrokeWidth = DP * 4 | |
| /** | |
| * Indicator width. | |
| */ | |
| private val mIndicatorItemLength = DP * 4 | |
| /** | |
| * Padding between indicators. | |
| */ | |
| private val mIndicatorItemPadding = DP * 8 | |
| /** | |
| * Some more natural animation interpolation | |
| */ | |
| private val mInterpolator = AccelerateDecelerateInterpolator() | |
| private val mPaint = Paint() | |
| init { | |
| mPaint.apply { | |
| strokeWidth = mIndicatorStrokeWidth | |
| style = Paint.Style.STROKE | |
| isAntiAlias = true | |
| } | |
| } | |
| override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { | |
| super.onDrawOver(c, parent, state) | |
| val itemCount = parent.adapter?.itemCount ?: 0 | |
| // center horizontally, calculate width and subtract half from center | |
| val totalLength = mIndicatorItemLength * itemCount | |
| val paddingBetweenItems = Math.max(0, itemCount - 1) * mIndicatorItemPadding | |
| val indicatorTotalWidth = totalLength + paddingBetweenItems | |
| val indicatorStartX = (parent.width - indicatorTotalWidth) / 2f | |
| // center vertically in the allotted space | |
| val indicatorPosY = parent.height - mIndicatorHeight / 2f | |
| drawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount) | |
| // find active page (which should be highlighted) | |
| (parent.layoutManager as? LinearLayoutManager)?.let { layoutManager -> | |
| val activePosition = layoutManager.findFirstVisibleItemPosition() | |
| if (activePosition == RecyclerView.NO_POSITION) { | |
| return | |
| } | |
| // find offset of active page (if the user is scrolling) | |
| layoutManager.findViewByPosition(activePosition)?.let { activeChild -> | |
| 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) | |
| } | |
| } | |
| } | |
| private fun drawInactiveIndicators(c: Canvas, indicatorStartX: Float, indicatorPosY: Float, itemCount: Int) { | |
| mPaint.color = colorInactive | |
| // width of item indicator including padding | |
| val itemWidth = mIndicatorItemLength + mIndicatorItemPadding | |
| var start = indicatorStartX | |
| for (i in 0 until itemCount) { | |
| c.drawCircle(start, indicatorPosY, mIndicatorItemLength / 2f, mPaint) | |
| start += itemWidth | |
| } | |
| } | |
| private fun drawHighlights( | |
| c: Canvas, indicatorStartX: Float, indicatorPosY: Float, | |
| highlightPosition: Int, progress: Float | |
| ) { | |
| mPaint.color = colorActive | |
| // width of item indicator including padding | |
| val itemWidth = mIndicatorItemLength + mIndicatorItemPadding | |
| if (progress == 0f) { | |
| // no swipe, draw a normal indicator | |
| val highlightStart = indicatorStartX + itemWidth * highlightPosition | |
| c.drawCircle(highlightStart, indicatorPosY, mIndicatorItemLength / 2f, mPaint) | |
| } else { | |
| val highlightStart = indicatorStartX + itemWidth * highlightPosition | |
| // calculate partial highlight | |
| val partialLength = mIndicatorItemLength * progress + mIndicatorItemPadding * progress | |
| c.drawCircle(highlightStart + partialLength, indicatorPosY, mIndicatorItemLength / 2f, mPaint) | |
| } | |
| } | |
| override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { | |
| super.getItemOffsets(outRect, view, parent, state) | |
| outRect.bottom = mIndicatorHeight | |
| } | |
| 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
I set this
private val colorActive = 0xFF545455.toInt()
private val colorInactive = 0x33000000