Search code examples
androidkotlintouch

I am getting android-studio warnings for "Custom View 'ImageView' has setOnTouchListener called on it but doesn't override performClick",


It irritates me because I have to see yellow line in my code each time I open class.

I have also added @SuppressLint("ClickableViewAccessibility") above onTouch.

My MultiTouchListener class :

open class MultiTouchListener : OnTouchListener {
    var maximumScale: Float = 0.toFloat()
    var minimumScale: Float = 0.toFloat()
    var rotateEnabled: Boolean = false
    var scaleEnabled: Boolean = false
    var translateEnabled: Boolean = false
    private var onTouch: OnTouch? = null
    private var rotateListener: OnRotateListener? = null
    private var activePointerId: Int = 0
    private var prevX: Float = 0.toFloat()
    private var prevY: Float = 0.toFloat()
    private var rect: Rect? = null
    private var scaleGestureDetector: ScaleGestureDetector? = null
    private var _root: StickerView? = null
    private var imgViewFrame: ImageView? = null

    constructor(isRotateEnabled: Boolean, isTranslateEnabled: Boolean, isScaleEnabled: Boolean, imgViewFrame: ImageView, _root: StickerView) {
        this.minimumScale = 0.0f
        this.maximumScale = 10.0f
        this.activePointerId = INVALID_POINTER_ID
        this.rotateEnabled = isRotateEnabled
        this.scaleEnabled = isScaleEnabled
        this.translateEnabled = isTranslateEnabled
        this.imgViewFrame = imgViewFrame
        this.scaleGestureDetector = ScaleGestureDetector(ScaleGestureListener())
        this._root = _root
    }

    constructor(isRotateEnabled: Boolean, isTranslateEnabled: Boolean, isScaleEnabled: Boolean, rotateListener: OnRotateListener) {
        this.minimumScale = 0.5f
        this.maximumScale = 10.0f
        this.activePointerId = INVALID_POINTER_ID
        this.rotateEnabled = isRotateEnabled
        this.scaleEnabled = isScaleEnabled
        this.translateEnabled = isTranslateEnabled
        this.scaleGestureDetector = ScaleGestureDetector(ScaleGestureListener())
        this.rotateListener = rotateListener
    }

    constructor() {
        this.rotateEnabled = true
        this.translateEnabled = true
        this.scaleEnabled = true
        this.minimumScale = 0.5f
        this.maximumScale = 10.0f
        this.activePointerId = INVALID_POINTER_ID
        this.scaleGestureDetector = ScaleGestureDetector(ScaleGestureListener())
    }

    constructor(onTouch: OnTouch) {
        this.rotateEnabled = true
        this.translateEnabled = true
        this.scaleEnabled = true
        this.minimumScale = 0.5f
        this.maximumScale = 10.0f
        this.activePointerId = INVALID_POINTER_ID
        this.scaleGestureDetector = ScaleGestureDetector(ScaleGestureListener())
        this.onTouch = onTouch
    }

    private fun move(view: View, info: TransformInfo) {
        computeRenderOffset(view, info.pivotX, info.pivotY)
        adjustTranslation(view, info.deltaX, info.deltaY)
        val scale = Math.max(info.minimumScale, Math.min(info.maximumScale, view.scaleX * info.deltaScale))
        view.scaleX = scale
        view.scaleY = scale
        view.rotation = adjustAngle(view.rotation + info.deltaAngle)
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouch(view: View, event: MotionEvent): Boolean {
        var newPointerIndex = 0
        this.scaleGestureDetector!!.onTouchEvent(view, event)
        if (this.translateEnabled) {
            val action = event.action
            val pointerIndex: Int
            when (event.actionMasked and action) {
                MotionEvent.ACTION_DOWN -> {
                    when {
                        this.onTouch != null -> this.onTouch!!.onTouchDown()
                    }
                    this.prevX = event.x
                    this.prevY = event.y
                    this.rect = Rect(view.left, view.top, view.right, view.bottom)
                    this.activePointerId = event.getPointerId(0)
                    imgViewFrame?.alpha = .5f
                    removeGalleryView()
                }
                MotionEvent.ACTION_UP -> {
                    this.activePointerId = INVALID_POINTER_ID
                    imgViewFrame?.alpha = 1f
                }
                MotionEvent.ACTION_MOVE -> {
                    pointerIndex = event.findPointerIndex(this.activePointerId)
                    when {
                        pointerIndex != INVALID_POINTER_ID -> {
                            val currX = event.getX(pointerIndex)
                            val currY = event.getY(pointerIndex)
                            when {
                                !this.scaleGestureDetector!!.isInProgress -> adjustTranslation(view, currX - this.prevX, currY - this.prevY)
                            }
                        }
                    }
                }
                MotionEvent.ACTION_CANCEL -> this.activePointerId = INVALID_POINTER_ID
                MotionEvent.ACTION_POINTER_UP -> {
                    pointerIndex = 65280 and action shr 8
                    when {
                        event.getPointerId(pointerIndex) == this.activePointerId -> {
                            when (pointerIndex) {
                                0 -> newPointerIndex = 1
                            }
                            this.prevX = event.getX(newPointerIndex)
                            this.prevY = event.getY(newPointerIndex)
                            this.activePointerId = event.getPointerId(newPointerIndex)
                        }
                    }
                }
            }
        }
        return true
    }

    interface OnRotateListener {
        fun getRotation(f: Float): Float
    }

    interface OnTouch {
        fun onTouchDown()
    }

    private inner class ScaleGestureListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
        private var mPivotX: Float = 0.toFloat()
        private var mPivotY: Float = 0.toFloat()
        private val mPrevSpanVector: Vector2D = Vector2D()

        override fun onScaleBegin(view: View, scaleGestureDetector: ScaleGestureDetector): Boolean {
            this.mPivotX = scaleGestureDetector.focusX
            this.mPivotY = scaleGestureDetector.focusY
            this.mPrevSpanVector.set(scaleGestureDetector.currentSpanVector)
            return true
        }

        override fun onScale(view: View, scaleGestureDetector: ScaleGestureDetector): Boolean {
            var angle: Float = when {
                [email protected] -> Vector2D.getAngle(this.mPrevSpanVector, scaleGestureDetector.currentSpanVector)
                else -> 0.0f
            }
            var f = 0.0f
            val info = TransformInfo()
            info.deltaScale = if ([email protected]) scaleGestureDetector.scaleFactor else 1.0f
            info.deltaAngle = angle
            angle = when {
                [email protected] -> scaleGestureDetector.focusX - this.mPivotX
                else -> 0.0f
            }
            info.deltaX = angle
            when {
                [email protected] -> f = scaleGestureDetector.focusY - this.mPivotY
            }
            info.deltaY = f
            info.pivotX = this.mPivotX
            info.pivotY = this.mPivotY
            info.minimumScale = [email protected]
            info.maximumScale = [email protected]
            [email protected](view, info)
            return false
        }
    }

    private inner class TransformInfo {
        var deltaAngle: Float = 0.toFloat()
        var deltaScale: Float = 0.toFloat()
        var deltaX: Float = 0.toFloat()
        var deltaY: Float = 0.toFloat()
        var maximumScale: Float = 0.toFloat()
        var minimumScale: Float = 0.toFloat()
        var pivotX: Float = 0.toFloat()
        var pivotY: Float = 0.toFloat()
    }

    companion object {
        private const val INVALID_POINTER_ID = -1

        private fun adjustAngle(degrees: Float): Float {
            return when {
                degrees > 180.0f -> degrees - 360.0f
                else -> when {
                    degrees < -180.0f -> degrees + 360.0f
                    else -> degrees
                }
            }
        }

        private fun adjustTranslation(view: View, deltaX: Float, deltaY: Float) {
            val deltaVector = floatArrayOf(deltaX, deltaY)
            view.matrix.mapVectors(deltaVector)
            view.translationX = view.translationX + deltaVector[0]
            view.translationY = view.translationY + deltaVector[1]
        }

        private fun computeRenderOffset(view: View, pivotX: Float, pivotY: Float) {
            when {
                view.pivotX != pivotX || view.pivotY != pivotY -> {
                    val prevPoint = floatArrayOf(0.0f, 0.0f)
                    view.matrix.mapPoints(prevPoint)
                    view.pivotX = pivotX
                    view.pivotY = pivotY
                    val currPoint = floatArrayOf(0.0f, 0.0f)
                    view.matrix.mapPoints(currPoint)
                    val offsetY = currPoint[1] - prevPoint[1]
                    view.translationX = view.translationX - (currPoint[0] - prevPoint[0])
                    view.translationY = view.translationY - offsetY
                }
            }
        }
    }
}

I am calling it like this:

        private var myTouchView1: ImageView? = null

        myTouchView1 = findViewById(R.id.myTouchView1)
        myTouchView1!!.setOnTouchListener(
                object : MultiTouchListener(true, true, true, imgViewBG!!, stickerView!!) {

                })

I understand that it is about overriding performClick, but where to override it? I am using ImageView Class.


Solution

  • I had this problem with my TextView while applying OnTOuchListener on it, so what I did is, I created a custom TextVIew class like this,

        public class AppTextViewRegular extends TextView {
    
        private Context context;
    
        public AppTextViewRegular(Context context) {
            super(context);
            this.context = context;
    
        }
    
        public AppTextViewRegular(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.context = context;
        }
    
        public void setSize(float size) {
            setTextSize(size);
        }
    
        @Override
        public boolean performClick() {
            return true;
        }
    }
    

    And added performClick() in it (as you can see in my code). Used it in my XML and Java code. And the warning was gone.