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" />

源码

相关推荐
程序员陆业聪2 小时前
从 OpenClaw 到 Android:Harness Engineering 是怎么让 Agent 变得可用的
android
hnlgzb4 小时前
常见的Android Jetpack库会有哪些?这些库中又有哪些常用类的?
android·android jetpack
钛态7 小时前
Flutter 三方库 http_mock_adapter — 赋能鸿蒙应用开发的高效率网络接口 Mock 与自动化测试注入引擎(适配鸿蒙 HarmonyOS Next ohos)
android·网络协议·flutter·http·华为·中间件·harmonyos
王码码20357 小时前
Flutter for OpenHarmony:Flutter 三方库 algoliasearch 毫秒级云端搜索体验(云原生搜索引擎)
android·前端·git·flutter·搜索引擎·云原生·harmonyos
左手厨刀右手茼蒿7 小时前
Flutter for OpenHarmony: Flutter 三方库 shamsi_date 助力鸿蒙应用精准适配波斯历法(中东出海必备)
android·flutter·ui·华为·自动化·harmonyos
代码飞天8 小时前
wireshark的高级使用
android·java·wireshark
2501_915918419 小时前
苹果App Store上架审核卡住原因分析与解决方案指南
android·ios·小程序·https·uni-app·iphone·webview
skiy9 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
小小小点9 小时前
Android四大常用布局详解与实战
android
MinQ10 小时前
binder和socket区别及原理
android