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

源码

相关推荐
2501_9160088915 分钟前
没有源码如何加密 IPA 实战流程与多工具组合落地指南
android·ios·小程序·https·uni-app·iphone·webview
2501_940094021 小时前
PS1模拟器 DuckStation更新最新版整合 下载即玩 附PS1Bios/游戏/金手指 安卓版+电脑版
android·游戏·电脑
橙武低代码3 小时前
业务流低代码平台:从理念到实战
android·低代码·ai编程
空白格973 小时前
三方框架必学系列#Retrofit
android
安卓程序猿4 小时前
kotlin build.gradle.kts下修改APK的输出名称
android·kotlin·gradle
wuwu_q4 小时前
通俗易懂 + Android 开发实战的方式,详细讲讲 Kotlin 中的 StateFlow
android·开发语言·kotlin
峰哥的Android进阶之路4 小时前
Kotlin面试题总结
android·开发语言·kotlin
美摄科技4 小时前
android短视频sdk,灵活集成,快速上线!
android·音视频
佳哥的技术分享4 小时前
图形化android可视化开机观测工具bootchart
android
杨筱毅4 小时前
【底层机制】 Android ION内存分配器深度解析
android·底层机制