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

Posted

技术标签:

【中文标题】如何在 Android Canvas 中绘制带有文本的矩形按钮?【英文标题】:How to draw a Button like rectangle with text in Android Canvas? 【发布时间】:2021-06-30 00:43:03 【问题描述】:

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

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

        val corners = floatArrayOf(
                80f, 80f,   // Top left radius in px
                80f, 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, corners, Path.Direction.CW)
        canvas?.drawPath(path, 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, 300f ,paint2);

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

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

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

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

请帮帮我

【问题讨论】:

【参考方案1】:

这是其中一种方法。不要忘记在custom attributes 中移动所有变量,如文本、文本大小等。我也不明白“画布中的点击监听器”是什么意思

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, boxRadius, boxShadowPaint)
    canvas?.drawRoundRect(boxBackground, boxRadius, boxRadius, 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)

【讨论】:

我认为他们只是想在视图上设置一个点击监听器,可能是在上面绘制了按钮的部分。您的解决方案填充了视图的画布,所以这一切都很好,但是如果他们试图在一个画布上绘制一堆按钮,他们将需要在点击侦听器中使用某种“用户触摸了哪些部分”逻辑 好的,然后创建List<Rect> 放置在画布上的所有按钮并使用onSingleTapUp 注册GestureDetector 得到xy 单击的坐标并检查哪个按钮来自哪个按钮是有意义的该列表是在此坐标中触发的。

以上是关于如何在 Android Canvas 中绘制带有文本的矩形按钮?的主要内容,如果未能解决你的问题,请参考以下文章

如何绘制带有边框和高程的CardView到Canvas?

Android绘制工具Canvas

如何在 Android Canvas 中使用“倒置”绘画进行绘制?

如何在带有Canvas的Kibana中使用Elastic SQL绘制时间序列直方图?

android中,如何用canvas绘制透明?

Android自定义组件系列——Canvas绘制折线图