Android 自定义View之BubbleImageView

文章目录

  • [Android 自定义View之BubbleImageView](#Android 自定义View之BubbleImageView)

Android 自定义View之BubbleImageView

效果

代码

xml 复制代码
<declare-styleable name="BubbleImageView">
    <attr name="radius" format="dimension" />
    <attr name="triangle_width" format="dimension" />
    <attr name="triangle_height" format="dimension" />
    <attr name="triangle_top" format="dimension" />
    <attr name="direction" format="integer">
        <enum name="left" value="1" />
        <enum name="right" value="2" />
    </attr>
</declare-styleable>
kotlin 复制代码
class BubbleImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {

    private val path = Path()
    private var triangleWidth = DEFAULT_TRIANGLE_WIDTH // 气泡三角形的宽度
    private var triangleHeight = DEFAULT_TRIANGLE_HEIGHT // 气泡三角形的高度
    private var triangleTop = DEFAULT_TRIANGLE_TOP // 气泡三角形距离顶部距离
    private var direction = DEFAULT_DIRECTION // 气泡方向
    private var radius = DEFAULT_RADIUS // 圆角

    init {
        val a = context.obtainStyledAttributes(attrs, R.styleable.BubbleImageView)
        triangleWidth = a.getDimension(
            R.styleable.BubbleImageView_triangle_width,
            DEFAULT_TRIANGLE_WIDTH
        )
        triangleHeight = a.getDimension(
            R.styleable.BubbleImageView_triangle_height,
            DEFAULT_TRIANGLE_HEIGHT
        )
        triangleTop = a.getDimension(
            R.styleable.BubbleImageView_triangle_top,
            DEFAULT_TRIANGLE_TOP
        )
        direction = a.getInt(
            R.styleable.BubbleImageView_direction,
            DEFAULT_DIRECTION
        )
        radius = a.getDimension(
            R.styleable.BubbleImageView_radius,
            DEFAULT_RADIUS
        )
        a.recycle()
    }

    override fun onDraw(canvas: Canvas) {
        path.reset()
        when (direction) {
            LEFT -> {
                // 绘制三角形
                path.moveTo(triangleWidth, triangleTop)
                path.lineTo(0F, triangleTop + triangleHeight / 2)
                path.lineTo(triangleWidth, triangleTop + triangleHeight)
                path.close()
                // 绘制圆角矩形
                path.addRoundRect(
                    triangleWidth,
                    0F,
                    measuredWidth.toFloat(),
                    measuredHeight.toFloat(),
                    radius,
                    radius,
                    Path.Direction.CW
                )
            }

            RIGHT -> {
                path.moveTo(measuredWidth - triangleWidth, triangleTop)
                path.lineTo(measuredWidth.toFloat(), triangleTop + triangleHeight / 2)
                path.lineTo(measuredWidth - triangleWidth, triangleTop + triangleHeight)
                path.close()
                path.addRoundRect(
                    0F,
                    0F,
                    measuredWidth - triangleWidth,
                    measuredHeight.toFloat(),
                    radius,
                    radius,
                    Path.Direction.CW
                )
            }
        }
        canvas.clipPath(path)
        super.onDraw(canvas)
    }

    companion object {
        private const val LEFT = 1
        private const val RIGHT = 2
        private val DEFAULT_RADIUS = 10F.dp
        private val DEFAULT_TRIANGLE_WIDTH = 10F.dp
        private val DEFAULT_TRIANGLE_HEIGHT = 10F.dp
        private val DEFAULT_TRIANGLE_TOP = 20F.dp
        private const val DEFAULT_DIRECTION = LEFT
    }
}

使用:

xml 复制代码
<com.xiangxiongfly.core.widgets.bubble.BubbleImageView
    android:layout_width="100dp"
    android:layout_height="200dp"
    android:scaleType="centerCrop"
    android:src="@drawable/dark_image" />

<com.xiangxiongfly.core.widgets.bubble.BubbleImageView
    android:layout_width="100dp"
    android:layout_height="200dp"
    android:layout_marginTop="10dp"
    android:scaleType="centerCrop"
    android:src="@drawable/dark_image"
    app:direction="right" />

源码

相关推荐
火柴就是我8 小时前
让我们实现一个更好看的内部阴影按钮
android·flutter
砖厂小工15 小时前
用 GLM + OpenClaw 打造你的 AI PR Review Agent — 让龙虾帮你审代码
android·github
张拭心15 小时前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心16 小时前
Android 17 来了!新特性介绍与适配建议
android·前端
Kapaseker18 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴18 小时前
Android17 为什么重写 MessageQueue
android
阿巴斯甜2 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker2 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95272 天前
Andorid Google 登录接入文档
android
黄林晴2 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack