在Android中,ImageView默认是一个矩形。如何使它成为一个圆角矩形(剪辑我的位图的所有4个角为圆角矩形)在ImageView?
请注意,从2021年起,只需使用ShapeableImageView
在Android中,ImageView默认是一个矩形。如何使它成为一个圆角矩形(剪辑我的位图的所有4个角为圆角矩形)在ImageView?
请注意,从2021年起,只需使用ShapeableImageView
当前回答
在支持库的v21中,现在有了一个解决方案:它被称为RoundedBitmapDrawable。
它基本上就像一个普通的Drawable,除了你给它一个角半径的剪辑:
setCornerRadius(float cornerRadius)
所以,从Bitmap src和一个目标ImageView开始,它看起来像这样:
RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(res, src);
dr.setCornerRadius(cornerRadius);
imageView.setImageDrawable(dr);
其他回答
如果你正在使用格莱德图书馆,这将是有帮助的:
Glide.with(getApplicationContext())
.load(image_url)
.asBitmap()
.centerCrop()
.into(new BitmapImageViewTarget(imageView) {
@Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(getApplicationContext().getResources(), resource);
circularBitmapDrawable.setCornerRadius(dpToPx(10));
circularBitmapDrawable.setAntiAlias(true);
imageView.setImageDrawable(circularBitmapDrawable);
}
});
public int dpToPx(int dp) {
DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics();
return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}
从材质组件库的1.2.0-alpha03版本开始,有了新的ShapeableImageView。
你可以这样使用:
<com.google.android.material.imageview.ShapeableImageView
...
app:shapeAppearanceOverlay="@style/roundedImageView"
app:srcCompat="@drawable/ic_image" />
在你的主题。xml:
<style name="roundedImageView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">8dp</item>
</style>
或通过编程:
float radius = getResources().getDimension(R.dimen.default_corner_radius);
imageView.setShapeAppearanceModel(imageView.getShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED,radius)
.build());
使用jetpack compose,您可以使用RoundedCornerShape应用剪辑修饰器:
Image(
painter = painterResource(R.drawable.xxxx),
contentDescription = "xxxx",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(64.dp)
.clip(RoundedCornerShape(8.dp))
)
如果你不希望边框影响图像,使用这个类。不幸的是,我没有找到任何方法来绘制画布上的透明区域来到onDraw()。这里创建了一个新的位图它是画在一个真实的画布上的。
如果您想要创建一个消失的边界,该视图非常有用。如果你将borderWidth设置为0,边框将会消失,图像仍然保持圆角,就像边界一样。也就是说,它看起来就像边界完全由图像边缘绘制。
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.RectF
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
class RoundedImageViewWithBorder @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0) : AppCompatImageView(context, attrs, defStyleAttr) {
var borderColor: Int = 0
set(value) {
invalidate()
field = value
}
var borderWidth: Int = 0
set(value) {
invalidate()
field = value
}
var cornerRadius: Float = 0f
set(value) {
invalidate()
field = value
}
private var bitmapForDraw: Bitmap? = null
private var canvasForDraw: Canvas? = null
private val transparentPaint = Paint().apply {
isAntiAlias = true
color = Color.TRANSPARENT
style = Paint.Style.STROKE
xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC)
}
private val borderPaint = Paint().apply {
isAntiAlias = true
style = Paint.Style.STROKE
}
private val transparentAreaRect = RectF()
private val borderRect = RectF()
init {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundedImageViewWithBorder)
try {
borderWidth = typedArray.getDimensionPixelSize(R.styleable.RoundedImageViewWithBorder_border_width, 0)
borderColor = typedArray.getColor(R.styleable.RoundedImageViewWithBorder_border_color, 0)
cornerRadius = typedArray.getDimensionPixelSize(R.styleable.RoundedImageViewWithBorder_corner_radius, 0).toFloat()
} finally {
typedArray.recycle()
}
}
@SuppressLint("CanvasSize", "DrawAllocation")
override fun onDraw(canvas: Canvas) {
if (canvas.height <=0 || canvas.width <=0) {
return
}
if (canvasForDraw?.height != canvas.height || canvasForDraw?.width != canvas.width) {
val newBitmap = Bitmap.createBitmap(canvas.width, canvas.height, Bitmap.Config.ARGB_8888)
bitmapForDraw = newBitmap
canvasForDraw = Canvas(newBitmap)
}
bitmapForDraw?.eraseColor(Color.TRANSPARENT)
// Draw existing content
super.onDraw(canvasForDraw)
if (borderWidth > 0) {
canvasForDraw?.let { drawWithBorder(it) }
} else {
canvasForDraw?.let { drawWithoutBorder(it) }
}
// Draw everything on real canvas
bitmapForDraw?.let { canvas.drawBitmap(it, 0f, 0f, null) }
}
private fun drawWithBorder(canvas: Canvas) {
// Draw transparent area
transparentPaint.strokeWidth = borderWidth.toFloat() * 4
transparentAreaRect.apply {
left = -borderWidth.toFloat() * 1.5f
top = -borderWidth.toFloat() * 1.5f
right = canvas.width.toFloat() + borderWidth.toFloat() * 1.5f
bottom = canvas.height.toFloat() + borderWidth.toFloat() * 1.5f
}
canvasForDraw?.drawRoundRect(transparentAreaRect, borderWidth.toFloat() * 2 + cornerRadius, borderWidth.toFloat() * 2 + cornerRadius, transparentPaint)
// Draw border
borderPaint.color = borderColor
borderPaint.strokeWidth = borderWidth.toFloat()
borderRect.apply {
left = borderWidth.toFloat() / 2
top = borderWidth.toFloat() / 2
right = canvas.width.toFloat() - borderWidth.toFloat() / 2
bottom = canvas.height.toFloat() - borderWidth.toFloat() / 2
}
canvas.drawRoundRect(borderRect, cornerRadius - borderWidth.toFloat() / 2, cornerRadius - borderWidth.toFloat() / 2, borderPaint)
}
private fun drawWithoutBorder(canvas: Canvas) {
// Draw transparent area
transparentPaint.strokeWidth = cornerRadius * 4
transparentAreaRect.apply {
left = -cornerRadius * 2
top = -cornerRadius * 2
right = canvas.width.toFloat() + cornerRadius * 2
bottom = canvas.height.toFloat() + cornerRadius * 2
}
canvasForDraw?.drawRoundRect(transparentAreaRect, cornerRadius * 3, cornerRadius * 3, transparentPaint)
}
}
值:
<declare-styleable name="RoundedImageViewWithBorder">
<attr name="corner_radius" format="dimension|string" />
<attr name="border_width" format="dimension|reference" />
<attr name="border_color" format="color|reference" />
</declare-styleable>
你可以使用新的ShapableImageView提供的新版本的Android材料库。
为此,您首先需要在应用程序级别构建中添加以下依赖项。gradle文件
implementation 'com.google.android.material:material:<version>'
另外,确保这个应用程序级别的构建。gradle文件有谷歌的Maven资源库谷歌()如下所示
allprojects {
repositories {
google()
jcenter()
}
}
在此之后,您可以引用此资源来实现所需类型或形状的imageview。
为什么不在draw()中进行剪辑?
以下是我的解决方案:
用剪切扩展RelativeLayout 将ImageView(或其他视图)放入布局中:
代码:
public class RoundRelativeLayout extends RelativeLayout {
private final float radius;
public RoundRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray attrArray = context.obtainStyledAttributes(attrs,
R.styleable.RoundRelativeLayout);
radius = attrArray.getDimension(
R.styleable.RoundRelativeLayout_radius, 0);
}
private boolean isPathValid;
private final Path path = new Path();
private Path getRoundRectPath() {
if (isPathValid) {
return path;
}
path.reset();
int width = getWidth();
int height = getHeight();
RectF bounds = new RectF(0, 0, width, height);
path.addRoundRect(bounds, radius, radius, Direction.CCW);
isPathValid = true;
return path;
}
@Override
protected void dispatchDraw(Canvas canvas) {
canvas.clipPath(getRoundRectPath());
super.dispatchDraw(canvas);
}
@Override
public void draw(Canvas canvas) {
canvas.clipPath(getRoundRectPath());
super.draw(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int oldWidth = getMeasuredWidth();
int oldHeight = getMeasuredHeight();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int newWidth = getMeasuredWidth();
int newHeight = getMeasuredHeight();
if (newWidth != oldWidth || newHeight != oldHeight) {
isPathValid = false;
}
}
}