Select a portion of image in ImageView and retrieve the end points of selected rectangle

后端 未结 3 1083
灰色年华
灰色年华 2020-12-05 06:16

I need to drag and select a portion of an image set in an ImageView and retrieve the end points of the selected rectangle without causing any modifications (suc

相关标签:
3条回答
  • 2020-12-05 06:27

    Here's one way, that You can use (however, there's lot of possibilities to implement the same). It's based on creation of custom View for drawing and tracking of selection rectangle. Also, You can just apply the logic from onTouch() of custom view in yours OnTouchListener().

    Main layout:

    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:id="@+id/root"
        android:background="@android:color/background_dark">
    
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/image"
            android:src="@drawable/up_image"
            android:scaleType="fitXY" />
    
        <com.example.TestApp.DragRectView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/dragRect" />
    
    </RelativeLayout>
    

    Custom view:

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.text.TextPaint;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    public class DragRectView extends View {
    
        private Paint mRectPaint;
    
        private int mStartX = 0;
        private int mStartY = 0;
        private int mEndX = 0;
        private int mEndY = 0;
        private boolean mDrawRect = false;
        private TextPaint mTextPaint = null;
    
        private OnUpCallback mCallback = null;
    
        public interface OnUpCallback {
            void onRectFinished(Rect rect);
        }
    
        public DragRectView(final Context context) {
            super(context);
            init();
        }
    
        public DragRectView(final Context context, final AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public DragRectView(final Context context, final AttributeSet attrs, final int defStyle) {
            super(context, attrs, defStyle);
            init();
        }
    
        /**
         * Sets callback for up
         *
         * @param callback {@link OnUpCallback}
         */
        public void setOnUpCallback(OnUpCallback callback) {
            mCallback = callback;
        }
    
        /**
         * Inits internal data
         */
        private void init() {
            mRectPaint = new Paint();
            mRectPaint.setColor(getContext().getResources().getColor(android.R.color.holo_green_light));
            mRectPaint.setStyle(Paint.Style.STROKE);
            mRectPaint.setStrokeWidth(5); // TODO: should take from resources
    
            mTextPaint = new TextPaint();
            mTextPaint.setColor(getContext().getResources().getColor(android.R.color.holo_green_light));
            mTextPaint.setTextSize(20);
        }
    
        @Override
        public boolean onTouchEvent(final MotionEvent event) {
    
            // TODO: be aware of multi-touches
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mDrawRect = false;
                    mStartX = (int) event.getX();
                    mStartY = (int) event.getY();
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_MOVE:
                    final int x = (int) event.getX();
                    final int y = (int) event.getY();
    
                    if (!mDrawRect || Math.abs(x - mEndX) > 5 || Math.abs(y - mEndY) > 5) {
                        mEndX = x;
                        mEndY = y;
                        invalidate();
                    }
    
                    mDrawRect = true;
                    break;
    
                case MotionEvent.ACTION_UP:
                    if (mCallback != null) {
                        mCallback.onRectFinished(new Rect(Math.min(mStartX, mEndX), Math.min(mStartY, mEndY),
                                Math.max(mEndX, mStartX), Math.max(mStartY, mEndY)));
                    }
                    invalidate();
                    break;
    
                default:
                    break;
            }
    
            return true;
        }
    
        @Override
        protected void onDraw(final Canvas canvas) {
            super.onDraw(canvas);
    
            if (mDrawRect) {
                canvas.drawRect(Math.min(mStartX, mEndX), Math.min(mStartY, mEndY),
                        Math.max(mEndX, mStartX), Math.max(mEndY, mStartY), mRectPaint);
                canvas.drawText("  (" + Math.abs(mStartX - mEndX) + ", " + Math.abs(mStartY - mEndY) + ")",
                        Math.max(mEndX, mStartX), Math.max(mEndY, mStartY), mTextPaint);
            }
        }
    }
    

    Activity is simple:

    public class MyActivity extends Activity {
    
        private static final String TAG = "MyActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            final DragRectView view = (DragRectView) findViewById(R.id.dragRect);
    
            if (null != view) {
                view.setOnUpCallback(new DragRectView.OnUpCallback() {
                    @Override
                    public void onRectFinished(final Rect rect) {
                        Toast.makeText(getApplicationContext(), "Rect is (" + rect.left + ", " + rect.top + ", " + rect.right + ", " + rect.bottom + ")",
                                Toast.LENGTH_LONG).show();
                    }
                });
            }
        }
    }
    

    The output is like the following:

    image

    0 讨论(0)
  • 2020-12-05 06:46

    I just tried out your solution, it's pretty cool. Maybe I am wrong, but I think there is a typo in your Toast output:

    mCallback.onRectFinished(new Rect(Math.min(mStartX, mEndX), Math.min(mStartY, mEndY),
                            Math.max(mEndX, mStartX), Math.max(mEndY, mStartX)));
    

    must be:

    mCallback.onRectFinished(new Rect(Math.min(mStartX, mEndX), Math.min(mStartY, mEndY),
                            Math.max(mEndX, mStartX), Math.max(mEndY, mStartY)));
    

    otherwise the value of the bottom sometimes is calculated wrong.

    0 讨论(0)
  • 2020-12-05 06:47

    Another way : https://github.com/edmodo/cropper

    From the Doc:

    The Cropper is an image cropping tool. It provides a way to set an image in XML and programmatically, and displays a resizable crop window on top of the image. Calling the method getCroppedImage() will then return the Bitmap marked by the crop window.

    Developers can customize the following attributes (both via XML and programmatically):

    appearance of guidelines in the crop window whether the aspect ratio is fixed or not aspect ratio (if the aspect ratio is fixed) image resource A public method to rotate the image by a specified number of degrees is also included. This can be used to provide the user with an option to fix the image orientation should Android miscalculate the intended orientation.

    Supported on API Level 7 and above.

    For more information, see the linked Github Wiki page.

    0 讨论(0)
提交回复
热议问题