-
-
Save forceLain/49e02e8d772e99707ebda9137b3b6ccb to your computer and use it in GitHub Desktop.
SlidingActivity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
abstract class SlidingActivity : AppCompatActivity() { | |
private val GESTURE_THRESHOLD = 10 | |
private lateinit var root: View | |
private var startX = 0f | |
private var startY = 0f | |
private lateinit var screenSize : Point | |
private var isSliding = false | |
private lateinit var windowScrim: ColorDrawable | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
screenSize = Point().apply { windowManager.defaultDisplay.getSize(this) } | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | |
window.statusBarColor = Color.TRANSPARENT | |
} | |
windowScrim = ColorDrawable(Color.argb(0xE0, 0, 0, 0)) | |
windowScrim.alpha = 0 | |
window.setBackgroundDrawable(windowScrim) | |
} | |
override fun onPostCreate(savedInstanceState: Bundle?) { | |
super.onPostCreate(savedInstanceState) | |
root = getRootView() | |
} | |
abstract fun getRootView(): View | |
override fun dispatchTouchEvent(ev: MotionEvent): Boolean { | |
var handled = false | |
when (ev.action) { | |
MotionEvent.ACTION_DOWN -> { | |
startX = ev.x | |
startY = ev.y | |
} | |
MotionEvent.ACTION_MOVE -> { | |
if ((shouldHandle(startX, startY, ev) && canSlideDown()) || isSliding) { | |
if (!isSliding) { | |
isSliding = true | |
onSlidingStarted() | |
ev.action = MotionEvent.ACTION_CANCEL | |
super.dispatchTouchEvent(ev) | |
} | |
root.y = (ev.y - startY).coerceAtLeast(0f) | |
updateScrim() | |
handled = true | |
} | |
} | |
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { | |
if (isSliding) { | |
isSliding = false | |
onSlidingFinished() | |
handled = true | |
if (shouldClose(ev.y - startY)) { | |
closeDownAndDismiss() | |
} else { | |
root.y = 0f | |
} | |
} | |
startX = 0f | |
startY = 0f | |
} | |
} | |
return if (handled) true else super.dispatchTouchEvent(ev) | |
} | |
private fun shouldHandle(startX: Float, startY: Float, ev: MotionEvent): Boolean { | |
val deltaX = (startX - ev.x).abs() | |
if (deltaX > GESTURE_THRESHOLD) return false | |
val deltaY = ev.y - startY | |
return deltaY > GESTURE_THRESHOLD | |
} | |
abstract fun onSlidingFinished() | |
abstract fun onSlidingStarted() | |
abstract fun canSlideDown(): Boolean | |
private fun shouldClose(delta: Float): Boolean { | |
return delta > screenSize.y / 3 | |
} | |
private fun closeDownAndDismiss() { | |
val start = root.y | |
val finish = screenSize.y.toFloat() | |
val positionAnimator = ObjectAnimator.ofFloat(root, "y", start, finish) | |
positionAnimator.duration = 100 | |
positionAnimator.addListener(object : Animator.AnimatorListener { | |
override fun onAnimationRepeat(animation: Animator) { | |
} | |
override fun onAnimationEnd(animation: Animator) { | |
root.y = screenSize.y.toFloat() | |
updateScrim() | |
finish() | |
} | |
override fun onAnimationCancel(animation: Animator) { | |
updateScrim() | |
} | |
override fun onAnimationStart(animation: Animator) { | |
} | |
}) | |
positionAnimator.addUpdateListener { | |
updateScrim() | |
} | |
positionAnimator.start() | |
} | |
private fun updateScrim() { | |
val progress = root.y / screenSize.y | |
val alpha = (progress * 255f).toInt() | |
windowScrim.alpha = 255 - alpha | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment