Search code examples
javaandroidandroid-layoutandroid-activityandroid-view

Get the coordinates of visible part of screen when zoomed in


I'm using a custom lib that implements a zoomable, pinchable and scrollable layout, but I when I zoom the layout in, I cant get the coordinates of the visible part. Is there a way of doing that? Android documentation explains nothing about viewport.

This pictures has an example. The rectangle in the left is my layout. When I zoom it, the user will only see the smaller one, but it will fill all the screen. How can I get the coordinates of the small rectangle (in red)?

enter image description here


Solution

  • So I'm not the library's true user that I don't know actual answer. But I myself do similar thing as the library in my custom ImageView. So I can suggest somewhat. Please try and examine later by yourself.

    The library has those Pan APIs. I think by using either getPan()/getPanX()/getPanY() or getScaledPan()/getScaledPanX()/getScaledPanY() you can get the left-top point's coordinates. (Maybe, the latter scaled ones are what you want?)

    Once you get the left-top point's coordinates, you can calculate the others by the rectangle's width and height.

    To know width and height, you can reverse-calculate from your ImageView's width and height, and current scale factor.

    To know the width and height of your ImageView, use getWidth() and getHeight().

    To know the current scale factor of the library, either getZoom() or getRealZoom() of Zoom APIs should be usable.

    Then, divide ImageView's width or height by the current scale factor and you get the rectangle's width or height.

    At last, based on the left-top point's coordinates, left-bottom point is plus height, right-top point is plus width and right-bottom point is plus width and height.


    Sample Code

    layout/activity_main.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"
        tools:context=".MainActivity">
    
        <com.otaliastudios.zoom.ZoomImageView
            android:id="@+id/zoomImageView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@android:color/darker_gray"
            app:alignment="top|left"
            app:layout_constraintBottom_toTopOf="@id/linearLayout"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:maxZoom="2"
            app:maxZoomType="zoom"
            app:minZoom="0.5"
            app:minZoomType="zoom"
            app:overPinchable="false"
            app:overScrollHorizontal="false"
            app:overScrollVertical="false"
            app:threeFingersScrollEnabled="false"
            app:transformation="centerCrop"
            app:transformationGravity="top|left"
            app:twoFingersScrollEnabled="false" />
    
        <LinearLayout
            android:id="@+id/linearLayout"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:orientation="vertical"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/zoomImageView">
    
            <Button
                android:id="@+id/button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:onClick="click"
                android:text="@string/app_name" />
    
            <TextView
                android:id="@+id/textView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
        </LinearLayout>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    MainActivity:

    import androidx.appcompat.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    
    import com.otaliastudios.zoom.ZoomImageView;
    
    public class MainActivity extends AppCompatActivity {
        private ZoomImageView zoomImageView;
        private TextView textView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            zoomImageView = findViewById(R.id.zoomImageView);
            zoomImageView.setImageDrawable(getResources().getDrawable(R.drawable.img2880x2880, null));
            textView = findViewById(R.id.textView);
        }
    
        public void click(View view) {
            textView.setText(String.format(
                    "pan (on the World (src image) coordinates):\n\t%s\n" +
                            "scaledPan (on the Display coordinates):\n\t%s\n" +
                            "zoom (relative ratio to the initial scale):\n\t%f\n" +
                            "realZoom (real scale factor for the image):\n\t%f\n" +
                            "the View's layout width: %d\n" +
                            "the View's layout height: %d\n\n" +
                            "the Window rect: (%f, %f) - (%f, %f)",
                    zoomImageView.getPan().toString(),
                    zoomImageView.getScaledPan().toString(),
                    zoomImageView.getZoom(),
                    zoomImageView.getRealZoom(),
                    zoomImageView.getWidth(),
                    zoomImageView.getHeight(),
                    -zoomImageView.getPanX(),
                    -zoomImageView.getPanY(),
                    -zoomImageView.getPanX() + ((float) zoomImageView.getWidth()) / zoomImageView.getRealZoom(),
                    -zoomImageView.getPanY() + ((float) zoomImageView.getHeight()) / zoomImageView.getRealZoom()
            ));
        }
    }
    

    And drawable-nodpi/img2880x2880.png. So my test device's display width is 1440px that I prepared a square image of 2880px by 2880px with checker 1440px squares.

    You can pan (scroll) the image and pinch zoom-in/out it. When you push the button, it indicates current status. Of the last, Window rect should be what you want.

    Note that because

    -zoomImageView.getPanX() + ((float) zoomImageView.getWidth()) / zoomImageView.getRealZoom()
    

    or

    -zoomImageView.getPanY() + ((float) zoomImageView.getHeight()) / zoomImageView.getRealZoom()
    

    is a calculation of float values, the result value may partially contain calculation error.

    screenshot