New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature]: over-scroll and nested-scrolling animation in termux terminal-emulator #3826
Comments
What exactly do you mean by "over scroll animation"? |
https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior |
VID_20240213114751.mp4 |
I am not able to play this video. |
Plays well on Google Chrome and Firefox Focus. |
How to implements overscroll stretch animation for custom view on android 12 or later, https://developer.android.com/develop/ui/views/touch-and-input/gestures/scroll#kotlin InteractiveChart sample https://android.googlesource.com/platform/development/+/master/samples/training/InteractiveChart/src/com/example/android/interactivechart/InteractiveLineGraphView.java |
I don't know how to implement this on terminal-emulator |
@RohitVerma882 please refer to the InteractiveChart sample |
@RohitVerma882 My App implments example code snippet // ... imports
open class OverScrollView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr),
GestureDetector.OnGestureListener {
private val scroller: OverScroller
private val gestureDetector: GestureDetector
// Edge effect / overscroll tracking objects.
private val edgeEffectTop: EdgeEffect
private val edgeEffectBottom: EdgeEffect
private val edgeEffectLeft: EdgeEffect
private val edgeEffectRight: EdgeEffect
private var edgeEffectTopActive = false
private var edgeEffectBottomActive = false
private var edgeEffectLeftActive = false
private var edgeEffectRightActive = false
// for example the max scrollX and scrollY
// screen width / 2
private val maxScrollX: Int
get() = context.resources.displayMetrics.widthPixels / 2
// screen height / 2
private val maxScrollY: Int
get() = context.resources.displayMetrics.heightPixels / 2
init {
scroller = OverScroller(context)
gestureDetector = GestureDetector(context, this)
// Sets up edge effects
edgeEffectTop = EdgeEffect(context)
edgeEffectBottom = EdgeEffect(context)
edgeEffectLeft = EdgeEffect(context)
edgeEffectRight = EdgeEffect(context)
}
override fun computeScroll() {
if (scroller.computeScrollOffset()) {
// horizontal absorb
if (
scroller.currX < 0 &&
edgeEffectLeft.isFinished() &&
!edgeEffectLeftActive
) {
edgeEffectLeft.onAbsorb(scroller.currVelocity.toInt())
edgeEffectLeftActive = true
} else if (
scroller.currX > maxScrollX &&
edgeEffectRight.isFinished() &&
!edgeEffectRightActive
) {
edgeEffectRight.onAbsorb(scroller.currVelocity.toInt())
edgeEffectRightActive = true
}
// vertical absorb
if (
scroller.currY < 0 &&
edgeEffectTop.isFinished() &&
!edgeEffectTopActive
) {
edgeEffectTop.onAbsorb(scroller.currVelocity.toInt())
edgeEffectTopActive = true
} else if (
scroller.currY > maxScrollY &&
edgeEffectBottom.isFinished() &&
!edgeEffectBottomActive
) {
edgeEffectBottom.onAbsorb(scroller.currVelocity.toInt())
edgeEffectBottomActive = true
}
scrollTo(
Math.min(Math.max(scroller.currX, 0), maxScrollX),
Math.min(Math.max(scroller.currY, 0), maxScrollY)
)
postInvalidateOnAnimation()
}
}
/**
* Draws the overscroll "glow" at the four edges of the chart region, if necessary. The edges
* of the chart region are stored in {@link #mContentRect}.
*
* @see EdgeEffect
*/
private fun drawEdgeEffect(canvas: Canvas) {
// The methods below rotate and translate the canvas as needed before drawing the glow,
// since the EdgeEffect always draws a top-glow at 0,0.
var needsInvalidate = false
if (!edgeEffectTop.isFinished()) {
val restoreCount = canvas.save()
canvas.translate(0f, 0f)
edgeEffectTop.setSize(getWidth(), getHeight())
if (edgeEffectTop.draw(canvas)) {
needsInvalidate = true
}
canvas.restoreToCount(restoreCount)
}
if (!edgeEffectBottom.isFinished()) {
val restoreCount = canvas.save()
canvas.translate(-getWidth().toFloat(), getHeight().toFloat())
edgeEffectBottom.setSize(getWidth(), getHeight())
canvas.rotate(180f, getWidth().toFloat(), 0f)
if (edgeEffectBottom.draw(canvas)) {
needsInvalidate = true
}
canvas.restoreToCount(restoreCount)
}
if (!edgeEffectLeft.isFinished()) {
val restoreCount = canvas.save()
canvas.translate(0f, getHeight().toFloat())
canvas.rotate(-90f, 0f, 0f);
edgeEffectLeft.setSize(getHeight(), getWidth())
if (edgeEffectLeft.draw(canvas)) {
needsInvalidate = true
}
canvas.restoreToCount(restoreCount)
}
if (!edgeEffectRight.isFinished()) {
val restoreCount = canvas.save()
canvas.translate(getWidth().toFloat(), 0f)
canvas.rotate(90f, 0f, 0f)
edgeEffectRight.setSize(getHeight(), getWidth())
if (edgeEffectRight.draw(canvas)) {
needsInvalidate = true
}
canvas.restoreToCount(restoreCount)
}
if (needsInvalidate) {
postInvalidateOnAnimation()
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// draw the edge effect
drawEdgeEffect(canvas)
}
private fun releaseEdgeEffects() {
edgeEffectTop.onRelease()
edgeEffectBottom.onRelease()
edgeEffectLeft.onRelease()
edgeEffectRight.onRelease()
}
private fun passtiveEdgeEffects() {
edgeEffectTopActive = false
edgeEffectBottomActive = false
edgeEffectLeftActive = false
edgeEffectRightActive = false
}
override fun onTouchEvent(e: MotionEvent): Boolean {
when (e.action) {
MotionEvent.ACTION_DOWN -> {
scroller.abortAnimation()
}
MotionEvent.ACTION_MOVE -> {
// do something
}
MotionEvent.ACTION_UP -> {
// callback the onUp
onUp(e)
}
}
gestureDetector.onTouchEvent(e)
return true
}
override fun onDown(e: MotionEvent): Boolean {
// when the user touches the screen
// change the edge effect states
passtiveEdgeEffects()
return true
}
override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
scroller.startScroll(
scroller.currX,
scroller.currY,
if(Math.abs(distanceX) > Math.abs(distanceY)) distanceX.toInt() else 0,
if(Math.abs(distanceY) > Math.abs(distanceX)) distanceY.toInt() else 0,
0
)
// vertical stretch overscroll effect
if (scroller.currY + distanceY < 0f) {
edgeEffectTop.onPullDistance(-distanceY / getHeight(), 1 - e2.getX() / getWidth())
edgeEffectTopActive = true
} else if (scroller.currY + distanceY > maxScrollY.toFloat()) {
edgeEffectBottom.onPullDistance(distanceY / getHeight(), e2.getX() / getWidth())
edgeEffectBottomActive = true
}
// horizontal stretch overscroll effect
if (scroller.currX + distanceX < 0f) {
edgeEffectLeft.onPullDistance(-distanceX / getWidth(), e2.getY() / getHeight())
edgeEffectLeftActive = true
} else if (scroller.currX + distanceX > maxScrollX.toFloat()) {
edgeEffectRight.onPullDistance(distanceX / getWidth(), e2.getY() / getHeight())
edgeEffectRightActive = true
}
return true
}
override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
// Before flinging, stops the current animation.
scroller.forceFinished(true)
scroller.fling(
// Current scroll position
scrollX,
scrollY,
if(Math.abs(velocityX) > Math.abs(velocityY)) -velocityX.toInt() else 0,
if(Math.abs(velocityY) > Math.abs(velocityX)) -velocityY.toInt() else 0,
/*
* Minimum and maximum scroll positions. The minimum scroll
* position is generally 0 and the maximum scroll position
* is generally the content size less the screen size. So if the
* content width is 2000 pixels and the screen width is 1200
* pixels, the maximum scroll offset is 800 pixels.
*/
0, maxScrollX,
0, maxScrollY,
// The edges of the content. This comes into play when using
// the EdgeEffect class to draw "glow" overlays.
getWidth() / 10,
getHeight() / 10
)
postInvalidateOnAnimation()
return true
}
private fun onUp(e: MotionEvent) {
// when the user lifts their finger off the screen
// release the edge effects
releaseEdgeEffects()
}
} |
Record_2024-05-16-14-01-36_01748b7c4d72684b5ef41a131992be3c.mp4 |
hi |
Feature description
Add over scroll animation feature in termux terminal for Android 12+ devices
Additional information
In
mt manager
have this featureThe text was updated successfully, but these errors were encountered: