Android的自定义View

测量-measure

布局-layout

绘制-draw

三大流程

练练手

来点自定义属性:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomView">
        <attr name="customColor" format="color" />
        <attr name="customText" format="string" />
        <attr name="customSize" format="dimension" />
    </declare-styleable>
</resources>

再来点代码时鲜:

kotlin 复制代码
package com.mircles.test.ui

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.view.View
import androidx.annotation.StyleRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.withStyledAttributes
import com.mircles.test.R
import kotlin.math.min


class CustomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    private var mPaint: Paint = Paint().apply {
        color = Color.BLACK
        style = Paint.Style.FILL
    }

    //定义变量来存储自定义属性值
    private var customColor: Int = Color.BLUE
    private var customSize: Float = 100f
    private var customText: String = "Say"


    init {

        //context.obtainStyledAttributes()
        //withStyledAttributes是obtainStyledAttributes的扩展函数,可以学学谷歌的工程师是怎么做扩展的
        context.withStyledAttributes(
            attrs,
            R.styleable.CustomView,
            defStyleAttr = defStyleAttr
        ) {
            customColor = getColor(R.styleable.CustomView_customColor, Color.BLACK)
            customSize = getDimension(R.styleable.CustomView_customSize, 100f)
            customText = getString(R.styleable.CustomView_customText) ?: "hello"

            //应用到画笔中
            mPaint.color = customColor

        }

    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val desiredWidth = 200 // 你期望的默认宽度(像素)
        val desiredHeight = 200 // 你期望的默认高度(像素)

        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)



        // 测量宽度
        val width = when (widthMode) {
            MeasureSpec.EXACTLY -> widthSize
            MeasureSpec.AT_MOST -> min(desiredWidth, widthSize)
            else -> desiredWidth
        }


        // 测量高度
        val height = when (heightMode) {
            MeasureSpec.EXACTLY -> heightSize
            MeasureSpec.AT_MOST -> min(desiredHeight, heightSize)
            else -> desiredHeight
        }

        setMeasuredDimension(width, height)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        // 绘制一个圆形
        val centerX = width / 2f
        val centerY = height / 2f
        val radius = min(centerX, centerY) - 10
        canvas.drawCircle(centerX, centerY, radius, mPaint)


        // 绘制文字
        val textPaint = Paint().apply {
            color = Color.BLUE
            textSize = customSize
            textAlign = Paint.Align.CENTER
        }
        //计算文字基线位置,使文字垂直居中:可以留意计算的思路
        val textBounds = Rect()
        textPaint.getTextBounds(customText,0,customText.length,textBounds)
        val textY = centerY - (textBounds.top+textBounds.bottom)/2f

        canvas.drawText(customText, centerX, textY, textPaint)

    }

    //提供设置方法以便在代码中动态修改
    fun setCustomColor(color:Int){
        customColor = color
        mPaint.color = color
        invalidate()
    }

    fun setCustomText(text: String){
        customText = text
        invalidate()
    }
    fun setCustomSize(size: Float){
        customSize = size
        invalidate()
    }

    // 如果你想要从样式资源中获取属性
    fun applyStyle(@StyleRes styleRes: Int) {
        context.withStyledAttributes(styleRes, R.styleable.CustomView) {
            customColor = getColor(R.styleable.CustomView_customColor, customColor)
            customSize = getDimension(R.styleable.CustomView_customSize, customSize)
            customText = getString(R.styleable.CustomView_customText) ?: customText
            mPaint.color = customColor
            invalidate()
        }
    }



}


@Composable
fun CircleOO() {
    AndroidView(
        factory = { context ->
            CustomView(context).apply {
                setCustomText("卧槽")
                setCustomSize(50f)
                setCustomColor(Color.DKGRAY)
            }
        },
        update = { cv ->

        }
    )
}

@Preview(showBackground = true)
@Composable
fun PreviewUI() {
    CircleOO()
}

还可以添加更多的属性,文字的规格样式、背景的规格样式等等。 还有onLayout()方法没用起来,继续进阶学习...

相关推荐
朱建伟3 小时前
大神尤雨溪再次出手,前端工具链整合--该文章是对vite plus官方README文档进行了翻译
前端·vite
vball3 小时前
宏观数据从哪里来?——主流宏观经济数据库与API全景
前端
吠品3 小时前
Vue项目Moment.js引入优化:全局挂载与按需引入的深度解析与最佳实践
前端·javascript·vue.js
不甜情歌3 小时前
JS 类型判断不用愁:4 种方法,覆盖所有场景
前端·javascript
ETA84 小时前
状态管理没那么复杂:手写实现 Zustand 核心逻辑
前端·react.js
用户255778850814 小时前
axios请求缓存
前端
夫瑞4 小时前
TypeScript 直接编译成原生二进制,没有浏览器,没有 V8
前端
Talents4 小时前
OpenLayers 7.5.2 判断点是否在区域边上
前端
cmd4 小时前
前端基础必看:JS 变量提升 & 函数提升完整解析
前端·javascript
小金鱼Y4 小时前
前端必看:this 不是玄学!5 大绑定规则帮你永久告别 this 困惑
前端·javascript·面试