Search code examples
javaandroidkotlinandroid-activityandroid-touch-event

OnTouch giving different position, compared to ImageView position


I have many ImageViews defined programmatically, and they have their positions in arrays, like that:

const1Positions = arrayOf(
  Point(dpToPx(349), dpToPx(258)),
  Point(dpToPx(491), dpToPx(302)), 
  Point(dpToPx(495), dpToPx(429)),
  Point(dpToPx(669), dpToPx(524)), 
  Point(dpToPx(600), dpToPx(618))
)

Here is dpToPx:

fun Activity.dpToPx(dp: Int): Int {
  return TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP,
    dp.toFloat(), 
    resources.displayMetrics
  ).roundToInt()
}

I'm trying to setOnTouchListener to every ImageView (when I initialize them inside a for, I also call imageview.setOnTouchListener...)

But my touch isn't recognized. I also tried, instead of adding an onTouchListener to every ImageView, add the onTouchEvent in the main view and, if the event.x == imageview.x (the user touched the ImageView), do the actions. But the event.x and image.x are different.

Here's my setOnTouchListener:

view.setOnTouchListener { v, event ->
    when (event.actionMasked) {
      MotionEvent.ACTION_DOWN -> {
        Log.d("DEBUG_TAG", event.x.toString())
        true
      }
      MotionEvent.ACTION_UP -> {
        Log.d("DEBUG_TAG", "Action was UP")
        Log.d("test", const1Positions[0].x.toString())
        Log.d("test2", view.width.toString())
        true
      }
      MotionEvent.ACTION_MOVE -> {
        Log.d("DEBUG_TAG", "Action was MOVE")
        true
      }
      MotionEvent.ACTION_CANCEL -> {
        Log.d("DEBUG_TAG", "Action was CANCEL")
        true
      }
      MotionEvent.ACTION_OUTSIDE -> {
        Log.d(
          "DEBUG_TAG",
          "Movement occurred outside bounds of current screen element"
        )
        true
      }
      else -> super.onTouchEvent(event)
    }
}

My layout width and height are both 2 times bigger than the screen, and I can zoom in/out and scroll, but I'm not using ScrollView. I'm using a custom Layout available on GitHub.

params.width = view.resources.displayMetrics.widthPixels * 2
params.height = view.resources.displayMetrics.heightPixels * 2
view.layoutParams = params

I'm using Log to compare the touch position, the ImageView position and the layout size. But the results are completely different:

2020-03-25 19:31:07.796 26112-26112/com.example.android.bonte_android D/DEBUG_TAG: 395.63367
2020-03-25 19:31:07.833 26112-26112/com.example.android.bonte_android D/test: 890
2020-03-25 19:31:07.834 26112-26112/com.example.android.bonte_android D/test2: 2160

The screen position is based on 2160, so It shows 890. But even when I touch on the screen, the event.x position shows 395 instead of 890, and the maximum position that event.x receives is 1080 (the real phone width), and not 2160 (the layout maximum width). Does anyone know why this happens?

Instead of adding onTouchListener to View, It'd be better to add to all of the ImageViews, but when I do that, as I said, onTouchListener doesn't recognize any touch,


Solution

  • I hope this answer (by Piyush) will satisfy you:

    MotionEvent will sometimes return absolute X and Y coordinates relative to the view, and sometimes relative coordinates to the previous motion event.

    getRawX() and getRawY() that is guaranteed to return absolute coordinates, relative to the device screen.

    While getX() and getY(), should return you coordinates, relative to the View, that dispatched them.

    UPD: adding to ZoomLayout in XML property app:hasClickableChildren="true" fix the issue.