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