如何在Android Canvas中绘制带有文本的矩形按钮?

问题描述

在Android应用程序中,我想在画布上绘制一个按钮,就像下图一样

campsitebutton

我尝试了一些堆栈溢出的答案,但无法获得确切的输出,尤其是下面的光影。我最糟糕的代码如下

        val corners = floatArrayOf(
                80f,80f,// Top left radius in px
                80f,// Top right radius in px
                0f,0f,// Bottom right radius in px
                0f,0f      // Bottom left radius in px
        )

        val path = Path()
        val rect = RectF(550f,500f,100f,300f)

        paint.style = Paint.Style.FILL;
        paint.color = Color.WHITE;
        path.addRoundRect(rect,corners,Path.Direction.CW)
        canvas?.drawPath(path,paint)

        paint.style = Paint.Style.stroke;
        paint.color = Color.BLACK;
        path.addRoundRect(rect,paint)

        paint.setColor(Color.RED)
        paint.setStyle(Paint.Style.FILL)
        val paint2 = Paint()
        paint2.setColor(Color.GREEN)
        paint2.setTextSize(50f) //set text size

        val w: Float = paint2.measureText("VIEW CAMPSITE MAP") / 2
        val textSize: Float = paint2.textSize
        canvas?.drawText("VIEW CAMPSITE MAP",300f,paint2);

我也无法在正确的位置设置文本

我还需要一个渐变来像真正的材质按钮一样显示凸出状态

并且还需要在画布/绘画中的点击侦听器

我需要它在纯画布上,而不是在任何视图中绘画

请帮帮我

解决方法

这是其中一种方法。不要忘记在 custom attributes 中移动所有变量,例如 text、textSize 等。我也没有明白“在画布中单击侦听器”是什么意思

enter image description here

class CustomView @JvmOverloads constructor(
context: Context,attrs: AttributeSet? = null,defStyleAttr: Int = 0
      ) : View(context,attrs,defStyleAttr) {

//constants. move them all to custom attributes
private val boxRadius = convertDpToPixel(10f)
private val boxColor = Color.parseColor("#52618e")
private val boxBackgroundColor = Color.WHITE
private val boxShadowSize = convertDpToPixel(2f)
private val boxStrokeWidth = convertDpToPixel(1f)
private val textColor = Color.parseColor("#21a207")
private val fontSize = convertDpToPixel(30f)
private val text = "View Campsite Plan"

private lateinit var boxShadow: RectF
private lateinit var boxBackground: RectF
private lateinit var boxShadowPaint: Paint
private lateinit var boxBackgroundPaint: Paint
private var textWidth = 0f
private var textSmallGlyphHeight = 0f
private lateinit var textPaint: Paint

  override fun onSizeChanged(w: Int,h: Int,oldw: Int,oldh: Int) {
    boxShadow = RectF(0f,0f,w.toFloat(),h.toFloat())
    boxBackground = RectF(boxStrokeWidth,boxStrokeWidth,w.toFloat()-boxStrokeWidth,h.toFloat()-boxStrokeWidth-boxShadowSize)
    boxShadowPaint = Paint().apply { color = boxColor }
    boxBackgroundPaint = Paint().apply { color = boxBackgroundColor }
    textPaint = Paint().apply {
        color = textColor
        textSize = fontSize
        typeface = Typeface.create(Typeface.DEFAULT,Typeface.BOLD)
        textWidth = measureText(text)
        textSmallGlyphHeight = fontMetrics.run { ascent + descent }
    }
  }

  override fun onDraw(canvas: Canvas?) {
    canvas?.drawRoundRect(boxShadow,boxRadius,boxShadowPaint)
    canvas?.drawRoundRect(boxBackground,boxBackgroundPaint)
    val textStartPadding = (width - textWidth)/2f
    val textTopPadding = (height - textSmallGlyphHeight)/2f
    canvas?.drawText(text,textStartPadding,textTopPadding,textPaint)
  }

  private fun convertDpToPixel(dp: Float) =
    dp*(resources.displayMetrics.densityDpi/DisplayMetrics.DENSITY_DEFAULT)
}