Android自定义View实现图片裁剪功能(一)

  1. 定义自定义View:

/**
 * 图片裁剪自定义View
 */
public class CropImageView extends View {

    private Paint mPaint;
    private Bitmap mBitmap;

    //裁剪框的宽高
    private float mBoxWidth;
    private float mBoxHeight;

    //裁剪框的左上角坐标
    private float mBoxX;
    private float mBoxY;

    //图片缩放比例
    private float mScale;
    //图片偏移量
    private float mTranslateX;
    private float mTranslateY;

    private int mImageWidth;
    private int mImageHeight;

    //触摸点的坐标
    private float mX;
    private float mY;

    //触摸的模式
    private int mMode = 0;
    public static final int DRAG = 1;
    public static final int ZOOM = 2;

    //触摸的两个点
    private PointF mPoint1 = new PointF();
    private PointF mPoint2 = new PointF();

    //缩放的最小比例
    private static final float SCALE_MIN = 0.5f;
    //缩放的最大比例
    private static final float SCALE_MAX = 1.5f;

    //移动时,手指在屏幕上移动的距离
    private float mMoveX;
    private float mMoveY;

    public CropImageView(Context context) {
        this(context,null);
    }

    public CropImageView(Context context,  AttributeSet attrs) {
        this(context, attrs,0);
    }

    public CropImageView(Context context,  AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
        //抗锯齿
        mPaint.setAntiAlias(true);
        //裁剪框的宽高
        mBoxWidth = (float) ScreenUtil.getScreenWidth(getContext()) * 0.8f;
        mBoxHeight = (float) ScreenUtil.getScreenHeight(getContext()) * 0.4f;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mBitmap != null) {
            canvas.translate(mTranslateX, mTranslateY);
            canvas.scale(mScale, mScale, mBoxX + mBoxWidth / 2, mBoxY + mBoxHeight / 2);
            canvas.drawBitmap(mBitmap, 0, 0, mPaint);
            //绘制裁剪框
            canvas.drawRect(mBoxX, mBoxY, mBoxX + mBoxWidth, mBoxY + mBoxHeight, mPaint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //获取触摸点的坐标
        mX = event.getX();
        mY = event.getY();
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                mMode = DRAG;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                mMode = ZOOM;
                //记录触摸的两个点的坐标
                mPoint1.set(event.getX(0), event.getY(0));
                mPoint2.set(event.getX(1), event.getY(1));
                break;
            case MotionEvent.ACTION_MOVE:
                if (mMode == ZOOM) {
                    //计算两个触摸点的距离
                    float distance = (float) Math.sqrt(Math.pow(event.getX(0) - event.getX(1), 2) + Math.pow(event.getY(0) - event.getY(1), 2));
                    //计算缩放比例
                    mScale = distance / (float) Math.sqrt(Math.pow(mPoint1.x - mPoint2.x, 2) + Math.pow(mPoint1.y - mPoint2.y, 2));
                    mScale = Math.max(mScale, SCALE_MIN);
                    mScale = Math.min(mScale, SCALE_MAX);
                    //计算图片的偏移量
                    mTranslateX = mX - mImageWidth / 2 - (mX - mImageWidth / 2 - mTranslateX) * mScale / mScale;
                    mTranslateY = mY - mImageHeight / 2 - (mY - mImageHeight / 2 - mTranslateY) * mScale / mScale;
                    if (mTranslateX > 0) {
                        mTranslateX = 0;
                    } else if (mTranslateX < -(mImageWidth * mScale - mBoxWidth)) {
                        mTranslateX = -(mImageWidth * mScale - mBoxWidth);
                    }
                    if (mTranslateY > 0) {
                        mTranslateY = 0;
                    } else if (mTranslateY < -(mImageHeight * mScale - mBoxHeight)) {
                        mTranslateY = -(mImageHeight * mScale - mBoxHeight);
                    }
                    invalidate();
                } else if (mMode == DRAG) {
                    //计算移动的距离
                    mMoveX = mX - mImageWidth / 2 - (mX - mImageWidth / 2 - mTranslateX);
                    mMoveY = mY - mImageHeight / 2 - (mY - mImageHeight / 2 - mTranslateY);
                    if (mMoveX > 0) {
                        mMoveX = 0;
                    } else if (mMoveX < -(mImageWidth * mScale - mBoxWidth)) {
                        mMoveX = -(mImageWidth * mScale - mBoxWidth);
                    }
                    if (mMoveY > 0) {
                        mMoveY = 0;
                    } else if (mMoveY < -(mImageHeight * mScale - mBoxHeight)) {
                        mMoveY = -(mImageHeight * mScale - mBoxHeight);
                    }
                    mTranslateX = mMoveX;
                    mTranslateY = mMoveY;
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                mMode = 0;
                break;
        }
        return true;
    }

    /**
     * 设置图片
     */
    public void setImageDrawable(Bitmap bitmap) {
        if (bitmap != null) {
            mBitmap = bitmap;
            mImageWidth = mBitmap.getWidth();
            mImageHeight = mBitmap.getHeight();
            mScale = 1;
            mTranslateX = 0;
            mTranslateY = 0;
            mBoxX = (float) ScreenUtil.getScreenWidth(getContext()) * 0.1f;
            mBoxY = (float) ScreenUtil.getScreenHeight(getContext()) * 0.3f;
            invalidate();
        }
    }

    /**
     * 获取裁剪图片的矩形
     */
    public RectF getCropRectF() {
        return new RectF(mBoxX - mTranslateX, mBoxY - mTranslateY, mBoxX + mBoxWidth - mTranslateX, mBoxY + mBoxHeight - mTranslateY);
    }
}
  1. 在layout文件中添加自定义View

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.kevin.cropimageview.view.CropImageView
        android:id="@+id/civ_crop"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
  1. 在代码中使用

public class MainActivity extends AppCompatActivity {

    private CropImageView mCropImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mCropImageView = (CropImageView) findViewById(R.id.civ_crop);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
        mCropImageView.setImageDrawable(bitmap);
    }

    /**
     * 点击裁剪按钮
     */
    public void crop(View view) {
        RectF rectF = mCropImageView.getCropRectF();
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
        Bitmap cropBitmap = Bitmap.createBitmap(bitmap, (int) rectF.left, (int) rectF.top, (int) rectF.width(), (int) rectF.height());
        mCropImageView.setImageDrawable(cropBitmap);
    }

}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是一个实现圆形边框和图片裁剪自定义View的完整代码: ``` public class CircleImageView extends ImageView { private Paint mBorderPaint; private int mBorderColor; private int mBorderWidth; private Bitmap mBitmap; private BitmapShader mBitmapShader; private int mBitmapWidth; private int mBitmapHeight; private float mRadius; private RectF mBorderRect; public CircleImageView(Context context) { super(context); init(); } public CircleImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mBorderPaint = new Paint(); mBorderPaint.setAntiAlias(true); mBorderRect = new RectF(); } @Override protected void onDraw(Canvas canvas) { if (mBitmapShader == null) { mBitmap = getBitmap(); if (mBitmap != null) { mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mBitmapWidth = mBitmap.getWidth(); mBitmapHeight = mBitmap.getHeight(); mRadius = Math.min(mBitmapWidth, mBitmapHeight) / 2; updateShaderMatrix(); } } if (mBitmapShader != null) { mBorderPaint.setShader(mBitmapShader); canvas.drawCircle(mRadius, mRadius, mRadius, mBorderPaint); mBorderPaint.setShader(null); mBorderPaint.setColor(mBorderColor); mBorderPaint.setStrokeWidth(mBorderWidth); mBorderRect.set(0, 0, getWidth(), getHeight()); canvas.drawArc(mBorderRect, 0, 360, false, mBorderPaint); } } private void updateShaderMatrix() { float scale; float dx = 0; float dy = 0; if (mBitmapWidth * getHeight() > getWidth() * mBitmapHeight) { scale = getHeight() / (float) mBitmapHeight; dx = (getWidth() - mBitmapWidth * scale) * 0.5f; } else { scale = getWidth() / (float) mBitmapWidth; dy = (getHeight() - mBitmapHeight * scale) * 0.5f; } Matrix matrix = new Matrix(); matrix.setScale(scale, scale); matrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f)); mBitmapShader.setLocalMatrix(matrix); } public void setBorderColor(int borderColor) { if (borderColor == mBorderColor) { return; } mBorderColor = borderColor; invalidate(); } public void setBorderWidth(int borderWidth) { if (borderWidth == mBorderWidth) { return; } mBorderWidth = borderWidth; invalidate(); } private Bitmap getBitmap() { Drawable drawable = getDrawable(); if (drawable == null) { return null; } if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } } ``` 使用方法: 在布局文件中添加自定义View: ``` <com.example.CircleImageView android:id="@+id/circle_image_view" android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/avatar" app:border_color="#ffffff" app:border_width="4dp" /> ``` 其中 `app:border_color` 和 `app:border_width` 分别表示边框的颜色和宽度,可以根据需要调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金戈鐡馬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值