diff options
author | Allan Wang <me@allanwang.ca> | 2017-07-05 14:47:58 -0700 |
---|---|---|
committer | Allan Wang <me@allanwang.ca> | 2017-07-05 14:47:58 -0700 |
commit | 36471abc904ff4aa3109bd06efbc3ed493f082b2 (patch) | |
tree | 7b7f8a9b7828d0171ad2b5854a67b0108e772de7 /core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt | |
parent | 10e2ee9d4f105d9737b98b1caacf5e6ccb1c3c7d (diff) | |
download | kau-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.kt | 161 |
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 } } |