Skip to content

Commit

Permalink
Add support for reversing the SlideToActView (#67)
Browse files Browse the repository at this point in the history
* Added a `slider_reversed` boolean attribute
* Added a boolean Kotlin attribute `isReversed` to control the reverse
behavior
* Extended handling of mPosition to support inverted position
* Added screenshots and section in the README file
* Added an extra layout with example of a reversed slider

Fixes #3
Fixes #65
  • Loading branch information
cortinico authored May 1, 2019
1 parent 8543fce commit 4ae44be
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 14 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ A simple *Slide to Unlock* **Material** widget for **Android**, written in [**Ko
* [``text``, ``text_size``, ``text_style``, ``text_appearance``](#text-text_size-text_style-text_appearance)
* [``slider_height``](#slider_height)
* [``slider_locked``](#slider_locked)
* [``slider_reversed``](#slider_reversed)
* [``slider_icon``](#slider_icon)
* [``rotate_icon``](#rotate_icon)
* [``android:elevation``](#androidelevation)
Expand Down Expand Up @@ -157,6 +158,20 @@ SlideToActView sta = (SlideToActView) findViewById(R.id.slider);
sta.setLocked(true);
```

#### ``slider_reversed``

Use the ``slider_reversed`` attribute to **reverse the slider** (this is a boolean attribute). When a slider is reversed, the cursor will appear on the right and will progress to the left. (default is false).

<p align="center">
<img src="assets/reversed_slider.gif" alt="reversed_slider gif"/>
</p>

You can also toggle this attribute programmatically with the provided setter.

```java
SlideToActView sta = (SlideToActView) findViewById(R.id.slider);
sta.setReversed(true);
```

#### ``slider_icon``

Expand Down
Binary file added assets/reversed_slider.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ protected void onCreate(Bundle savedInstanceState) {
findViewById(R.id.button_event_callbacks).setOnClickListener(this);
findViewById(R.id.button_locked_slider).setOnClickListener(this);
findViewById(R.id.button_custom_icon).setOnClickListener(this);
findViewById(R.id.button_reversed_slider).setOnClickListener(this);
}

public boolean onCreateOptionsMenu(Menu menu) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ protected void onCreate(Bundle savedInstanceState) {
case R.id.button_custom_icon:
setContentView(R.layout.content_custom_icon);
break;
case R.id.button_reversed_slider:
setContentView(R.layout.content_reversed_slider);
break;
default:
finish();
break;
Expand Down
6 changes: 6 additions & 0 deletions example/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,11 @@
android:layout_height="wrap_content"
android:text="@string/custom_icon" />

<Button
android:id="@+id/button_reversed_slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/reversed_slider" />

</LinearLayout>
</ScrollView>
21 changes: 21 additions & 0 deletions example/src/main/res/layout/content_reversed_slider.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:id="@+id/slide_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical">

<com.ncorti.slidetoact.SlideToActView
android:id="@+id/slide_reversed"
style="@style/SlideToActView.Example"
app:slider_reversed="true"
app:text="Reversed Slider" />

</LinearLayout>
</ScrollView>
1 change: 1 addition & 0 deletions example/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<string name="event_callback">Event Callback</string>
<string name="locked_slider">Locked Slider</string>
<string name="custom_icon">Custom Icon</string>
<string name="reversed_slider">Reversed Slider</string>
<string name="event_log">Event Log</string>
<string name="welcome_body">Press the following buttons to checkout different SlideToActView and understand each parameter. You can reset the sliders pressing the Reset button in the Toolbar. Enjoy :)</string>
</resources>
52 changes: 38 additions & 14 deletions slidetoact/src/main/java/com/ncorti/slidetoact/SlideToActView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class SlideToActView @JvmOverloads constructor (
invalidate()
}

/** Slider cursor position (between 0 and (`reaWidth - mAreaHeight)) */
/** Slider cursor position (between 0 and (`mAreaWidth - mAreaHeight)) */
private var mPosition: Int = 0
set(value) {
field = value
Expand All @@ -133,6 +133,13 @@ class SlideToActView @JvmOverloads constructor (
}
mPositionPerc = value.toFloat() / (mAreaWidth - mAreaHeight).toFloat()
mPositionPercInv = 1 - value.toFloat() / (mAreaWidth - mAreaHeight).toFloat()
mEffectivePosition = mPosition
}

/** Slider cursor effective position. This is used to handle the `reversed` scenario. */
private var mEffectivePosition : Int = 0
set(value) {
field = if (isReversed) (mAreaWidth - mAreaHeight) - value else value
}

/** Positioning of text */
Expand Down Expand Up @@ -203,6 +210,15 @@ class SlideToActView @JvmOverloads constructor (
/** Public flag to lock the slider */
var isLocked = false

/** Public flag to reverse the slider by 180 degree */
var isReversed = false
set(value) {
field = value
// We reassign the position field to trigger the re-computation of the effective position.
mPosition = mPosition
invalidate()
}

/** Public flag to lock the rotation icon */
var isRotateIcon = true

Expand Down Expand Up @@ -258,6 +274,7 @@ class SlideToActView @JvmOverloads constructor (
textAppearance = layoutAttrs.getResourceId(R.styleable.SlideToActView_text_appearance, 0)

isLocked = layoutAttrs.getBoolean(R.styleable.SlideToActView_slider_locked, false)
isReversed = layoutAttrs.getBoolean(R.styleable.SlideToActView_slider_reversed, false)
isRotateIcon = layoutAttrs.getBoolean(R.styleable.SlideToActView_rotate_icon, true)
isAnimateCompletion = layoutAttrs.getBoolean(R.styleable.SlideToActView_animate_completion, true)

Expand All @@ -279,8 +296,9 @@ class SlideToActView @JvmOverloads constructor (
layoutAttrs.recycle()
}

mInnerRect = RectF((mActualAreaMargin + mPosition).toFloat(), mActualAreaMargin.toFloat(),
(mAreaHeight + mPosition).toFloat() - mActualAreaMargin.toFloat(),
mInnerRect = RectF((mActualAreaMargin + mEffectivePosition).toFloat(),
mActualAreaMargin.toFloat(),
(mAreaHeight + mEffectivePosition).toFloat() - mActualAreaMargin.toFloat(),
mAreaHeight.toFloat() - mActualAreaMargin.toFloat())

mOuterRect = RectF(mActualAreaWidth.toFloat(), 0f, mAreaWidth.toFloat() - mActualAreaWidth.toFloat(), mAreaHeight.toFloat())
Expand Down Expand Up @@ -346,6 +364,9 @@ class SlideToActView @JvmOverloads constructor (
// Text horizontal/vertical positioning (both centered)
mTextXPosition = mAreaWidth.toFloat() / 2
mTextYPosition = (mAreaHeight.toFloat() / 2) - (mTextPaint.descent() + mTextPaint.ascent()) / 2

// Make sure the position is recomputed.
mPosition = 0
}

override fun onDraw(canvas: Canvas?) {
Expand All @@ -365,15 +386,20 @@ class SlideToActView @JvmOverloads constructor (
// 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 + mPosition).toFloat(),
mInnerRect.set((mActualAreaMargin + mEffectivePosition).toFloat(),
mActualAreaMargin.toFloat(),
(mAreaHeight + mPosition).toFloat() - mActualAreaMargin.toFloat(),
(mAreaHeight + mEffectivePosition).toFloat() - mActualAreaMargin.toFloat(),
mAreaHeight.toFloat() - mActualAreaMargin.toFloat())
canvas.drawRoundRect(mInnerRect, mBorderRadius.toFloat() * ratio, mBorderRadius.toFloat() * ratio, mInnerPaint)

// Arrow angle
// We compute the rotation of the arrow and we apply .rotate transformation on the canvas.
canvas.save()
if (isReversed) {
canvas.rotate(180f, mInnerRect.centerX(), mInnerRect.centerY())
}
if (isRotateIcon) {
mArrowAngle = -180 * mPositionPerc
mArrowAngle = 180 * mPositionPerc * (if (isReversed) 1 else -1)
canvas.rotate(mArrowAngle, mInnerRect.centerX(), mInnerRect.centerY())
}
mDrawableArrow.setBounds(mInnerRect.left.toInt() + mArrowMargin,
Expand All @@ -384,10 +410,7 @@ class SlideToActView @JvmOverloads constructor (
mDrawableArrow.bounds.top <= mDrawableArrow.bounds.bottom) {
mDrawableArrow.draw(canvas)
}

if (isRotateIcon) {
canvas.rotate(-1 * mArrowAngle, mInnerRect.centerX(), mInnerRect.centerY())
}
canvas.restore()

// Tick drawing
mDrawableTick.setBounds(
Expand All @@ -402,7 +425,6 @@ class SlideToActView @JvmOverloads constructor (
} else {
(mDrawableTick as AnimatedVectorDrawableCompat).setTint(innerColor)
}

if (mFlagDrawTick) {
mDrawableTick.draw(canvas)
}
Expand Down Expand Up @@ -475,17 +497,19 @@ class SlideToActView @JvmOverloads constructor (
* @return A boolean that informs if user has pressed or not
*/
private fun checkInsideButton(x: Float, y: Float): Boolean {
return (0 < y && y < mAreaHeight && mPosition < x && x < (mAreaHeight + mPosition))
return (0 < y && y < mAreaHeight && mEffectivePosition < x && x < (mAreaHeight + mEffectivePosition))
}

/**
* Private method for increasing/decreasing the position
* Ensure that position never exits from its range [0, (mAreaWidth - mAreaHeight)]
* Ensure that position never exits from its range [0, (mAreaWidth - mAreaHeight)].
*
* Please note that the increment is inverted in case of a reversed slider.
*
* @param inc Increment to be performed (negative if it's a decrement)
*/
private fun increasePosition(inc: Int) {
mPosition += inc
mPosition = if (isReversed) mPosition - inc else mPosition + inc
if (mPosition < 0)
mPosition = 0
if (mPosition > (mAreaWidth - mAreaHeight))
Expand Down
1 change: 1 addition & 0 deletions slidetoact/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<attr name="border_radius" format="dimension" />
<attr name="slider_height" format="dimension" />
<attr name="slider_locked" format="boolean" />
<attr name="slider_reversed" format="boolean" />
<attr name="slider_icon" format="reference" />
<attr name="slider_icon_color" format="color"/>
<attr name="rotate_icon" format="boolean" />
Expand Down

0 comments on commit 4ae44be

Please sign in to comment.