1.实现图片放大
public void scale (float sx, float sy) ;//以(0,0)为中心点,将画布长宽分别变为原来的sx/sy倍
public final void scale (float sx, float sy, float px, float py); //以(px,py)为中心点,将画布长宽分别变为原来的sx/sy倍
2.实现双击放大
2.1使用GestureDetector
private gestureDetector = GestureDetectorCompat(context,gestureListener)
⽤于在点击和⻓按之外,增加其他⼿势的监听,例如双击、滑动。通过在View.onTouchEvent() ⾥调⽤ GestureDetector.onTouchEvent() ,以代理的形式来实现:
override fun onTouchEvent(event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}
GestureDetector的几个回调方法
\
2.2通过GestureDetector.setOnDoubleTapListener(OnDoubleTapListener)来配置双击功能:
gestureDetector.setOnDoubleTapListener(doubleTapListener);
(但其实因为GestureDetector的内部实现导致不用实现该接口)
所以总体代码为:
private val gestureDetector: GestureDetector = GestureDetector(
context, object :GestureDetector.OnGestureListener {
override fun onDown(e: MotionEvent?): Boolean {
return true
}
override fun onShowPress(e: MotionEvent?) {
}
override fun onSingleTapUp(e: MotionEvent?): Boolean {
return true
}
// distanceX: Float为当前事件的点 - 上次事件的点
override fun onScroll(
e1: MotionEvent?,
e2: MotionEvent?,
distanceX: Float,
distanceY: Float
): Boolean {
return true
}
override fun onLongPress(e: MotionEvent?) {
}
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent?,
velocityX: Float,
velocityY: Float
): Boolean {
return true
}
}).apply {
setOnDoubleTapListener(object :GestureDetector.OnDoubleTapListener{
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
}
override fun onDoubleTap(e: MotionEvent?): Boolean {
return true
}
override fun onDoubleTapEvent(e: MotionEvent?): Boolean {
}
})
}
3.实现放大时可以移动
先定义手指滑动时的偏移量
//大图模式下移动时的偏移量
private var extraOffsetX = 0f
private var extraOffsetY = 0f
onDraw中实现偏移效果
onScroll中修改偏移量
4.实现惯性移动
OverScroller⽤于⾃动计算滑动的偏移。常⽤于 onFling() ⽅法中,调⽤ OverScroller.fling() ⽅法来启动惯性滑动的计算:
//模板
val overScroller = OverScroller(context);
override fun onFling(downEvent: MotionEvent,
currentEvent: MotionEvent, velocityX: Float, velocityY:
Float) {
// 初始化滑动
scroller.fling(startX, startY, velocityX, velocityY,
minX, maxX, minY, maxY)
// 下⼀帧刷新
ViewCompat.postOnAnimation(this, this)
return false
}
...
override fun run() {
// 计算此时的位置,并且如果滑动已经结束,就停⽌
if (scroller.computeScrollOffset()) {
// 把此时的位置应⽤于界⾯
offsetX = scroller.currX.toFloat()
offsetY = scroller.currY.toFloat()
invalidate()
// 下⼀帧刷新
ViewCompat.postOnAnimation(this, this)
}
}
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent?,
velocityX: Float,
velocityY: Float
): Boolean {
if (big){
overScroller.fling(extraOffsetX.toInt(), extraOffsetY.toInt(), velocityX.toInt(), velocityY.toInt(),
(- (bitmap.width * bigScale - width) / 2).toInt(),
((bitmap.width * bigScale - width) / 2).toInt(),
(- (bitmap.height * bigScale - height) / 2).toInt(),
((bitmap.height * bigScale - height) / 2).toInt(),
40.dp.toInt(), 40.dp.toInt())
//下一帧到来时执行Runnable
ViewCompat.postOnAnimation(this,this)
}
return false
}
override fun run() {
//计算当前的位置,返回值是惯性运动是否还在进行
if(overScroller.computeScrollOffset()){
//取当前位置
extraOffsetX = overScroller.currX.toFloat()
extraOffsetY = overScroller.currY.toFloat()
invalidate()
ViewCompat.postOnAnimation(this,this)
}
}
5.实现放大移动后缩小恢复到原位置
override fun onDoubleTap(e: MotionEvent): Boolean {
big = !big
if (big){
//实现放大移动后缩小恢复到原位置
extraOffsetX = (1- bigScale / smallScale) * (e.x - width / 2)
extraOffsetY = (1- bigScale / smallScale) * (e.y - height / 2)
extraOffsetX = min(extraOffsetX,(bitmap.width * bigScale - width)/2)
extraOffsetX = max(extraOffsetX,- (bitmap.width * bigScale - width)/2)
extraOffsetY = min(extraOffsetY,(bitmap.height * bigScale - height)/2)
extraOffsetY = max(extraOffsetY,- (bitmap.height * bigScale - height)/2)
scaleAnimator.start()
}else{
scaleAnimator.reverse()
}
return true
}
6.实现双指缩放
ScaleGestureDetector 和ScaleGestureListener
private scaleGestureDetector =ScaleGestureDetector(context, scaleGestureListener)
class HenScaleGestureListener : OnScaleGestureListener {
override fun onScaleBegin(detector:
ScaleGestureDetector): Boolean {
// 捏撑开始
return true
}
override fun onScaleEnd(detector:
ScaleGestureDetector) {
// 捏撑结束
}
override fun onScale(detector: ScaleGestureDetector):Boolean {
// 新的捏撑事件
currentScale *= detector.scaleFactor
// 这个返回值表示「事件是否消耗」,即「这个事件算不算数」
//return true 则scaleFactor表示当前状态放缩系数和前一个状态的比值
//return false则scaleFactor表示当前状态放缩系数和初始状态的比值
return true
}
}
private val scaleGestureDetector = ScaleGestureDetector(context,object : ScaleGestureDetector.OnScaleGestureListener{
override fun onScale(detector: ScaleGestureDetector): Boolean {
val tempCurrentScale = currentScale * detector.scaleFactor
if (tempCurrentScale < smallScale || tempCurrentScale > bigScale){
return false
}else{
currentScale *= detector.scaleFactor
return true
}
// 这个返回值表示「事件是否消耗」,即「这个事件算不算数」
//return true 则scaleFactor表示当前状态放缩系数和前一个状态的比值
//return false则scaleFactor表示当前状态放缩系数和初始状态的比值
return true
}
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
//实现放大移动后缩小恢复到原位置
extraOffsetX = (1- bigScale / smallScale) * (detector.focusX - width / 2)
extraOffsetY = (1- bigScale / smallScale) * (detector.focusY - height / 2)
return true
}
override fun onScaleEnd(detector: ScaleGestureDetector?) {
}
})
override fun onTouchEvent(event: MotionEvent?): Boolean {
scaleGestureDetector.onTouchEvent(event)
if (!scaleGestureDetector.isInProgress){
gestureDetector.onTouchEvent(event)
}
return true
}