I need to get the position, width and height of image inside ImageView after the scale has changed. I need the values to add code to control the scrolling limits. I has seen other threads that use a Matrix mechanism but in my case they did not apply because my image does goes beyond the ImageView on purpose since the scale change is to zoom image 2 and 3 times.
What I need is to keep the image not to show empty space when scrolling. For instance the top left corner of the image can't go below the top border of the view nor go far right of the left border of the view. Similar on the other corners, the image can't go over the bottom border nor far left of the right border, etc.
When I do pdfview.x and pdfview.width etc. the values are giving me the original value. I could get the width and height by math but can't do it with the position as it will change when scrolling.
I tried getting the bounds but it also gives me the original values.
Bounds code:
var bounds: RectF = getImageBounds(pdfview)
fun getImageBounds(imageView: ImageView): RectF {
val bounds = RectF()
val drawable = imageView.drawable
if (drawable != null) {
imageView.imageMatrix.mapRect(bounds, RectF(drawable.bounds))
}
return bounds
}
Zoom code:
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
pdfview = binding.pdfview
slider = binding.slider
slider.addOnChangeListener { slider, value, fromUser ->
// Responds to when slider's value is changed
pdfview.scaleX = 1 + slider.value / 100
pdfview.scaleY = 1 + slider.value / 100
}
PAN code:
var preX: Float = pdfview.x
var preY: Float = pdfview.y
pdfview.setOnTouchListener { v, event ->
val currentX: Float
val currentY: Float
when (event.action) {
MotionEvent.ACTION_DOWN -> {
preX = event.x
preY = event.y
}
MotionEvent.ACTION_MOVE -> {
currentX = event.x
currentY = event.y
pdfview.scrollBy((preX - currentX).toInt(), (preY - currentY).toInt())
preX = currentX
preY = currentY
}
MotionEvent.ACTION_UP -> {
currentX = event.x
currentY = event.y
pdfview.scrollBy((preX - currentX).toInt(), (preY - currentY).toInt())
}
}
true
}
Layout xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/myLayout"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/frame"
android:layout_width="350dp"
android:layout_height="515dp"
android:layout_marginStart="30dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="30dp"
android:background="@drawable/image_border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/creatorButton">
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cropToPadding="true"
android:padding="1dp"
android:scaleType="centerCrop" />
<ImageView
android:id="@+id/pdfview"
android:layout_width="350dp"
android:layout_height="515dp"
android:contentDescription="@string/pdf"
android:cropToPadding="true"
android:padding="1dp"
android:scaleType="centerCrop"
app:srcCompat="@color/material_dynamic_neutral80" />
</FrameLayout>
<LinearLayout
android:id="@+id/linear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/frame"
app:layout_constraintVertical_bias="0.0">
<com.google.android.material.slider.Slider
android:id="@+id/slider"
android:layout_width="350dp"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:valueFrom="0.0"
android:valueTo="300.0" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Turns out that I found how to use the Matrix movement mechanism instead of the the scroll mechanism. The key is to do the correct Matrix redraw code.
The following is the movement code:
pdfview.setOnTouchListener { _, event -> //v, event ->
val bounds: RectF = getImageBounds(pdfview, m)
val currentX: Float
val currentY: Float
when (event.action) {
MotionEvent.ACTION_DOWN -> {
preX = event.x
preY = event.y
}
MotionEvent.ACTION_MOVE -> {
currentX = event.x
currentY = event.y
//// The function xyComp is used to control the limits of the Matrix movements
//// with the help of the Drawable boundaries and corner coordinates, and total size of the View.
//// Those values are obtain on each movement below.
if (xyComp(
bounds,
fixbounds,
preX,
preY,
currentX,
currentY,
(preX - currentX),
(preY - currentY)
)
) {
//// Matrix movement. postTranslate move the Matrix in continuos mode
m.postTranslate(
-(preX - currentX),
-(preY - currentY)
)
//// Redraw Matrix by assigning the moved Matrix to the View, do not use invalidate method
pdfview.imageMatrix = m
//// Get the size(top,left,bottom,right) coordinates of the Drawable/Matrix within the View
pbounds = getImageBounds(pdfview)
//// Get the Matrix corner coordinates
val f = FloatArray(9)
m.getValues(f)
pscrollX = f[Matrix.MTRANS_X]
pscrollY = f[Matrix.MTRANS_Y]
//// With the size and corner then you can control the limits which can it move
preX = currentX
preY = currentY
}
}
MotionEvent.ACTION_UP -> {
currentX = event.x
currentY = event.y
if (xyComp(
bounds,
fixbounds,
preX,
preY,
currentX,
currentY,
(preX - currentX),
(preY - currentY)
)
) {
m.postTranslate(
-(preX - currentX),
-(preY - currentY)
)
pdfview.imageMatrix = m
pbounds = getImageBounds(pdfview)
val f = FloatArray(9)
m.getValues(f)
pscrollX = f[Matrix.MTRANS_X]
pscrollY = f[Matrix.MTRANS_Y]
}
}
}
if (pscrollX != scrollX) {
switchPAN.tag = true
switchPAN.visibility = VISIBLE
switchCenter.visibility = GONE
}
true
}