自定义圆形、圆角矩形View

本文介绍如何在Android开发中自定义一个View,用于实现圆角矩形或圆形图片显示,支持设置边框、颜色和按下状态蒙层颜色等功能。详细步骤包括定义属性、布局引用、初始化属性、矩阵变换、视图绘制和触屏事件处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

日常开发中经常要用到圆角矩形或者圆形来显示头像或图片,因此对于它的使用方式我们还是比较关注的。下面我们就自定义一个View来进行圆角矩形或圆形图片的展示,同时也支持自定义设置边框大小、边框颜色、按下状态蒙层颜色等属性。

效果图

使用

1、在attrs.xml中自定义属性

<declare-styleable name="RoundImageView">
    <!-- 显示类型 -->
    <attr name="imageType" format="enum">
        <enum name="circle" value="0" />
        <enum name="round" value="1" />
    </attr>
    <!-- 边框大小 -->
    <attr name="borderWidth" format="dimension" />
    <!-- 边框颜色 -->
    <attr name="borderColor" format="color" />
    <!-- 圆角大小 -->
    <attr name="roundRadius" format="dimension" />
    <!-- 按下状态蒙层颜色 -->
    <attr name="coverColor" format="color" />
    <!-- 是否可被按下 -->
    <attr name="isPressed" format="boolean" />
</declare-styleable>

2、布局引用

 <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <com.wiggins.roundpicture.widget.RoundImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/pic_one" />

    <com.wiggins.roundpicture.widget.RoundImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginBottom="@dimen/margin_large"
        android:layout_marginTop="@dimen/margin_large"
        android:src="@drawable/pic_three"
        app:borderColor="@color/red"
        app:borderWidth="1.5dp"
        app:imageType="circle" />

    <com.wiggins.roundpicture.widget.RoundImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/pic_two"
        app:borderColor="@color/colorAccent"
        app:borderWidth="1.5dp"
        app:imageType="round" />
</LinearLayout>

3、自定义RoundImageView

初始化属性

private void initAttributes() {
    // 设置缩放
    setScaleType(ScaleType.CENTER_CROP);
    // 初始化画笔等属性
    mShaderMatrix = new Matrix();
    mRcBitmap = new RectF();
    mRcBorder = new RectF();

    mBitmapPaint = new Paint();
    mBitmapPaint.setAntiAlias(true);
    mBitmapPaint.setDither(true);

    mBorderPaint = new Paint();
    mBorderPaint.setAntiAlias(true);
    mBorderPaint.setDither(true);
    mBorderPaint.setStyle(Paint.Style.FILL);
    mBorderPaint.setColor(mBorderColor);
    mBorderPaint.setStrokeWidth(mBorderWidth);
}

渲染器及大小

private void setShader() {
    Drawable drawable = getDrawable();
    if (drawable == null) {
        return;
    }
    Bitmap bitmap = getBitmapFromDrawable(drawable);

    mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
    mBitmapPaint.setShader(mBitmapShader);

    mRcBorder.set(0, 0, getWidth(), getHeight());
    mBorderRadius = Math.min((mRcBorder.height() - mBorderWidth) / 2, (mRcBorder.width() - mBorderWidth) / 2);

    if (mImageType == TYPE_CIRCLE) {
        mRcBitmap.set(mBorderWidth, mBorderWidth, mRcBorder.width() - mBorderWidth, mRcBorder.height() - mBorderWidth);
    } else if (mImageType == TYPE_ROUND) {
        mRcBitmap.set(mBorderWidth / 2, mBorderWidth / 2, mRcBorder.width() - mBorderWidth / 2, mRcBorder.height() - mBorderWidth / 2);
    }

    mBitmapRadius = Math.min(mRcBitmap.height() / 2, mRcBitmap.width() / 2);

    updateShaderMatrix(bitmap);
    invalidate();
}

矩阵变换

private void updateShaderMatrix(Bitmap mBitmap) {
    float scale;
    float dx = 0;
    float dy = 0;

    mShaderMatrix.set(null);

    if (mBitmap.getWidth() * mRcBitmap.height() > mRcBitmap.width() * mBitmap.getHeight()) {
        scale = mRcBitmap.height() / (float) mBitmap.getHeight();
        dx = (mRcBitmap.width() - mBitmap.getWidth() * scale) * 0.5f;
    } else {
        scale = mRcBitmap.width() / (float) mBitmap.getWidth();
        dy = (mRcBitmap.height() - mBitmap.getHeight() * scale) * 0.5f;
    }

    mShaderMatrix.setScale(scale, scale);
    mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth);
    mBitmapShader.setLocalMatrix(mShaderMatrix);
}

视图绘制

@Override
protected void onDraw(Canvas canvas) {
    if (getDrawable() == null) {
        return;
    }
    setShader();
    if (mImageType == TYPE_ROUND) {
        canvas.drawRoundRect(mRcBorder, mRoundRadius, mRoundRadius, mBorderPaint);
        canvas.drawRoundRect(mRcBitmap, mRoundRadius, mRoundRadius, mBitmapPaint);
    } else {
        canvas.drawCircle(mCenterCoordinates, mCenterCoordinates, mBorderRadius, mBorderPaint);
        canvas.drawCircle(mCenterCoordinates, mCenterCoordinates, mBitmapRadius, mBitmapPaint);
    }
}

触屏事件

@Override
public boolean onTouchEvent(MotionEvent event) {
    int action = event.getActionMasked();
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            setPressed(true);
            break;
        case MotionEvent.ACTION_MOVE:
            if (!mRcBitmap.contains(event.getX(), event.getY())) {
                setPressed(false);
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            setPressed(false);
            break;
    }
    return true;
}

按下状态蒙层颜色

@Override
public void setPressed(boolean pressed) {
    super.setPressed(pressed);
    if (!mIsPressed) {
        return;
    }
    if (pressed) {
        mBitmapPaint.setColorFilter(new PorterDuffColorFilter(mCoverColor, PorterDuff.Mode.SRC_ATOP));
    } else {
        mBitmapPaint.setColorFilter(null);
    }
    invalidate();
}

项目地址 ☞ 传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值