Kotlin : ImageView 이미지 확대, 축소, 회전 기능

2023. 2. 2. 20:22[Android APP] feat. Kotlin/Kotlin 공부

문제 상황

Image를 ImageView에 띄어준 뒤, 이미지에 있는 작은 글씨를 보기 위해 이미지 확대/축소 기능이 필요했다.

 

 

해결

1. TouchMode 등 선언

internal enum class TOUCHMODE {
    NONE,
    SINGLE,
    MULTI
}
private var touchMode: TOUCH_MODE? = null
private var matrix : Matrix? = null
private var savedMatrix : Matrix? = null
private var startPoint: PointF? = null
private var midPoint : PointF? = null
private var oldDistance = 0f
private var oldDegree = 0.0

2. 이미지 확대/축소 실행

matrix = Matrix()
savedMatrix = Matrix()
binding.blueprintImage.setOnTouchListener(onTouch)
binding.blueprintImage.scaleType = ImageView.ScaleType.MATRIX

3. 이미지 확대/축소 함수

@SuppressLint("ClickableViewAccessibility")
private val onTouch = OnTouchListener { v, event ->
    if (v == binding.blueprintImage) {
        val action = event.action
        when (action and MotionEvent.ACTION_MASK) {
            //한 손가락 터치
            MotionEvent.ACTION_DOWN -> {
                touchMode = TOUCH_MODE.SINGLE
                donwSingleEvent(event)
            }
            //두 손가락 터치
            MotionEvent.ACTION_POINTER_DOWN -> if (event.pointerCount == 2) { 
                touchMode = TOUCH_MODE.MULTI
                downMultiEvent(event)
            }
            //한 손가락 이동
            MotionEvent.ACTION_MOVE -> if (touchMode === TOUCH_MODE.SINGLE) {
                moveSingleEvent(event)
            } 
            //두 손가락 이동
            else if (touchMode === TOUCH_MODE.MULTI) {
                moveMultiEvent(event)
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> touchMode = TOUCH_MODE.NONE
        }
    }
    true
}

 

  • 두 손가락 간 중간점을 찾아주는 함수
private fun getMidPoint(e: MotionEvent): PointF? {
    val x = (e.getX(0) + e.getX(1)) / 2
    val y = (e.getY(0) + e.getY(1)) / 2
    return PointF(x, y)
}

 

  • 각 손가락 간 거리를 구해주는 함수
private fun getDistance(e: MotionEvent): Float {
    val x = e.getX(0) - e.getX(1)
    val y = e.getY(0) - e.getY(1)
    return Math.sqrt((x * x + y * y).toDouble()).toFloat()
}

 

  • 한손가락, 두 손가락으로 터치했을 때 시작점을 구하는 함수
private fun donwSingleEvent(event: MotionEvent) {
    savedMatrix!!.set(matrix)
    startPoint = PointF(event.x, event.y)
}
private fun downMultiEvent(event: MotionEvent) {
    oldDistance = getDistance(event)
    if (oldDistance > 5f) {
        savedMatrix!!.set(matrix)
        midPoint = getMidPoint(event)
        val radian = atan2((event.y - midPoint!!.y).toDouble(), (event.x - midPoint!!.x).toDouble())
        oldDegree = radian * 180 / Math.PI
    }
}

 

  • 한 손가락, 두 손가락으로 이동 및 회전하는 함수

(본인은 회전하는 기능이 불필요 했기 때문에 degree 대신 0.0.toFloat() 값을 넣어줘서 회전을 막았다.)

private fun moveSingleEvent(event: MotionEvent) {
    matrix!!.set(savedMatrix)
    matrix!!.postTranslate(event.x - startPoint!!.x, event.y - startPoint!!.y)
    binding.blueprintImage.imageMatrix = matrix
}

private fun moveMultiEvent(event: MotionEvent) {
    val newDistance = getDistance(event)
    if (newDistance > 5f) {
        matrix!!.set(savedMatrix)
        val scale = newDistance / oldDistance
        matrix!!.postScale(scale, scale, midPoint!!.x, midPoint!!.y)
        val nowRadian =
            Math.atan2((event.y - midPoint!!.y).toDouble(), (event.x - midPoint!!.x).toDouble())
        val nowDegress = nowRadian * 180 / Math.PI
        val degree = (nowDegress - oldDegree).toFloat()
        matrix!!.postRotate(degree, midPoint!!.x, midPoint!!.y)
        binding.blueprintImage.imageMatrix = matrix
    }
}

 

반응형