aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-07-05 14:47:58 -0700
committerAllan Wang <me@allanwang.ca>2017-07-05 14:47:58 -0700
commit36471abc904ff4aa3109bd06efbc3ed493f082b2 (patch)
tree7b7f8a9b7828d0171ad2b5854a67b0108e772de7 /core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
parent10e2ee9d4f105d9737b98b1caacf5e6ccb1c3c7d (diff)
downloadkau-36471abc904ff4aa3109bd06efbc3ed493f082b2.tar.gz
kau-36471abc904ff4aa3109bd06efbc3ed493f082b2.tar.bz2
kau-36471abc904ff4aa3109bd06efbc3ed493f082b2.zip
Setup swipe for all directions
Diffstat (limited to 'core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt')
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt161
1 files changed, 125 insertions, 36 deletions
diff --git a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
index 37dde73..d668b4c 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
@@ -5,14 +5,15 @@ import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.support.v4.view.ViewCompat
-import android.support.v4.widget.ViewDragHelper
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
+import ca.allanwang.kau.logging.KL
import ca.allanwang.kau.utils.navigationBarColor
import ca.allanwang.kau.utils.statusBarColor
+import ca.allanwang.kau.utils.withAlpha
import java.lang.ref.WeakReference
class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0
@@ -34,8 +35,8 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
set(value) {
field = value
if (value != null) {
- statusBarAlpha = Color.alpha(value.statusBarColor)
- navBarAlpha = Color.alpha(value.navigationBarColor)
+ statusBarAlpha = Color.alpha(value.statusBarColor)
+ navBarAlpha = Color.alpha(value.navigationBarColor)
}
}
@@ -70,22 +71,21 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
invalidate()
}
- var statusBarAlpha: Int = 255
- var navBarAlpha: Int = 255
+ private var statusBarAlpha: Int = 255
+ private var navBarAlpha: Int = 255
val chromeFadeListener: SwipeListener by lazy {
object : SwipeListener {
- override fun onScroll(percent: Float, px: Int) {
- TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ override fun onScroll(percent: Float, px: Int, edgeFlag: Int) {
+ activity?.apply {
+ statusBarColor = statusBarColor.withAlpha((statusBarAlpha * (1 - percent)).toInt())
+ navigationBarColor = navigationBarColor.withAlpha((navBarAlpha * (1 - percent)).toInt())
+ }
}
- override fun onEdgeTouch() {
- TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
- }
+ override fun onEdgeTouch() {}
- override fun onScrollToClose() {
- TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
- }
+ override fun onScrollToClose(edgeFlag: Int) {}
}
}
@@ -98,13 +98,43 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
*/
private var trackingEdge: Int = 0
+ override var edgeSize: Int
+ get() = dragHelper.edgeSize
+ set(value) {
+ dragHelper.edgeSize = value
+ }
+
+ override var edgeFlag = EDGE_LEFT
+ /**
+ * We will verify that only one axis is used at a time
+ */
+ set(value) {
+ val result = if (value and EDGE_HORIZONTAL > 0) value and EDGE_HORIZONTAL else value and EDGE_VERTICAL
+ field = value
+ dragHelper.setEdgeTrackingEnabled(value)
+ }
+
+ private val isHorizontal: Boolean
+ get() = edgeFlag and EDGE_HORIZONTAL > 0
+
+ private val isVertical: Boolean
+ get() = edgeFlag and EDGE_VERTICAL > 0
+
+ /**
+ * Specifies the edge flag that should by considered at the current moment
+ */
+ private var edgeChangeFlag: Int = -1
+
init {
dragHelper = ViewDragHelper.create(this, ViewDragCallback())
val density = resources.displayMetrics.density
val minVel = MIN_FLING_VELOCITY * density
- setEdgeSize(resources.displayMetrics.widthPixels)
+ //allow touch from anywhere on the screen
+ edgeSize = Math.max(resources.displayMetrics.widthPixels, resources.displayMetrics.heightPixels)
dragHelper.minVelocity = minVel
- dragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT)
+ dragHelper.maxVelocity = 2 * minVel
+ edgeFlag = edgeFlag
+ addListener(chromeFadeListener)
}
@@ -124,13 +154,13 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
* @param swipeEdge The size of an edge in pixels
*/
- override fun setEdgeSize(swipeEdge: Int) {
- trackingEdge = swipeEdge
- }
+ // override fun setEdgeSize(swipeEdge: Int) {
+// trackingEdge = swipeEdge
+// }
override fun setEdgeSizePercent(swipeEdgePercent: Float) {
- trackingEdge = (resources.displayMetrics.widthPixels * swipeEdgePercent).toInt()
+ edgeSize = (resources.displayMetrics.widthPixels * swipeEdgePercent).toInt()
}
/**
@@ -181,6 +211,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
inLayout = true
+ //todo update
contentView?.layout(contentOffset, 0, contentOffset + contentView!!.measuredWidth, contentView!!.measuredHeight)
inLayout = false
}
@@ -214,9 +245,8 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
val decor = activity.window.decorView as ViewGroup
var decorChild = decor.findViewById<View>(android.R.id.content)
- while (decorChild.parent !== decor) {
+ while (decorChild.parent !== decor)
decorChild = decorChild.parent as View
- }
decorChild.setBackgroundResource(background)
decor.removeView(decorChild)
addView(decorChild)
@@ -241,8 +271,11 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
private inner class ViewDragCallback : ViewDragHelper.Callback() {
private var isScrollOverValid: Boolean = false
+ /**
+ * Toggles whether we may intercept the touch event
+ */
override fun tryCaptureView(view: View, i: Int): Boolean {
- val ret = dragHelper.isEdgeTouched(ViewDragHelper.EDGE_LEFT, i)
+ val ret = dragHelper.isEdgeTouched(edgeFlag, i)
if (ret) {
listeners.forEach { it.get()?.onEdgeTouch() }
isScrollOverValid = true
@@ -250,47 +283,89 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
return ret
}
+ /**
+ * Needs to be bigger than 0 to specify that scrolling is possible horizontally
+ */
override fun getViewHorizontalDragRange(child: View): Int {
- return trackingEdge
+ return if (isHorizontal) 1 else 0
}
- override fun getViewVerticalDragRange(child: View?): Int {
- return 0
+ /**
+ * Needs to be bigger than 0 to specify that scrolling is possible vertically
+ */
+ override fun getViewVerticalDragRange(child: View): Int {
+ return if (isVertical) 1 else 0
}
override fun onViewPositionChanged(changedView: View, left: Int, top: Int, dx: Int, dy: Int) {
super.onViewPositionChanged(changedView, left, top, dx, dy)
- scrollPercent = Math.abs(left.toFloat() / contentView!!.width)
- contentOffset = left
+ //make sure that we are using the proper axis
+ val horizontal = (isHorizontal && (!isVertical || dy == 0))
+ edgeChangeFlag =
+ if (horizontal)
+ if (left > 0) EDGE_LEFT else EDGE_RIGHT
+ else
+ if (top > 0) EDGE_BOTTOM else EDGE_TOP
+
+ scrollPercent = Math.abs(
+ if (horizontal) left.toFloat() / contentView!!.width
+ else (top.toFloat() / contentView!!.height))
+// KL.d("horiz $horizontal scroll $scrollPercent")
+ contentOffset = if (horizontal) left else top
invalidate()
if (scrollPercent < scrollThreshold && !isScrollOverValid)
isScrollOverValid = true
- listeners.forEach { it.get()?.onScroll(scrollPercent, contentOffset) }
+ listeners.forEach { it.get()?.onScroll(scrollPercent, contentOffset, edgeChangeFlag) }
if (scrollPercent >= 1) {
if (!(activity?.isFinishing ?: true)) {
if (scrollPercent >= scrollThreshold && isScrollOverValid) {
isScrollOverValid = false
- listeners.forEach { it.get()?.onScrollToClose() }
+ listeners.forEach { it.get()?.onScrollToClose(edgeChangeFlag) }
}
activity?.finish()
+ activity?.overridePendingTransition(0, 0)
}
}
}
override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
- val childWidth = releasedChild.width
- val top = 0
- val left = if (xvel > 0 || xvel == 0f && scrollPercent > scrollThreshold)
- childWidth + OVERSCROLL_DISTANCE
- else 0
- dragHelper.settleCapturedViewAt(left, top)
+ var result = Pair(0, 0)
+ if (scrollPercent <= scrollThreshold) {
+ //threshold not met; check velocities
+ if ((edgeChangeFlag == EDGE_LEFT && xvel > MIN_FLING_VELOCITY)
+ || (edgeChangeFlag == EDGE_RIGHT && xvel < -MIN_FLING_VELOCITY)
+ || (edgeChangeFlag == EDGE_TOP && yvel > MIN_FLING_VELOCITY)
+ || (edgeChangeFlag == EDGE_BOTTOM && yvel < -MIN_FLING_VELOCITY))
+ result = exitCaptureOffsets(edgeChangeFlag, releasedChild)
+ } else {
+ //threshold met; fling to designated side
+ result = exitCaptureOffsets(edgeChangeFlag, releasedChild)
+ }
+ dragHelper.settleCapturedViewAt(result.first, result.second)
invalidate()
}
+ private fun exitCaptureOffsets(edgeFlag: Int, view: View): Pair<Int, Int> {
+ var top: Int = 0
+ var left: Int = 0
+ when (edgeFlag) {
+ EDGE_LEFT -> left = view.width + OVERSCROLL_DISTANCE
+ EDGE_RIGHT -> left = -(view.width + OVERSCROLL_DISTANCE)
+ EDGE_TOP -> top = -(view.height + OVERSCROLL_DISTANCE)
+ EDGE_BOTTOM -> top = view.height + OVERSCROLL_DISTANCE
+ else -> KL.e("Unknown edgeChangeFlag $edgeChangeFlag")
+ }
+ return Pair(left, top)
+ }
+
override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int {
- return Math.min(child.width, Math.max(left, 0))
+ return if (isHorizontal) Math.min(child.width, Math.max(left, 0)) else 0
+ }
+
+ override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
+ return if (isVertical) Math.min(child.height, Math.max(top, 0)) else 0
}
}
@@ -308,5 +383,19 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
private const val DEFAULT_SCROLL_THRESHOLD = 0.3f
private const val OVERSCROLL_DISTANCE = 10
+
+ val EDGE_LEFT = ViewDragHelper.EDGE_LEFT
+
+ val EDGE_RIGHT = ViewDragHelper.EDGE_RIGHT
+
+ val EDGE_TOP = ViewDragHelper.EDGE_TOP
+
+ val EDGE_BOTTOM = ViewDragHelper.EDGE_BOTTOM
+
+ val EDGE_HORIZONTAL = EDGE_LEFT or EDGE_RIGHT
+
+ val EDGE_VERTICAL = EDGE_TOP or EDGE_BOTTOM
+
+ val EDGE_ALL = EDGE_HORIZONTAL or EDGE_VERTICAL
}
}