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()方法没用起来,继续进阶学习...

相关推荐
EatFan1 分钟前
React 项目踩坑实录:useEffect 闭包陷阱、Context 性能陷阱与 React 18 升级避坑排查手册
前端·javascript·react.js·react·react hooks·useeffect·闭包陷阱
风骏时光牛马35 分钟前
企业业务运营信息数据库
前端
IT_陈寒1 小时前
Vue的数组更新把我坑惨了
前端·人工智能·后端
于航1 小时前
分层上下文压缩,幻觉检测,错误累积概要
前端
数据掘金1 小时前
鸿蒙统计的权限弹窗怎么适配?
前端
数据掘金1 小时前
鸿蒙统计的多设备协同数据怎么打通?
前端
尘中远1 小时前
Qwt7的曲线渲染平滑实现:高斯卷积、Savitzky-Golay 回归与特征保护
前端
Fly2 小时前
我来提需求,你带着 Codex 做项目:AI 全栈课程开始实战了
前端
集智飞行3 小时前
解决mavros2 ros2版本cpu占用高的问题
java·服务器·前端
HSunR4 小时前
ruoyi 若依 自定义注解 参数校验
java·前端·数据库