Android 双击缩放使图像向图像中心缩放

Android 双击缩放使图像向图像中心缩放,android,android-layout,kotlin,pinchzoom,Android,Android Layout,Kotlin,Pinchzoom,目前,我已经实现了一个自定义类,该类实现了AppCompatImageView、OnGetureListener和OnDoubleTapListener,以构建我自己的ImageView,在本文的帮助下,该ImageView可以通过收缩来放大或缩小 这里我缺少的是,当用户双击图像的一角时,默认情况下图像会向图像的中心缩放。如何确保双击时考虑到点击坐标以缩放到该坐标 这是我的TouchImageView课程 class TouchImageView : androidx.appcompat.wid

目前,我已经实现了一个自定义类,该类实现了AppCompatImageView、OnGetureListener和OnDoubleTapListener,以构建我自己的ImageView,在本文的帮助下,该ImageView可以通过收缩来放大或缩小

这里我缺少的是,当用户双击图像的一角时,默认情况下图像会向图像的中心缩放。如何确保双击时考虑到点击坐标以缩放到该坐标

这是我的TouchImageView课程

class TouchImageView : androidx.appcompat.widget.AppCompatImageView, GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {

var matrix1: Matrix? = null
var mode = NONE

// Remember some things for zooming
var last = PointF()
var start = PointF()
var minScale = 1f
var maxScale = 3f
var m: FloatArray? = null
var viewWidth = 0
var viewHeight = 0
var saveScale = 1f
protected var origWidth = 0f
protected var origHeight = 0f
var oldMeasuredWidth = 0
var oldMeasuredHeight = 0
var mScaleDetector: ScaleGestureDetector? = null
//    var context: Context? = null
var context1 : Context? = null

constructor(context: Context) : super(context) {
    sharedConstructing(context)
}

constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
    sharedConstructing(context)
}

var mGestureDetector: GestureDetector? = null
private fun sharedConstructing(context: Context) {
    super.setClickable(true)
    this.context1 = context
    mGestureDetector = GestureDetector(context, this)
    mGestureDetector!!.setOnDoubleTapListener(this)
    mScaleDetector = ScaleGestureDetector(context, ScaleListener())
    matrix1 = Matrix()
    m = FloatArray(9)
    imageMatrix = matrix1
    scaleType = ScaleType.MATRIX
    setOnTouchListener { v, event ->
        mScaleDetector!!.onTouchEvent(event)
        mGestureDetector!!.onTouchEvent(event)
        val curr = PointF(event.x, event.y)
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                last.set(curr)
                start.set(last)
                mode = DRAG
            }
            MotionEvent.ACTION_MOVE -> if (mode == DRAG) {
                val deltaX = curr.x - last.x
                val deltaY = curr.y - last.y
                val fixTransX = getFixDragTrans(
                    deltaX, viewWidth.toFloat(),
                    origWidth * saveScale
                )
                val fixTransY = getFixDragTrans(
                    deltaY, viewHeight.toFloat(),
                    origHeight * saveScale
                )
                matrix1!!.postTranslate(fixTransX, fixTransY)
                fixTrans()
                last[curr.x] = curr.y
            }
            MotionEvent.ACTION_UP -> {
                mode = NONE
                val xDiff = Math.abs(curr.x - start.x).toInt()
                val yDiff = Math.abs(curr.y - start.y).toInt()
                if (xDiff < CLICK && yDiff < CLICK) performClick()
            }
            MotionEvent.ACTION_POINTER_UP -> mode = NONE
        }
        imageMatrix = matrix1
        invalidate()
        true // indicate event was handled
    }
}

fun setMaxZoom(x: Float) {
    maxScale = x
}

override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
    return false
}

override fun onDoubleTap(e: MotionEvent): Boolean {
    // Double tap is detected
    Log.i("MAIN_TAG", "Double tap detected")
    val origScale = saveScale
    val mScaleFactor: Float
    if (saveScale == maxScale) {
        saveScale = minScale
        mScaleFactor = minScale / origScale
    } else {
        saveScale = maxScale
        mScaleFactor = maxScale / origScale
    }
    matrix1!!.postScale(
        mScaleFactor, mScaleFactor, (viewWidth / 2).toFloat(), (
                viewHeight / 2).toFloat()
    )
    fixTrans()
    return false
}

override fun onDoubleTapEvent(e: MotionEvent): Boolean {
    return false
}

override fun onDown(e: MotionEvent): Boolean {
    return false
}

override fun onShowPress(e: MotionEvent) {}
override fun onSingleTapUp(e: MotionEvent): Boolean {
    return false
}

override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
    return false
}

override fun onLongPress(e: MotionEvent) {}
override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
    return false
}

private inner class ScaleListener : SimpleOnScaleGestureListener() {
    override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
        mode = ZOOM
        return true
    }

    override fun onScale(detector: ScaleGestureDetector): Boolean {
        var mScaleFactor = detector.scaleFactor
        val origScale = saveScale
        saveScale *= mScaleFactor
        if (saveScale > maxScale) {
            saveScale = maxScale
            mScaleFactor = maxScale / origScale
        } else if (saveScale < minScale) {
            saveScale = minScale
            mScaleFactor = minScale / origScale
        }
        if (origWidth * saveScale <= viewWidth
            || origHeight * saveScale <= viewHeight
        ) matrix1!!.postScale(
            mScaleFactor, mScaleFactor, (viewWidth / 2).toFloat(), (
                    viewHeight / 2).toFloat()
        ) else matrix1!!.postScale(
            mScaleFactor, mScaleFactor,
            detector.focusX, detector.focusY
        )
        fixTrans()
        return true
    }
}

fun fixTrans() {
    matrix1!!.getValues(m)
    val transX = m!![Matrix.MTRANS_X]
    val transY = m!![Matrix.MTRANS_Y]
    val fixTransX = getFixTrans(transX, viewWidth.toFloat(), origWidth * saveScale)
    val fixTransY = getFixTrans(
        transY, viewHeight.toFloat(), origHeight
                * saveScale
    )
    if (fixTransX != 0f || fixTransY != 0f) matrix1!!.postTranslate(fixTransX, fixTransY)
}

fun getFixTrans(trans: Float, viewSize: Float, contentSize: Float): Float {
    val minTrans: Float
    val maxTrans: Float
    if (contentSize <= viewSize) {
        minTrans = 0f
        maxTrans = viewSize - contentSize
    } else {
        minTrans = viewSize - contentSize
        maxTrans = 0f
    }
    if (trans < minTrans) return -trans + minTrans
    return if (trans > maxTrans) -trans + maxTrans else 0f
}

private fun getFixDragTrans(delta: Float, viewSize: Float, contentSize: Float): Float {
    return if (contentSize <= viewSize) {
        0f
    } else delta
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    viewWidth = MeasureSpec.getSize(widthMeasureSpec)
    viewHeight = MeasureSpec.getSize(heightMeasureSpec)

    //
    // Rescales image on rotation
    //
    if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight || viewWidth == 0 || viewHeight == 0) return
    oldMeasuredHeight = viewHeight
    oldMeasuredWidth = viewWidth
    if (saveScale == 1f) {
        // Fit to screen.
        val scale: Float
        val drawable = drawable
        if (drawable == null || drawable.intrinsicWidth == 0 || drawable.intrinsicHeight == 0) return
        val bmWidth = drawable.intrinsicWidth
        val bmHeight = drawable.intrinsicHeight
        Log.d("bmSize", "bmWidth: $bmWidth bmHeight : $bmHeight")
        val scaleX = viewWidth.toFloat() / bmWidth.toFloat()
        val scaleY = viewHeight.toFloat() / bmHeight.toFloat()
        scale = Math.min(scaleX, scaleY)
        matrix1!!.setScale(scale, scale)

        // Center the image
        var redundantYSpace = (viewHeight.toFloat()
                - scale * bmHeight.toFloat())
        var redundantXSpace = (viewWidth.toFloat()
                - scale * bmWidth.toFloat())
        redundantYSpace /= 2.toFloat()
        redundantXSpace /= 2.toFloat()
        matrix1!!.postTranslate(redundantXSpace, redundantYSpace)
        origWidth = viewWidth - 2 * redundantXSpace
        origHeight = viewHeight - 2 * redundantYSpace
        imageMatrix = matrix1
    }
    fixTrans()
}

companion object {
    // We can be in one of these 3 states
    const val NONE = 0
    const val DRAG = 1
    const val ZOOM = 2
    const val CLICK = 3
}
class TouchImageView:androidx.appcompat.widget.AppCompatImageView、GestureDetector.OnGetureListener、GestureDetector.OnDoubleTapListener{
var matrix1:矩阵?=null
var模式=无
//记住一些关于缩放的事情
var last=PointF()
var start=PointF()
var minScale=1f
var maxScale=3f
变量m:FloatArray?=null
var viewWidth=0
var viewHeight=0
var saveScale=1f
受保护变量origWidth=0f
受保护的var origHeight=0f
var oldMeasuredWidth=0
var oldMeasuredHeight=0
var mScaleDetector:ScaleGetStureDetector?=null
//变量上下文:上下文?=null
var context1:上下文?=null
构造函数(上下文:上下文):超级(上下文){
共享构造(上下文)
}
构造函数(context:context,attrs:AttributeSet?):super(context,attrs){
共享构造(上下文)
}
var mGestureDetector:GestureDetector?=null
私有趣味共享构造(上下文:上下文){
super.setClickable(真)
this.context1=context
mGestureDetector=GestureDetector(上下文,此)
mGestureDetector!!.setOnDoubleTapListener(此)
mScaleDetector=scalegestruedetector(上下文,ScaleListener())
矩阵1=矩阵()
m=浮点数组(9)
imageMatrix=matrix1
scaleType=scaleType.MATRIX
setOnTouchListener{v,事件->
mScaleDetector!!.onTouchEvent(事件)
mGestureDetector!!.onTouchEvent(事件)
val curr=PointF(event.x,event.y)
何时(事件、动作){
MotionEvent.ACTION\u向下->{
最后一组(当前)
开始。设置(最后一个)
模式=拖动
}
MotionEvent.ACTION\u MOVE->if(模式==拖动){
val deltaX=当前x-最后x
val deltaY=当前y-最后y
val fixtranx=getfixtragtrans(
deltaX,viewWidth.toFloat(),
原始宽度*保存比例
)
val fixTransY=getfixtragtrans(
deltaY,viewHeight.toFloat(),
origHeight*保存比例
)
matrix1!!.postTranslate(fixtranx,fixtrany)
fixTrans()
最后一次[当前x]=当前
}
MotionEvent.ACTION\u UP->{
模式=无
val xDiff=Math.abs(curr.x-start.x).toInt()
val yDiff=Math.abs(curr.y-start.y).toInt()
if(xDiff模式=无
}
imageMatrix=matrix1
使无效
true//指示事件已处理
}
}
fun setMaxZoom(x:Float){
最大刻度=x
}
override fun OnSingleTapConfiged(e:MotionEvent):布尔值{
返回错误
}
override fun onDoubleTap(e:MotionEvent):布尔值{
//检测到双抽头
Log.i(“主标签”,“检测到双击”)
val origScale=saveScale
val mScaleFactor:浮点
如果(saveScale==maxScale){
saveScale=minScale
mScaleFactor=最小刻度/原始刻度
}否则{
saveScale=maxScale
mScaleFactor=最大刻度/原始刻度
}
matrix1!!.postScale(
mScaleFactor,mScaleFactor,(viewWidth/2).toFloat()(
viewHeight/2).toFloat()
)
fixTrans()
返回错误
}
重写DoubleTapeEvent(e:MotionEvent):布尔值{
返回错误
}
override fun onDown(e:MotionEvent):布尔值{
返回错误
}
在ShowPress(e:MotionEvent){}
override fun onSingleTapUp(e:MotionEvent):布尔值{
返回错误
}
覆盖趣味onScroll(e1:MotionEvent,e2:MotionEvent,distanceX:Float,distanceY:Float):布尔值{
返回错误
}
重写fun onLongPress(e:MotionEvent){}
重写fun onFling(e1:MotionEvent,e2:MotionEvent,velocityX:Float,velocityY:Float):布尔值{
返回错误
}
私有内部类ScaleListener:SimpleOnScaleGetStureListener(){
覆盖SCALEBEGIN(检测器:SCALEGSTUREDETECTOR):布尔值{
模式=缩放
返回真值
}
在刻度上覆盖乐趣(检测器:scalegestruedetector):布尔值{
var mScaleFactor=detector.scaleFactor
val origScale=saveScale
saveScale*=mScaleFactor
如果(保存比例>最大比例){
saveScale=maxScale
mScaleFactor=最大刻度/原始刻度
}else if(保存比例<最小比例){
saveScale=minScale
mScaleFactor=最小刻度/原始刻度
}
如果(origWidth*saveScale您尝试过吗

我可以想象它具有您所需的所有功能,并且维护良好

谢谢此库在我的应用程序中运行良好