Android平台下如何显示菱形图片及带侧边圆角的菱形图片?
嘿,这个问题我刚好在项目里处理过几次,给你分享两种靠谱的实现方案,分别对应普通菱形和带侧边圆角的菱形图片:
一、实现普通菱形图片展示
这里有两种常用的实现方式,你可以根据需求选择:
方法1:自定义ImageView通过裁剪路径实现
这种方式最直观,核心是用Path构建菱形的轮廓,然后裁剪画布,让图片只显示在菱形区域内。
class RhombusImageView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AppCompatImageView(context, attrs, defStyleAttr) { private val clipPath = Path() override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) // 根据View的宽高,构建菱形的四个顶点路径 clipPath.reset() clipPath.moveTo(w / 2f, 0f) // 顶部顶点 clipPath.lineTo(w.toFloat(), h / 2f) // 右侧顶点 clipPath.lineTo(w / 2f, h.toFloat()) // 底部顶点 clipPath.lineTo(0f, h / 2f) // 左侧顶点 clipPath.close() } override fun onDraw(canvas: Canvas?) { canvas?.clipPath(clipPath) // 裁剪画布为菱形 super.onDraw(canvas) // 让系统绘制图片 } }
使用的时候直接在布局里引用这个自定义View就行,和普通ImageView用法一样。要是遇到API 18以下的设备(现在很少见了),记得给这个View关闭硬件加速:android:layerType="software"。
方法2:用BitmapShader绘制菱形
这种方式是把图片作为着色器,直接绘制到菱形路径上,好处是可以更精准控制图片的缩放和位置,边缘也更平滑。
class RhombusImageView2 @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AppCompatImageView(context, attrs, defStyleAttr) { private val paint = Paint(Paint.ANTI_ALIAS_FLAG) override fun onDraw(canvas: Canvas?) { val drawable = drawable ?: return val bitmap = (drawable as BitmapDrawable).bitmap // 创建图片着色器,设置拉伸模式 val shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) // 计算缩放比例,让图片覆盖整个菱形区域 val scale = max(width.toFloat() / bitmap.width, height.toFloat() / bitmap.height) val matrix = Matrix() matrix.postScale(scale, scale) matrix.postTranslate((width - bitmap.width * scale) / 2, (height - bitmap.height * scale) / 2) shader.setLocalMatrix(matrix) paint.shader = shader // 绘制菱形路径 val path = Path() path.moveTo(width / 2f, 0f) path.lineTo(width.toFloat(), h / 2f) path.lineTo(width / 2f, height.toFloat()) path.lineTo(0f, h / 2f) path.close() canvas?.drawPath(path, paint) } }
二、实现带侧边圆角的菱形图片
这个稍微复杂点,因为菱形的边是斜线,普通的圆角矩形方法没用,得用贝塞尔曲线手动构建带圆角的菱形路径:
class RoundedRhombusImageView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AppCompatImageView(context, attrs, defStyleAttr) { private val clipPath = Path() private var cornerRadius = 20f // 默认圆角大小,可通过自定义属性配置 init { // 读取自定义属性里的圆角值 val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundedRhombusImageView) cornerRadius = typedArray.getDimension(R.styleable.RoundedRhombusImageView_cornerRadius, cornerRadius) typedArray.recycle() } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) clipPath.reset() // 菱形四个顶点坐标 val top = Pair(w / 2f, 0f) val right = Pair(w.toFloat(), h / 2f) val bottom = Pair(w / 2f, h.toFloat()) val left = Pair(0f, h / 2f) // 绘制顶部圆角 clipPath.moveTo(top.first, top.second + cornerRadius) clipPath.quadTo(top.first, top.second, top.first + cornerRadius, top.second) // 绘制右侧圆角 clipPath.lineTo(right.first - cornerRadius, right.second) clipPath.quadTo(right.first, right.second, right.first, right.second + cornerRadius) // 绘制底部圆角 clipPath.lineTo(bottom.first, bottom.second - cornerRadius) clipPath.quadTo(bottom.first, bottom.second, bottom.first - cornerRadius, bottom.second) // 绘制左侧圆角 clipPath.lineTo(left.first + cornerRadius, left.second) clipPath.quadTo(left.first, left.second, left.first, left.second - cornerRadius) clipPath.close() } override fun onDraw(canvas: Canvas?) { canvas?.clipPath(clipPath) super.onDraw(canvas) } }
另外要记得在res/values/attrs.xml里添加自定义属性,这样就能在布局里直接设置圆角大小了:
<declare-styleable name="RoundedRhombusImageView"> <attr name="cornerRadius" format="dimension" /> </declare-styleable>
布局里使用示例:
<com.yourpackage.RoundedRhombusImageView android:layout_width="200dp" android:layout_height="200dp" android:src="@drawable/your_image" app:cornerRadius="16dp" />
一些注意事项
- 不管哪种方式,都要确保View的宽高设置合理,比如固定大小或者匹配父布局,不然菱形的形状会变形。
- 如果需要适配低版本系统(API < 18),记得给自定义View添加
android:layerType="software"关闭硬件加速,不然裁剪路径可能不生效。
内容的提问来源于stack exchange,提问作者Gopal Singoriya
相关产品推荐
相关产品推荐

