继续scoller 和惯性滑动view,上一篇是用GestureListener来进行监听,这里我们使用原生的onTouch事件来获取手势的操作。
不同如下
- 1.手势获取监听不同。
- 2.重新绘制的机制不同,前面是使用的postAnimation()来运行runbale实现滚动重绘,这里使用computeScroll()方法来实现重新绘制。这个方法会在view进行重新绘制时候被进行调用。
贴代码:
import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.view.animation.Interpolator
import android.view.animation.LinearInterpolator
import android.widget.ScrollView
import android.widget.Scroller
import view.NaughtyChild.myview.R
import kotlin.math.abs
import kotlin.math.max
class CustomTouchView : View {
val bitmap = BitmapFactory.decodeResource(resources, R.mipmap.mountain)
val velocityTracker = VelocityTracker.obtain()
private val sQuinticInterpolator = Interpolator { t ->
var tempT = t
tempT -= 1.0f
tempT * tempT * tempT * tempT * tempT + 1.0f
}
val decelerateInterpolator: DecelerateInterpolator = DecelerateInterpolator(1f)
val scroller = Scroller(context, decelerateInterpolator)
var downX = 0
var downY = 0
var isFling = false
var oldMoveX = 0
var oldMoveY = 0
var oldScrollX = 0
var oldScrollY = 0
val maxSpeed = 800
var upX = 0
var upY = 0
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun onTouchEvent(event: MotionEvent?): Boolean {
val action = event!!.actionMasked
velocityTracker.addMovement(event)
when (action) {
MotionEvent.ACTION_DOWN -> {
downX = event.x.toInt()
downY = event.y.toInt()
oldMoveX = event.x.toInt()
oldMoveY = event.y.toInt()
Log.d("CustomTouchView", "ACTION_DOWN: downx=$downX,downy=$downY");
}
MotionEvent.ACTION_UP -> {
upX = event.x.toInt()
upY = event.y.toInt()
downY = 0
downX = 0
velocityTracker.computeCurrentVelocity(1000, maxSpeed.toFloat())//每秒像素数
var xSpeed = velocityTracker.xVelocity
var ySpeed = velocityTracker.yVelocity
Log.d("CustomTouchView", "ACTION_UP: $xSpeed,$ySpeed");
if (abs(xSpeed) > 400 || abs(ySpeed) > 400) {
isFling = true
this.doFling(oldMoveX, oldMoveY, -xSpeed.toInt(), -ySpeed.toInt())
}
oldMoveY = 0
oldMoveX = 0
}
MotionEvent.ACTION_MOVE -> {
Log.d("CustomTouchView", " ACTION_MOVE: movex=${event.x},moveY=${event.y}");
Log.d("CustomTouchView", " ACTION_MOVE: downx=$downX,downy=$downY");
val dx = event.x.toInt() - oldMoveX
val dy = event.y.toInt() - oldMoveY
scrollBy(-dx, -dy)
Log.d("CustomTouchView", "ACTION_MOVE: dx=$dx,dy=$dy");
oldMoveX = event.x.toInt()
oldMoveY = event.y.toInt()
}
}
return true
}
private fun doFling(oldx: Int, oldY: Int, xspeed: Int, yseed: Int) {
Log.d("CustomTouchView", "doFling:xspeed${xspeed},yspeed=${yseed} ");
scroller.fling(0, 0, xspeed, yseed, Int.MIN_VALUE, Int.MAX_VALUE, Int.MIN_VALUE, Int.MAX_VALUE)
invalidate()
}
override fun draw(canvas: Canvas) {
super.draw(canvas)
canvas.drawBitmap(bitmap, 0f, 0f, null)
}
override fun computeScroll() {//本方法在进行重新绘制时候被调用,所以只要我们在这里方法里面使用重绘,就会被重新调用。使用isFling作为是否重新绘制的开关。
if (!isFling) return
val scrolling = scroller.computeScrollOffset()
Log.d("CustomTouchView", "computeScroll:$scrolling ");
if (scrolling) {
Log.d("CustomTouchView", "computeScroll: getCurrX=${scroller.getCurrX()},getCurrY=${scroller.getCurrY()}");
Log.d("CustomTouchView", "computeScroll: ${scroller.getCurrX() - upX},${scroller.getCurrY() - upY}");
scrollBy(scroller.getCurrX(), scroller.getCurrY());
invalidate();
} else {
isFling = false
}
}
}