Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
sangcomz committed Sep 23, 2019
1 parent b8f0eca commit 004e7ed
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 57 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.recyclerview:recyclerview:1.1.0-beta04'
implementation 'androidx.viewpager2:viewpager2:1.0.0-beta04'
implementation "org.jetbrains.anko:anko:0.10.8"

testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package xyz.sangcomz.indicatordecoratorsample

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.PagerSnapHelper
import kotlinx.android.synthetic.main.activity_main.*
import xyz.sangcomz.indicatordecorator.IndicatorItemDecoration
import xyz.sangcomz.indicatordecorator.LinePagerIndicatorDecoration
import xyz.sangcomz.indicatordecorator.shape.DrawableIndicator

class MainActivity : AppCompatActivity() {

Expand All @@ -27,12 +28,22 @@ class MainActivity : AppCompatActivity() {
setContentView(R.layout.activity_main)

viewPager.adapter = adapter
viewPager.addItemDecoration(IndicatorItemDecoration())
viewPager.addItemDecoration(IndicatorItemDecoration().apply {
})
// viewPager.addItemDecoration(LinePagerIndicatorDecoration())

recyclerView.adapter = adapter
PagerSnapHelper().attachToRecyclerView(recyclerView)
// recyclerView.addItemDecoration(IndicatorItemDecoration())
recyclerView.addItemDecoration(LinePagerIndicatorDecoration())
recyclerView.addItemDecoration(IndicatorItemDecoration().apply {
indicatorShape = DrawableIndicator(
ContextCompat.getDrawable(
this@MainActivity,
R.drawable.ic_grade_red_24dp
)!!,
ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_grade_black_24dp)!!
)
})


}
}
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_grade_black_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_grade_red_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#EB3351"
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z" />
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -2,74 +2,58 @@ package xyz.sangcomz.indicatordecorator

import android.content.res.Resources
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.view.View

import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import xyz.sangcomz.indicatordecorator.shape.CircleIndicator
import xyz.sangcomz.indicatordecorator.shape.IndicatorShape
import kotlin.math.max

class IndicatorItemDecoration : RecyclerView.ItemDecoration() {

private val colorActive = Color.BLACK
private val colorInactive = Color.GRAY
private val radius = (DP * 3.5).toFloat()
private val offset = (DP * 8).toInt()

private var selectedPage = 0

/**
* Indicator width.
*/
private val mIndicatorItemLength = radius * 2
var topOffset = (DP * 4).toInt()
var bottomOffset = (DP * 4).toInt()
/**
* Padding between indicators.
*/
private val mIndicatorItemPadding = DP * 4
var indicatorItemPadding = DP * 8

private val mPaint = Paint()

init {
mPaint.strokeCap = Paint.Cap.ROUND
mPaint.isAntiAlias = true
}
var indicatorShape: IndicatorShape = CircleIndicator().apply { radius = DP * 4 }

override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(c, parent, state)

val adapter = parent.adapter ?: return
val layoutManager: LinearLayoutManager =
parent.layoutManager as? LinearLayoutManager ?: return

val itemCount = adapter.itemCount

val totalLength = mIndicatorItemLength * itemCount
val paddingBetweenItems = Math.max(0, itemCount - 1) * mIndicatorItemPadding
val totalLength = indicatorShape.getIndicatorWidth() * itemCount

val paddingBetweenItems = max(0, itemCount - 1) * indicatorItemPadding
val indicatorTotalWidth = totalLength + paddingBetweenItems
val indicatorStartX = (parent.width - indicatorTotalWidth) / 2f

val indicatorPosY = parent.height - radius
val indicatorPosY = parent.height - (indicatorShape.getIndicatorWidth() / 2) - bottomOffset

drawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount)

val layoutManager = parent.layoutManager as? LinearLayoutManager
val activePosition = layoutManager?.findFirstVisibleItemPosition()

val activePosition = layoutManager.findFirstVisibleItemPosition()
if (activePosition == RecyclerView.NO_POSITION) {
return
}

val view = layoutManager?.findViewByPosition(activePosition!!)!!
println("activeView width, left:::: ${view.width}, ${view.left}")
println("activeView width + left:::: ${view.width + view.left}")
val view = layoutManager.findViewByPosition(activePosition)!!

selectedPage = activePosition ?: 0 + if (view.width / 2 > view.width + view.left) 1 else 0

println("selectedPage :::: $selectedPage")

// if (layoutManager?.findLastVisibleItemPosition() != RecyclerView.NO_POSITION) {
// selectedPage = layoutManager?.findLastVisibleItemPosition() ?: 0
// }

drawSelectedIndicators(c, indicatorStartX, indicatorPosY)
drawSelectedIndicators(
c,
activePosition + if (view.width / 2f > view.width + view.left) 1 else 0,
indicatorStartX,
indicatorPosY
)
}

private fun drawInactiveIndicators(
Expand All @@ -78,22 +62,32 @@ class IndicatorItemDecoration : RecyclerView.ItemDecoration() {
indicatorPosY: Float,
itemCount: Int
) {
mPaint.color = colorInactive

val itemWidth = mIndicatorItemLength + mIndicatorItemPadding
val itemWidth = indicatorShape.getIndicatorWidth() + indicatorItemPadding

var start = indicatorStartX
for (i in 0 until itemCount) {
c.drawCircle(start + radius, indicatorPosY, radius, mPaint)
indicatorShape.inactiveIndicatorDraw(
c, start + indicatorShape.getIndicatorWidth() / 2,
indicatorPosY
)
start += itemWidth
}
}

private fun drawSelectedIndicators(c: Canvas, indicatorStartX: Float, indicatorPosY: Float) {
mPaint.color = colorActive
val itemWidth = mIndicatorItemLength + mIndicatorItemPadding
val start = indicatorStartX + itemWidth * selectedPage
c.drawCircle(start + radius, indicatorPosY, radius, mPaint)
private fun drawSelectedIndicators(
c: Canvas,
selectedPosition: Int,
indicatorStartX: Float,
indicatorPosY: Float
) {
val itemWidth = indicatorShape.getIndicatorWidth() + indicatorItemPadding
val start = indicatorStartX + itemWidth * selectedPosition

indicatorShape.activeIndicatorDraw(
c,
start + indicatorShape.getIndicatorWidth() / 2,
indicatorPosY
)
}

override fun getItemOffsets(
Expand All @@ -103,11 +97,10 @@ class IndicatorItemDecoration : RecyclerView.ItemDecoration() {
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.bottom = (offset + radius).toInt()
outRect.bottom = (topOffset + bottomOffset + indicatorShape.getIndicatorWidth()).toInt()
}

companion object {

private val DP = Resources.getSystem().displayMetrics.density
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class LinePagerIndicatorDecoration : RecyclerView.ItemDecoration() {

var start = indicatorStartX
for (i in 0 until itemCount) {
// draw the line for every item
// inactiveIndicatorDraw the line for every item
c.drawLine(start, indicatorPosY, start + mIndicatorItemLength, indicatorPosY, mPaint)
start += itemWidth
}
Expand All @@ -114,7 +114,7 @@ class LinePagerIndicatorDecoration : RecyclerView.ItemDecoration() {
val itemWidth = mIndicatorItemLength + mIndicatorItemPadding

if (progress == 0f) {
// no swipe, draw a normal indicator
// no swipe, inactiveIndicatorDraw a normal indicator
val highlightStart = indicatorStartX + itemWidth * highlightPosition
c.drawLine(
highlightStart, indicatorPosY,
Expand All @@ -125,13 +125,13 @@ class LinePagerIndicatorDecoration : RecyclerView.ItemDecoration() {
// calculate partial highlight
val partialLength = mIndicatorItemLength * progress

// draw the cut off highlight
// inactiveIndicatorDraw the cut off highlight
c.drawLine(
highlightStart + partialLength, indicatorPosY,
highlightStart + mIndicatorItemLength, indicatorPosY, mPaint
)

// draw the highlight overlapping to the next item as well
// inactiveIndicatorDraw the highlight overlapping to the next item as well
if (highlightPosition < itemCount - 1) {
highlightStart += itemWidth
c.drawLine(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package xyz.sangcomz.indicatordecorator.shape

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint

class CircleIndicator : IndicatorShape {
private val paint = Paint().apply { isAntiAlias = true }
var colorActive: Int = Color.YELLOW
var colorInactive: Int = Color.GRAY
var radius: Float = 1f

override var scaleFactor: Float = 1.2f

override fun getIndicatorWidth() = radius * 2

override fun inactiveIndicatorDraw(c: Canvas, x: Float, y: Float) {
paint.color = colorInactive
c.drawCircle(x, y, radius, paint)
}

override fun activeIndicatorDraw(c: Canvas, x: Float, y: Float) {
paint.color = colorActive
c.drawCircle(x, y, radius * scaleFactor, paint)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package xyz.sangcomz.indicatordecorator.shape

import android.graphics.Canvas
import android.graphics.drawable.Drawable


class DrawableIndicator(
drawableActive: Drawable,
drawableInActive: Drawable
) : IndicatorShape {
override var scaleFactor: Float = 1f
var width: Float = drawableActive.intrinsicWidth.toFloat()
var drawableActive = drawableActive
var drawableInActive = drawableInActive

override fun inactiveIndicatorDraw(c: Canvas, x: Float, y: Float) {
drawableInActive.setBounds(
x.toInt(),
(y - width / 2).toInt(),
(x + width).toInt(),
(y + width / 2).toInt()
)
drawableInActive.draw(c)
}

override fun activeIndicatorDraw(c: Canvas, x: Float, y: Float) {
val scale = ((width * scaleFactor) - width) / 2
drawableActive.setBounds(
(x - scale).toInt(),
(y - width / 2).toInt(),
(x + width + scale).toInt(),
(y + width / 2).toInt()
)
drawableActive.draw(c)
}

override fun getIndicatorWidth() = width
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.sangcomz.indicatordecorator.shape

import android.graphics.Canvas

interface IndicatorShape {
var scaleFactor: Float
fun inactiveIndicatorDraw(c: Canvas, x: Float, y: Float)
fun activeIndicatorDraw(c: Canvas, x: Float, y: Float)
fun getIndicatorWidth(): Float
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package xyz.sangcomz.indicatordecorator.shape

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint

class SquareIndicator : IndicatorShape {
private val paint = Paint().apply { isAntiAlias = true }
var colorActive: Int = Color.RED
var colorInactive: Int = Color.GRAY
var width = 20f
override var scaleFactor = 1.5f
override fun inactiveIndicatorDraw(c: Canvas, x: Float, y: Float) {
paint.color = colorInactive
c.drawRect(x, y - width / 2, x + width, y + width / 2, paint)
}

override fun activeIndicatorDraw(c: Canvas, x: Float, y: Float) {
paint.color = colorActive
val scale = ((width * scaleFactor) - width) / 2
c.drawRect(
x - scale,
y - (width * scaleFactor) / 2,
x + width + scale,
y + (width * scaleFactor) / 2,
paint
)
}

override fun getIndicatorWidth() = width
}

0 comments on commit 004e7ed

Please sign in to comment.