diff --git a/slidetoact/src/main/java/com/ncorti/slidetoact/SlideToActView.kt b/slidetoact/src/main/java/com/ncorti/slidetoact/SlideToActView.kt
index e3507278..1d02cff5 100644
--- a/slidetoact/src/main/java/com/ncorti/slidetoact/SlideToActView.kt
+++ b/slidetoact/src/main/java/com/ncorti/slidetoact/SlideToActView.kt
@@ -8,11 +8,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.content.res.TypedArray
-import android.graphics.Canvas
-import android.graphics.Outline
-import android.graphics.Paint
-import android.graphics.RectF
-import android.graphics.Typeface
+import android.graphics.*
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.VibrationEffect
@@ -24,6 +20,7 @@ import android.view.MotionEvent
import android.view.View
import android.view.ViewOutlineProvider
import android.view.animation.AnticipateOvershootInterpolator
+import android.view.animation.LinearInterpolator
import android.view.animation.OvershootInterpolator
import android.widget.TextView
import androidx.annotation.ColorInt
@@ -46,9 +43,9 @@ import com.ncorti.slidetoact.SlideToActIconUtil.tintIconCompat
* with a "Slide-to-unlock" like widget.
*/
class SlideToActView @JvmOverloads constructor(
- context: Context,
- xmlAttrs: AttributeSet? = null,
- defStyleAttr: Int = R.attr.slideToActViewStyle
+ context: Context,
+ xmlAttrs: AttributeSet? = null,
+ defStyleAttr: Int = R.attr.slideToActViewStyle
) : View(context, xmlAttrs, defStyleAttr) {
companion object {
@@ -66,16 +63,26 @@ class SlideToActView @JvmOverloads constructor(
/** Height of the drawing area */
private var mAreaHeight: Int = 0
+
/** Width of the drawing area */
private var mAreaWidth: Int = 0
+
/** Actual Width of the drawing area, used for animations */
private var mActualAreaWidth: Int = 0
+
/** Border Radius, default to mAreaHeight/2, -1 when not initialized */
private var mBorderRadius: Int = -1
+
/** Margin of the cursor from the outer area */
private var mActualAreaMargin: Int
private val mOriginAreaMargin: Int
+ /** Enable default icon tint for slider **/
+ var enableSliderIconTint: Boolean = true
+
+ /** Enable default icon tint for completion **/
+ var enableCompleteIconTint: Boolean = true
+
/** Text message */
var text: CharSequence = ""
set(value) {
@@ -124,6 +131,28 @@ class SlideToActView @JvmOverloads constructor(
invalidate()
}
+ /** Stroke for inner borders **/
+ var innerStroke: Stroke? = null
+ set(value) {
+ field = value
+ value?.also {
+ mInnerStrokePaint.strokeWidth = it.width
+ mInnerStrokePaint.color = it.color
+ }
+ invalidate()
+ }
+
+ /** Stroke for outer borders **/
+ var outerStroke: Stroke? = null
+ set(value) {
+ field = value
+ value?.also {
+ mOuterStrokePaint.strokeWidth = it.width
+ mOuterStrokePaint.color = it.color
+ }
+ invalidate()
+ }
+
/** Duration of the complete and reset animation (in milliseconds). */
var animDuration: Long = 300
@@ -144,7 +173,8 @@ class SlideToActView @JvmOverloads constructor(
var iconColor: Int = 0
set(value) {
field = value
- DrawableCompat.setTint(mDrawableArrow, value)
+ if (value != 0)
+ DrawableCompat.setTint(mDrawableArrow, value)
invalidate()
}
@@ -156,7 +186,8 @@ class SlideToActView @JvmOverloads constructor(
if (field != 0) {
ResourcesCompat.getDrawable(context.resources, value, context.theme)?.let {
mDrawableArrow = it
- DrawableCompat.setTint(it, iconColor)
+ if (iconColor != 0)
+ DrawableCompat.setTint(it, iconColor)
}
invalidate()
}
@@ -197,16 +228,20 @@ class SlideToActView @JvmOverloads constructor(
/** Slider cursor position in percentage (between 0f and 1f) */
private var mPositionPerc: Float = 0f
+
/** 1/mPositionPerc */
private var mPositionPercInv: Float = 1f
/* -------------------- ICONS -------------------- */
private val mIconMargin: Int
+
/** Margin for Arrow Icon */
private var mArrowMargin: Int
+
/** Current angle for Arrow Icon */
private var mArrowAngle: Float = 0f
+
/** Margin for Tick Icon */
private var mTickMargin: Int
@@ -234,6 +269,16 @@ class SlideToActView @JvmOverloads constructor(
/** Paint used for inner elements */
private val mInnerPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
+ /** Paint stroke used for inner elements */
+ private val mInnerStrokePaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ style = Paint.Style.STROKE
+ strokeJoin = Paint.Join.ROUND
+ strokeCap = Paint.Cap.ROUND
+ }
+
+ /** Paint stroke used for outer elements */
+ private val mOuterStrokePaint: Paint = Paint(mInnerStrokePaint)
+
/** Paint used for text elements */
private var mTextPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
@@ -242,13 +287,24 @@ class SlideToActView @JvmOverloads constructor(
/** Inner rectangle (used for arrow rotation) */
private var mInnerRect: RectF
+
+ /** Inner stroke rectangle (used for arrow rotation) */
+ private var mInnerStrokeRect: RectF
+
+
/** Outer rectangle (used for area drawing) */
private var mOuterRect: RectF
+
+ /** Outer stroke rectangle (used for area drawing) */
+ private var mOuterStrokeRect: RectF
+
+
/** Grace value, when mPositionPerc > mGraceValue slider will perform the 'complete' operations */
- private val mGraceValue: Float = 0.8F
+ var graceValue: Float = 0.8F
/** Last X coordinate for the touch event */
private var mLastX: Float = 0F
+
/** Flag to understand if user is moving the slider cursor */
private var mFlagMoving: Boolean = false
@@ -284,49 +340,60 @@ class SlideToActView @JvmOverloads constructor(
val actualInnerColor: Int
val actualTextColor: Int
val actualIconColor: Int
-
+ val actualStrokeInnerColor: Int
+ val actualStrokeInnerWidth: Float
+ val actualStrokeOuterColor: Int
+ val actualStrokeOuterWidth: Float
val actualCompleteDrawable: Int
+ val defaultStrokeWidth: Float = resources.getDimension(R.dimen.slidetoact_default_stroke_width)
+
mTextView = TextView(context)
mTextPaint = mTextView.paint
val attrs: TypedArray = context.theme.obtainStyledAttributes(
- xmlAttrs,
- R.styleable.SlideToActView,
- defStyleAttr,
- R.style.SlideToActView
+ xmlAttrs,
+ R.styleable.SlideToActView,
+ defStyleAttr,
+ R.style.SlideToActView
)
try {
mDesiredSliderHeight = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- mDesiredSliderHeightDp,
- resources.displayMetrics
+ TypedValue.COMPLEX_UNIT_DIP,
+ mDesiredSliderHeightDp,
+ resources.displayMetrics
).toInt()
mDesiredSliderWidth = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- mDesiredSliderWidthDp,
- resources.displayMetrics
+ TypedValue.COMPLEX_UNIT_DIP,
+ mDesiredSliderWidthDp,
+ resources.displayMetrics
).toInt()
val defaultOuter = ContextCompat.getColor(
- this.context,
- R.color.slidetoact_defaultAccent
+ this.context,
+ R.color.slidetoact_defaultAccent
)
val defaultWhite = ContextCompat.getColor(
- this.context,
- R.color.slidetoact_white
+ this.context,
+ R.color.slidetoact_white
)
with(attrs) {
mDesiredSliderHeight = getDimensionPixelSize(
- R.styleable.SlideToActView_slider_height,
- mDesiredSliderHeight
+ R.styleable.SlideToActView_slider_height,
+ mDesiredSliderHeight
)
mBorderRadius = getDimensionPixelSize(R.styleable.SlideToActView_border_radius, -1)
actualOuterColor = getColor(R.styleable.SlideToActView_outer_color, defaultOuter)
actualInnerColor = getColor(R.styleable.SlideToActView_inner_color, defaultWhite)
+ actualStrokeInnerColor = getColor(R.styleable.SlideToActView_inner_stroke_color, -1)
+ actualStrokeOuterColor = getColor(R.styleable.SlideToActView_outer_stroke_color, -1)
+
+ actualStrokeInnerWidth = getDimension(R.styleable.SlideToActView_inner_stroke_width, defaultStrokeWidth)
+ actualStrokeOuterWidth = getDimension(R.styleable.SlideToActView_outer_stroke_width, defaultStrokeWidth)
+
// For text color, check if the `text_color` is set.
// if not check if the `outer_color` is set.
// if not, default to white.
@@ -340,8 +407,8 @@ class SlideToActView @JvmOverloads constructor(
text = getString(R.styleable.SlideToActView_text) ?: ""
typeFace = getInt(R.styleable.SlideToActView_text_style, 0)
mTextSize = getDimensionPixelSize(
- R.styleable.SlideToActView_text_size,
- resources.getDimensionPixelSize(R.dimen.slidetoact_default_text_size)
+ R.styleable.SlideToActView_text_size,
+ resources.getDimensionPixelSize(R.dimen.slidetoact_default_text_size)
)
textColor = actualTextColor
@@ -352,46 +419,63 @@ class SlideToActView @JvmOverloads constructor(
isReversed = getBoolean(R.styleable.SlideToActView_slider_reversed, false)
isRotateIcon = getBoolean(R.styleable.SlideToActView_rotate_icon, true)
isAnimateCompletion = getBoolean(
- R.styleable.SlideToActView_animate_completion,
- true
+ R.styleable.SlideToActView_animate_completion,
+ true
+ )
+
+ graceValue = getFloat(
+ R.styleable.SlideToActView_grace_value_percent,
+ graceValue
)
+
animDuration = getInteger(
- R.styleable.SlideToActView_animation_duration,
- 300
+ R.styleable.SlideToActView_animation_duration,
+ 300
).toLong()
bumpVibration = getInt(
- R.styleable.SlideToActView_bump_vibration,
- 0
+ R.styleable.SlideToActView_bump_vibration,
+ 0
).toLong()
mOriginAreaMargin = getDimensionPixelSize(
- R.styleable.SlideToActView_area_margin,
- resources.getDimensionPixelSize(R.dimen.slidetoact_default_area_margin)
+ R.styleable.SlideToActView_area_margin,
+ resources.getDimensionPixelSize(R.dimen.slidetoact_default_area_margin)
)
mActualAreaMargin = mOriginAreaMargin
+ enableSliderIconTint = getBoolean(
+ R.styleable.SlideToActView_enable_tint_slider_icon,
+ true
+ )
+
+ enableCompleteIconTint = getBoolean(
+ R.styleable.SlideToActView_enable_tint_complete_icon,
+ true
+ )
+
sliderIcon = getResourceId(
- R.styleable.SlideToActView_slider_icon,
- R.drawable.slidetoact_ic_arrow
+ R.styleable.SlideToActView_slider_icon,
+ R.drawable.slidetoact_ic_arrow
)
// For icon color. check if the `slide_icon_color` is set.
// if not check if the `outer_color` is set.
// if not, default to defaultOuter.
actualIconColor = when {
+ !enableSliderIconTint -> 0
hasValue(R.styleable.SlideToActView_slider_icon_color) ->
getColor(R.styleable.SlideToActView_slider_icon_color, defaultOuter)
hasValue(R.styleable.SlideToActView_outer_color) -> actualOuterColor
else -> defaultOuter
}
actualCompleteDrawable = getResourceId(
- R.styleable.SlideToActView_complete_icon,
- R.drawable.slidetoact_animated_ic_check
+ R.styleable.SlideToActView_complete_icon,
+ R.drawable.slidetoact_animated_ic_check
)
mIconMargin = getDimensionPixelSize(
- R.styleable.SlideToActView_icon_margin,
- resources.getDimensionPixelSize(R.dimen.slidetoact_default_icon_margin)
+ R.styleable.SlideToActView_icon_margin,
+ resources.getDimensionPixelSize(R.dimen.slidetoact_default_icon_margin)
)
mArrowMargin = mIconMargin
@@ -402,17 +486,31 @@ class SlideToActView @JvmOverloads constructor(
}
mInnerRect = RectF(
- (mActualAreaMargin + mEffectivePosition).toFloat(),
- mActualAreaMargin.toFloat(),
- (mAreaHeight + mEffectivePosition).toFloat() - mActualAreaMargin.toFloat(),
- mAreaHeight.toFloat() - mActualAreaMargin.toFloat()
+ (mActualAreaMargin + mEffectivePosition).toFloat(),
+ mActualAreaMargin.toFloat(),
+ (mAreaHeight + mEffectivePosition).toFloat() - mActualAreaMargin.toFloat(),
+ mAreaHeight.toFloat() - mActualAreaMargin.toFloat()
+ )
+
+ mInnerStrokeRect = RectF(
+ mInnerRect.left + mInnerStrokePaint.strokeWidth / 2,
+ mInnerRect.top + mInnerStrokePaint.strokeWidth / 2,
+ mInnerRect.right - mInnerStrokePaint.strokeWidth / 2,
+ mInnerRect.bottom - mInnerStrokePaint.strokeWidth / 2
)
mOuterRect = RectF(
- mActualAreaWidth.toFloat(),
- 0f,
- mAreaWidth.toFloat() - mActualAreaWidth.toFloat(),
- mAreaHeight.toFloat()
+ mActualAreaWidth.toFloat(),
+ 0f,
+ mAreaWidth.toFloat() - mActualAreaWidth.toFloat(),
+ mAreaHeight.toFloat()
+ )
+
+ mOuterStrokeRect = RectF(
+ mOuterRect.left + mOuterStrokePaint.strokeWidth / 2,
+ mOuterRect.top + mOuterStrokePaint.strokeWidth / 2,
+ mOuterRect.right - mOuterStrokePaint.strokeWidth / 2,
+ mOuterRect.bottom - mOuterStrokePaint.strokeWidth / 2
)
mDrawableTick = loadIconCompat(context, actualCompleteDrawable)
@@ -423,6 +521,13 @@ class SlideToActView @JvmOverloads constructor(
innerColor = actualInnerColor
iconColor = actualIconColor
+
+ if (actualStrokeInnerColor != -1)
+ innerStroke = Stroke(actualStrokeInnerWidth, actualStrokeInnerColor)
+
+ if (actualStrokeOuterColor != -1)
+ outerStroke = Stroke(actualStrokeOuterWidth, actualStrokeOuterColor)
+
// This outline provider force removal of shadow
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
outlineProvider = SlideToActOutlineProvider()
@@ -454,7 +559,7 @@ class SlideToActView @JvmOverloads constructor(
// Text horizontal/vertical positioning (both centered)
mTextXPosition = mAreaWidth.toFloat() / 2
mTextYPosition = (mAreaHeight.toFloat() / 2) -
- (mTextPaint.descent() + mTextPaint.ascent()) / 2
+ (mTextPaint.descent() + mTextPaint.ascent()) / 2
// Make sure the position is recomputed.
mPosition = 0
@@ -466,47 +571,79 @@ class SlideToActView @JvmOverloads constructor(
// Outer area
mOuterRect.set(
- mActualAreaWidth.toFloat(),
- 0f,
- mAreaWidth.toFloat() - mActualAreaWidth.toFloat(),
- mAreaHeight.toFloat()
+ mActualAreaWidth.toFloat(),
+ 0f,
+ mAreaWidth.toFloat() - mActualAreaWidth.toFloat(),
+ mAreaHeight.toFloat()
)
canvas.drawRoundRect(
- mOuterRect,
- mBorderRadius.toFloat(),
- mBorderRadius.toFloat(),
- mOuterPaint
+ mOuterRect,
+ mBorderRadius.toFloat(),
+ mBorderRadius.toFloat(),
+ mOuterPaint
)
+ outerStroke?.also {
+ mOuterStrokeRect.set(
+ mOuterRect.left + it.width / 2,
+ mOuterRect.top + it.width / 2,
+ mOuterRect.right - it.width / 2,
+ mOuterRect.bottom - it.width / 2,
+ )
+ val outerRadius = mBorderRadius.toFloat()
+ canvas.drawRoundRect(
+ mOuterStrokeRect,
+ outerRadius,
+ outerRadius,
+ mOuterStrokePaint
+ )
+ }
+
// Text alpha
mTextPaint.alpha = (255 * mPositionPercInv).toInt()
// Checking if the TextView has a Transformation method applied (e.g. AllCaps).
val textToDraw = mTextView.transformationMethod?.getTransformation(text, mTextView) ?: text
canvas.drawText(
- textToDraw,
- 0,
- textToDraw.length,
- mTextXPosition,
- mTextYPosition,
- mTextPaint
+ textToDraw,
+ 0,
+ textToDraw.length,
+ mTextXPosition,
+ mTextYPosition,
+ mTextPaint
)
// Inner Cursor
// ratio is used to compute the proper border radius for the inner rect (see #8).
val ratio = (mAreaHeight - 2 * mActualAreaMargin).toFloat() / mAreaHeight.toFloat()
mInnerRect.set(
- (mActualAreaMargin + mEffectivePosition).toFloat(),
- mActualAreaMargin.toFloat(),
- (mAreaHeight + mEffectivePosition).toFloat() - mActualAreaMargin.toFloat(),
- mAreaHeight.toFloat() - mActualAreaMargin.toFloat()
+ (mActualAreaMargin + mEffectivePosition).toFloat(),
+ mActualAreaMargin.toFloat(),
+ (mAreaHeight + mEffectivePosition).toFloat() - mActualAreaMargin.toFloat(),
+ mAreaHeight.toFloat() - mActualAreaMargin.toFloat()
)
canvas.drawRoundRect(
- mInnerRect,
- mBorderRadius.toFloat() * ratio,
- mBorderRadius.toFloat() * ratio,
- mInnerPaint
+ mInnerRect,
+ mBorderRadius.toFloat() * ratio,
+ mBorderRadius.toFloat() * ratio,
+ mInnerPaint
)
+ innerStroke?.also {
+ val innerRadius = (mBorderRadius.toFloat() * ratio)
+ mInnerStrokeRect.set(
+ mInnerRect.left + it.width / 2,
+ mInnerRect.top + it.width / 2,
+ mInnerRect.right - it.width / 2,
+ mInnerRect.bottom - it.width / 2,
+ )
+ canvas.drawRoundRect(
+ mInnerStrokeRect,
+ innerRadius,
+ innerRadius,
+ mInnerStrokePaint
+ )
+ }
+
// Arrow angle
// We compute the rotation of the arrow and we apply .rotate transformation on the canvas.
canvas.save()
@@ -517,33 +654,60 @@ class SlideToActView @JvmOverloads constructor(
mArrowAngle = -180 * mPositionPerc
canvas.rotate(mArrowAngle, mInnerRect.centerX(), mInnerRect.centerY())
}
- mDrawableArrow.setBounds(
- mInnerRect.left.toInt() + mArrowMargin,
- mInnerRect.top.toInt() + mArrowMargin,
- mInnerRect.right.toInt() - mArrowMargin,
- mInnerRect.bottom.toInt() - mArrowMargin
- )
+
+ createCropBounds(mDrawableArrow,mInnerRect,mArrowMargin)
+
if (mDrawableArrow.bounds.left <= mDrawableArrow.bounds.right &&
- mDrawableArrow.bounds.top <= mDrawableArrow.bounds.bottom
+ mDrawableArrow.bounds.top <= mDrawableArrow.bounds.bottom
) {
mDrawableArrow.draw(canvas)
}
+
canvas.restore()
// Tick drawing
mDrawableTick.setBounds(
- mActualAreaWidth + mTickMargin,
- mTickMargin,
- mAreaWidth - mTickMargin - mActualAreaWidth,
- mAreaHeight - mTickMargin
+ mActualAreaWidth + mTickMargin,
+ mTickMargin,
+ mAreaWidth - mTickMargin - mActualAreaWidth,
+ mAreaHeight - mTickMargin
)
- tintIconCompat(mDrawableTick, innerColor)
+ if (enableCompleteIconTint)
+ tintIconCompat(mDrawableTick, innerColor)
+
if (mFlagDrawTick) {
mDrawableTick.draw(canvas)
}
}
+ private fun createCropBounds(drawable: Drawable,rect:RectF,margin:Int) {
+ val proportion = drawable.intrinsicWidth / drawable.intrinsicHeight.toFloat()
+ val width = rect.right.toInt() - margin * 2 - rect.left.toInt()
+ val height = rect.bottom.toInt() - margin * 2 - rect.top.toInt()
+ val proportionWidth: Int
+ val proportionHeight: Int
+
+ if (proportion >= 1) {
+ proportionHeight = (width * 1 / proportion).toInt()
+ proportionWidth = width
+ } else {
+ proportionHeight = height
+ proportionWidth = (height * proportion).toInt()
+ }
+
+ val left = rect.left.toInt() + margin + width / 2 - proportionWidth / 2
+ val top = rect.top.toInt() + margin + height / 2 - proportionHeight / 2
+ val right = rect.left.toInt() + margin + width / 2 + proportionWidth / 2
+ val bottom = rect.top.toInt() + margin + height / 2 + proportionHeight / 2
+ drawable.setBounds(
+ left,
+ top,
+ right,
+ bottom
+ )
+ }
+
// Intentionally override `performClick` to do not lose accessibility support.
@Suppress("RedundantOverride")
override fun performClick(): Boolean {
@@ -570,7 +734,7 @@ class SlideToActView @JvmOverloads constructor(
MotionEvent.ACTION_UP -> {
parent.requestDisallowInterceptTouchEvent(false)
if ((mPosition > 0 && isLocked) ||
- (mPosition > 0 && mPositionPerc < mGraceValue)
+ (mPosition > 0 && mPositionPerc < graceValue)
) {
// Check for grace value
val positionAnimator = ValueAnimator.ofInt(mPosition, 0)
@@ -580,7 +744,7 @@ class SlideToActView @JvmOverloads constructor(
invalidate()
}
positionAnimator.start()
- } else if (mPosition > 0 && mPositionPerc >= mGraceValue) {
+ } else if (mPosition > 0 && mPositionPerc >= graceValue) {
isEnabled = false // Fully disable touch events
startAnimationComplete()
} else if (mFlagMoving && mPosition == 0) {
@@ -621,11 +785,11 @@ class SlideToActView @JvmOverloads constructor(
*/
private fun checkInsideButton(x: Float, y: Float): Boolean {
return (
- 0 < y &&
- y < mAreaHeight &&
- mEffectivePosition < x &&
- x < (mAreaHeight + mEffectivePosition)
- )
+ 0 < y &&
+ y < mAreaHeight &&
+ mEffectivePosition < x &&
+ x < (mAreaHeight + mEffectivePosition)
+ )
}
/**
@@ -665,14 +829,20 @@ class SlideToActView @JvmOverloads constructor(
// Animator that bounce away the cursors
val marginAnimator = ValueAnimator.ofInt(
- mActualAreaMargin,
- (mInnerRect.width() / 2).toInt() + mActualAreaMargin
+ mActualAreaMargin,
+ (mInnerRect.width() / 2).toInt() + mActualAreaMargin
)
marginAnimator.addUpdateListener {
mActualAreaMargin = it.animatedValue as Int
+ innerStroke?.also { stroke ->
+ mInnerStrokePaint.apply {
+ val factor = (1 - it.animatedFraction)
+ alpha = checkAlphaLimit((factor * 255).toInt())
+ }
+ }
invalidate()
}
- marginAnimator.interpolator = AnticipateOvershootInterpolator(2f)
+ marginAnimator.interpolator = LinearInterpolator()
// Animator that reduces the outer area (to right)
val areaAnimator = ValueAnimator.ofInt(0, (mAreaWidth - mAreaHeight) / 2)
@@ -709,28 +879,28 @@ class SlideToActView @JvmOverloads constructor(
animSet.duration = animDuration
animSet.addListener(
- object : Animator.AnimatorListener {
- override fun onAnimationStart(p0: Animator?) {
- onSlideToActAnimationEventListener?.onSlideCompleteAnimationStarted(
- this@SlideToActView,
- mPositionPerc
- )
- }
+ object : Animator.AnimatorListener {
+ override fun onAnimationStart(p0: Animator?) {
+ onSlideToActAnimationEventListener?.onSlideCompleteAnimationStarted(
+ this@SlideToActView,
+ mPositionPerc
+ )
+ }
- override fun onAnimationCancel(p0: Animator?) {
- }
+ override fun onAnimationCancel(p0: Animator?) {
+ }
- override fun onAnimationEnd(p0: Animator?) {
- mIsCompleted = true
- onSlideToActAnimationEventListener?.onSlideCompleteAnimationEnded(
- this@SlideToActView
- )
- onSlideCompleteListener?.onSlideComplete(this@SlideToActView)
- }
+ override fun onAnimationEnd(p0: Animator?) {
+ mIsCompleted = true
+ onSlideToActAnimationEventListener?.onSlideCompleteAnimationEnded(
+ this@SlideToActView
+ )
+ onSlideCompleteListener?.onSlideComplete(this@SlideToActView)
+ }
- override fun onAnimationRepeat(p0: Animator?) {
+ override fun onAnimationRepeat(p0: Animator?) {
+ }
}
- }
)
animSet.start()
}
@@ -797,6 +967,12 @@ class SlideToActView @JvmOverloads constructor(
val marginAnimator = ValueAnimator.ofInt(mActualAreaMargin, mOriginAreaMargin)
marginAnimator.addUpdateListener {
mActualAreaMargin = it.animatedValue as Int
+ innerStroke?.also { stroke ->
+ mInnerStrokePaint.apply {
+ val factor = it.animatedFraction
+ alpha = checkAlphaLimit((factor * 255).toInt())
+ }
+ }
invalidate()
}
marginAnimator.interpolator = AnticipateOvershootInterpolator(2f)
@@ -812,11 +988,11 @@ class SlideToActView @JvmOverloads constructor(
if (isAnimateCompletion) {
animSet.playSequentially(
- tickAnimator,
- areaAnimator,
- positionAnimator,
- marginAnimator,
- arrowAnimator
+ tickAnimator,
+ areaAnimator,
+ positionAnimator,
+ marginAnimator,
+ arrowAnimator
)
} else {
animSet.playSequentially(positionAnimator)
@@ -825,32 +1001,39 @@ class SlideToActView @JvmOverloads constructor(
animSet.duration = animDuration
animSet.addListener(
- object : Animator.AnimatorListener {
- override fun onAnimationStart(p0: Animator?) {
- onSlideToActAnimationEventListener?.onSlideResetAnimationStarted(
- this@SlideToActView
- )
- }
+ object : Animator.AnimatorListener {
+ override fun onAnimationStart(p0: Animator?) {
+ onSlideToActAnimationEventListener?.onSlideResetAnimationStarted(
+ this@SlideToActView
+ )
+ }
- override fun onAnimationCancel(p0: Animator?) {
- }
+ override fun onAnimationCancel(p0: Animator?) {
+ }
- override fun onAnimationEnd(p0: Animator?) {
- isEnabled = true
- stopIconAnimation(mDrawableTick)
- onSlideToActAnimationEventListener?.onSlideResetAnimationEnded(
- this@SlideToActView
- )
- onSlideResetListener?.onSlideReset(this@SlideToActView)
- }
+ override fun onAnimationEnd(p0: Animator?) {
+ isEnabled = true
+ stopIconAnimation(mDrawableTick)
+ onSlideToActAnimationEventListener?.onSlideResetAnimationEnded(
+ this@SlideToActView
+ )
+ onSlideResetListener?.onSlideReset(this@SlideToActView)
+ }
- override fun onAnimationRepeat(p0: Animator?) {
+ override fun onAnimationRepeat(p0: Animator?) {
+ }
}
- }
)
animSet.start()
}
+ /**Check limit for alpha value**/
+ private fun checkAlphaLimit(alpha: Int): Int = when {
+ alpha > 255 -> 255
+ alpha < 0 -> 0
+ else -> alpha
+ }
+
/**
* Private method to handle vibration logic, called when the cursor it moved to the end of
* it's path.
@@ -860,13 +1043,13 @@ class SlideToActView @JvmOverloads constructor(
if (bumpVibration <= 0) return
if (ContextCompat.checkSelfPermission(context, Manifest.permission.VIBRATE) !=
- PackageManager.PERMISSION_GRANTED
+ PackageManager.PERMISSION_GRANTED
) {
Log.w(
- TAG,
- "bumpVibration is set but permissions are unavailable." +
- "You must have the permission android.permission.VIBRATE in " +
- "AndroidManifest.xml to use bumpVibration"
+ TAG,
+ "bumpVibration is set but permissions are unavailable." +
+ "You must have the permission android.permission.VIBRATE in " +
+ "AndroidManifest.xml to use bumpVibration"
)
return
}
@@ -875,7 +1058,7 @@ class SlideToActView @JvmOverloads constructor(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(
- VibrationEffect.createOneShot(bumpVibration, VibrationEffect.DEFAULT_AMPLITUDE)
+ VibrationEffect.createOneShot(bumpVibration, VibrationEffect.DEFAULT_AMPLITUDE)
)
} else {
vibrator.vibrate(bumpVibration)
@@ -978,12 +1161,17 @@ class SlideToActView @JvmOverloads constructor(
if (view == null || outline == null) return
outline.setRoundRect(
- mActualAreaWidth,
- 0,
- mAreaWidth - mActualAreaWidth,
- mAreaHeight,
- mBorderRadius.toFloat()
+ mActualAreaWidth,
+ 0,
+ mAreaWidth - mActualAreaWidth,
+ mAreaHeight,
+ mBorderRadius.toFloat()
)
}
}
+
+ data class Stroke(
+ val width: Float,
+ @ColorInt val color: Int
+ )
}
diff --git a/slidetoact/src/main/res/values/attrs.xml b/slidetoact/src/main/res/values/attrs.xml
index 606d870b..317a1446 100644
--- a/slidetoact/src/main/res/values/attrs.xml
+++ b/slidetoact/src/main/res/values/attrs.xml
@@ -11,15 +11,22 @@
+
+
+
+
+
+
+
diff --git a/slidetoact/src/main/res/values/dimens.xml b/slidetoact/src/main/res/values/dimens.xml
index 1d4f69ea..0f26c29d 100644
--- a/slidetoact/src/main/res/values/dimens.xml
+++ b/slidetoact/src/main/res/values/dimens.xml
@@ -1,5 +1,6 @@
8dp
+ 3dp
16dp
16sp