简体   繁体   中英

Change Custom View Width And Height In Android

In my android app, I have a crop image. So, I programming a custom view as my crop box. I can move the crop box. But my problem is how can I drag border of the crop box and change width and height of it. How can I do it?

Attr Class:

public class Attr {

    public static final float CROP_BOX_START_X = 5;
    public static final float CROP_BOX_START_Y = 5;
    public static final float CROP_BOX_END_X = 305;
    public static final float CROP_BOX_END_Y = 105;

}

CropBox Class:

public class CropBox extends View {

    private Paint paint = new Paint();


    public CropBox(Context context) {
        super(context);
    }

    public CropBox(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
    }


    @Override
    public void onDraw(Canvas canvas) {
        float[][] circleXY = {
            {Attr.CROP_BOX_START_X, Attr.CROP_BOX_START_Y},
            {(Attr.CROP_BOX_START_X + Attr.CROP_BOX_END_X) / 2, Attr.CROP_BOX_START_Y},
            {Attr.CROP_BOX_END_X, Attr.CROP_BOX_START_Y},
            {Attr.CROP_BOX_START_X, Attr.CROP_BOX_END_Y},
            {(Attr.CROP_BOX_START_X + Attr.CROP_BOX_END_X) / 2, Attr.CROP_BOX_END_Y},
            {Attr.CROP_BOX_END_X, Attr.CROP_BOX_END_Y},
            {Attr.CROP_BOX_START_X, (Attr.CROP_BOX_START_Y + Attr.CROP_BOX_END_Y) / 2},
            {Attr.CROP_BOX_END_X, (Attr.CROP_BOX_START_Y + Attr.CROP_BOX_END_Y) / 2}
        };
        float[][] lineXY = {
            {Attr.CROP_BOX_START_X, Attr.CROP_BOX_START_Y, Attr.CROP_BOX_END_X, Attr.CROP_BOX_START_Y},
            {Attr.CROP_BOX_START_X, Attr.CROP_BOX_END_Y, Attr.CROP_BOX_END_X, Attr.CROP_BOX_END_Y},
            {Attr.CROP_BOX_START_X, Attr.CROP_BOX_START_Y, Attr.CROP_BOX_START_X, Attr.CROP_BOX_END_Y},
            {Attr.CROP_BOX_END_X, Attr.CROP_BOX_START_Y, Attr.CROP_BOX_END_X, Attr.CROP_BOX_END_Y}
        };

        paint.setColor(Color.CYAN);
        paint.setStrokeWidth(1);

        for(int i = 0 ; i < circleXY.length ; i++)
            canvas.drawCircle(circleXY[i][0], circleXY[i][1], 5, paint);

        paint.setStrokeWidth(2);

        for(int i = 0 ; i < lineXY.length ; i++)
            canvas.drawLine(lineXY[i][0], lineXY[i][2], lineXY[i][2], lineXY[i][3], paint);
    }

}

CropTestActivity Class:

public class CropTestActivity extends Activity {

    private ImageView imageView;
    private CropBox cropBox;
    private RelativeLayout relativeLayout;
    private RelativeLayout.LayoutParams layoutParams;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.crop_test_layout);
        imageView = (ImageView)findViewById(R.id.android_image);
        cropBox = new CropBox(this);
        relativeLayout = (RelativeLayout)findViewById(R.id.crop_test_layout);
        layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
        imageView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                layoutParams.leftMargin = imageView.getWidth() / 2 - (int)((Attr.CROP_BOX_START_X + Attr.CROP_BOX_END_X) / 2) + imageView.getLeft();
                layoutParams.topMargin = imageView.getHeight() / 2 - (int)((Attr.CROP_BOX_START_Y + Attr.CROP_BOX_END_Y) / 2) + imageView.getTop();
            }
        });
        relativeLayout.addView(cropBox, layoutParams);
        cropBox.setOnTouchListener(new Crop(imageView));
    }

}

Crop Class:

public class Crop implements OnTouchListener {

    private static final int NONE = 0;
    private static final int BOX_DRAG = 1;
    private static final int BORDER_DRAG = 2;

    private int mode = NONE;

    private float cropBoxStartX = Attr.CROP_BOX_START_X;
    private float cropBoxStartY = Attr.CROP_BOX_START_Y;
    private float cropBoxEndX = Attr.CROP_BOX_END_X;
    private float cropBoxEndY = Attr.CROP_BOX_END_Y;

    private ImageView imageView;

    private PointF start = new PointF();


    public Crop(ImageView imageView) {
        this.imageView = imageView;
    }


    public boolean onTouch(View view, MotionEvent event) {
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)view.getLayoutParams();

        switch(event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                start.set(event.getX(), event.getY());
                if(event.getX() > cropBoxStartX && event.getX() < cropBoxEndX && event.getY() > cropBoxStartY && event.getY() < cropBoxEndY)
                    mode = BOX_DRAG;
                else if(event.getX() == cropBoxStartX || event.getX() == cropBoxEndX || event.getY() == cropBoxStartY || event.getY() == cropBoxEndY)
                    mode = BORDER_DRAG;
                else
                    mode = NONE;
                break;

            case MotionEvent.ACTION_UP:
                mode = NONE;
                break;

            case MotionEvent.ACTION_MOVE:
                if(mode == BOX_DRAG) {
                    layoutParams.leftMargin = (int)event.getX() - (int)start.x + view.getLeft();
                    layoutParams.topMargin = (int)event.getY() - (int)start.y + view.getTop();
                    while(layoutParams.topMargin + 5 < imageView.getTop())
                        layoutParams.topMargin++;
                    while(layoutParams.leftMargin + (cropBoxEndX - cropBoxStartX + 5) > imageView.getRight())
                        layoutParams.leftMargin--;
                    while(layoutParams.topMargin + (cropBoxEndY - cropBoxStartY + 5) > imageView.getBottom())
                        layoutParams.topMargin--;
                    while(layoutParams.leftMargin + 5 < imageView.getLeft())
                        layoutParams.leftMargin++;
                }
                else if(mode == BORDER_DRAG) {
                }
                break;
        }
        view.setLayoutParams(layoutParams);
        return true;
    }

}

Layout XML:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/crop_test_layout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ImageView
        android:id="@+id/android_image"
        android:src="@drawable/android"
        android:layout_width="fill_parent"
        android:layout_height="300dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="10dp"
        android:layout_gravity="center"
        android:scaleType="fitXY"
        android:contentDescription="@string/android_image_description" >
    </ImageView>

</RelativeLayout>

Before Resize:

在此输入图像描述

After Resize:

在此输入图像描述

Thanks for your help.

Following is the solution,

Modified onCreate from Activity

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.crop_test_layout);
    imageView = (ImageView)findViewById(R.id.android_image);
    cropBox = new CropBox(this, imageView);
    relativeLayout = (RelativeLayout)findViewById(R.id.crop_test_layout);
    relativeLayout.addView(cropBox);
}

Modified CropBox class:

public class CropBox extends View {

    private static final int CROP_BOX_START_X = 5;
    private static final int CROP_BOX_START_Y = 5;
    private static final int CROP_BOX_END_X = 305;
    private static final int CROP_BOX_END_Y = 105;

    private static final int DRAG_SQUARE = 75;

    public ImageView mImageView;
    boolean mIsFirstClick = false;

    private Paint paint = new Paint();
    private Rect mRect;

    public CropBox(Context context, ImageView aBaseView) {
        super(context);
        mImageView = aBaseView;
        mRect = new Rect(CROP_BOX_START_X, CROP_BOX_START_Y, CROP_BOX_END_X, CROP_BOX_END_Y);
        setOnTouchListener(new Crop());
    }

    public CropBox(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
    }

    @Override
    public void onDraw(Canvas canvas) {

        paint.setStrokeWidth(2);

        paint.setColor(Color.CYAN);
        paint.setStyle(Paint.Style.STROKE);

        canvas.drawRect(mRect, paint);

        canvas.drawLine(mRect.right-DRAG_SQUARE, mRect.bottom-DRAG_SQUARE, 
                mRect.right, mRect.bottom-DRAG_SQUARE, paint);

        canvas.drawLine(mRect.right-DRAG_SQUARE, mRect.bottom-DRAG_SQUARE, 
                mRect.right-DRAG_SQUARE, mRect.bottom, paint);
    }

    class Crop implements OnTouchListener {

        private static final int NONE = 0;
        private static final int BOX_DRAG = 1;
        private static final int BORDER_DRAG = 2;

        private int mode = NONE;

        private PointF start = new PointF();

        public boolean onTouch(View view, MotionEvent event) {
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)view.getLayoutParams();

            switch(event.getAction() & MotionEvent.ACTION_MASK) {

                case MotionEvent.ACTION_DOWN:
                    start.set(event.getX(), event.getY());

                    if((event.getX() <= mRect.right && event.getX() >=(mRect.right - DRAG_SQUARE)) 
                            && (event.getY() >= mRect.top && event.getY() >=(mRect.bottom - DRAG_SQUARE))){
                        mode = BORDER_DRAG;
                        mIsFirstClick = false;
                    }
                    else if(mRect.contains((int)event.getX(), (int)event.getY())) {
                        mode = BOX_DRAG;
                        if (mIsFirstClick){
                            mRect = new Rect(CROP_BOX_START_X, CROP_BOX_START_Y, 
                                    CROP_BOX_END_X, CROP_BOX_END_Y);
                            mIsFirstClick = false;  
                        } else {
                            mIsFirstClick = true;   
                        }
                    }
                    else{
                        mode = NONE;
                        mIsFirstClick = true;
                    }
                    break;

                case MotionEvent.ACTION_UP:
                    mode = NONE;
                    break;

                case MotionEvent.ACTION_MOVE:
                    mIsFirstClick = false;
                    if(mode == BOX_DRAG) {
                        layoutParams.leftMargin = (int)event.getX() - (int)start.x + view.getLeft();
                        layoutParams.topMargin = (int)event.getY() - (int)start.y + view.getTop();
                    }
                    else if(mode == BORDER_DRAG) {
                        if (event.getX() > view.getLeft() && event.getY() > view.getTop()){
                            mRect.right = (int) event.getX();
                            mRect.bottom = (int) event.getY();
                        }
                    }
                    while(layoutParams.topMargin + 5 < mImageView.getTop())
                        layoutParams.topMargin++;
                    while(layoutParams.leftMargin + mRect.right > mImageView.getRight())
                        layoutParams.leftMargin--;
                    while(layoutParams.topMargin + mRect.bottom > mImageView.getBottom())
                        layoutParams.topMargin--;
                    while(layoutParams.leftMargin + 5 < mImageView.getLeft())
                        layoutParams.leftMargin++;
                    break;
            }
            view.setLayoutParams(layoutParams);
            invalidate();
            return true;
        }
    }
}

Some points I would like to mention.

  • Merged Attr and Crop in CropBox
  • No need of creating a rectangle from lines. You can use Rect .
  • Never initialize an array/object in Draw method
  • Added a feature: if double touched on rectangle it returns to original position
  • There might be some hitches about the restricting the rect in imageview. I am sure you can fix those... :)

Other than this there is another interesting way using scaling of canvas Image in Canvas with touch events Use that class instead of Cropbox and try it.

Hope it helps..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM