【问题标题】:How to draw text with different stroke and fill colors?如何用不同的笔触和填充颜色绘制文本?
【发布时间】:2012-01-28 11:04:40
【问题描述】:

我想在我的应用程序中显示如下文本。我正在使用Paint 风格的FILL_AND_STROKE 类来实现这一点。但是只有一种方法setColor()可以设置颜色。

如何设置不同的描边和填充颜色?

【问题讨论】:

    标签: java android paint


    【解决方案1】:

    不要使用 FILL_AND_STROKE。使用 FILL 绘制一次,然后更改颜色并使用 STROKE 绘制。

    (这适用于矩形。我不确定 STROKE 是否适用于文本。你必须尝试一下并找出答案。)

    【讨论】:

    • 我试过了,但是当笔画宽度更大时,结果文本看起来不太好。
    • 对于更大的文本大小和笔划宽度,生成的文本看起来很丑。
    【解决方案2】:
    import android.annotation.SuppressLint
    import android.content.Context
    import android.graphics.Canvas
    import android.graphics.Paint
    import android.graphics.Paint.Join
    import android.graphics.Rect
    import android.util.AttributeSet
    import android.widget.TextView
    
    @SuppressLint("AppCompatCustomView")
    class BorderTextView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : TextView(context, attrs, defStyleAttr) {
        private var strokeWidth: Float = 0F
        private val paintStroke = Paint(Paint.ANTI_ALIAS_FLAG)
    
        init {
            paint.color = currentTextColor
            paint.typeface = typeface
    
            if (attrs != null) {
                val a = context.obtainStyledAttributes(attrs, R.styleable.BorderTextView)
                if (a.hasValue(R.styleable.BorderTextView_strokeColor)) {
                    strokeWidth =
                        a.getDimensionPixelSize(R.styleable.BorderTextView_strokeWidth, 1).toFloat()
                    val strokeColor = a.getColor(R.styleable.BorderTextView_strokeColor, 0)
                    val strokeMiter =
                        a.getDimensionPixelSize(R.styleable.BorderTextView_strokeMiter, 10).toFloat()
                    var strokeJoin: Join? = null
                    when (a.getInt(R.styleable.BorderTextView_strokeJoinStyle, 2)) {
                        0 -> strokeJoin = Join.MITER
                        1 -> strokeJoin = Join.BEVEL
                        2 -> strokeJoin = Join.ROUND
                    }
                    setStroke(strokeWidth, strokeColor, strokeJoin, strokeMiter)
                }
                a.recycle()
            }
        }
    
        private fun setStroke(width: Float, color: Int, join: Join?, miter: Float) {
            paintStroke.strokeJoin = join
            paintStroke.strokeMiter = miter
            paintStroke.strokeWidth = width
            paintStroke.style = Paint.Style.STROKE
            paintStroke.color = color
            paintStroke.textSize = textSize
            paintStroke.typeface = typeface
            paintStroke.letterSpacing = letterSpacing
        }
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            this.setMeasuredDimension(measuredWidth + strokeWidth.toInt(), measuredHeight);
        }
        override fun onDraw(canvas: Canvas) {
            val r = Rect()
            paint.getTextBounds(text.toString(), 0, text.length, r)
            val desc = paint.descent()
            val asc = paint.ascent()
            val y = (height.toFloat() - (1 + asc + desc / 2F)) / 2F
            val x = width / 2f - r.width() / 2f - r.left
            canvas.drawText(text.toString(), x, y, paintStroke)
            canvas.drawText(text.toString(), x, y, paint)
        }
    }
    

    【讨论】:

      【解决方案3】:

      自定义 TextView 内部(在 EditText 中不起作用):

      @Override
      public void onDraw(Canvas canvas)
      {
          final ColorStateList textColor = getTextColors();
      
          TextPaint paint = this.getPaint();
      
          paint.setStyle(Style.STROKE);
          paint.setStrokeJoin(Join.ROUND);
          paint.setStrokeMiter(10);
          this.setTextColor(strokeColor);
          paint.setStrokeWidth(strokeWidth);
      
          super.onDraw(canvas);
          paint.setStyle(Style.FILL);
      
          setTextColor(textColor);
          super.onDraw(canvas);
      }
      

      【讨论】:

      • 如果您在自定义 EditText 中实现它,这将不起作用,在这种情况下会显示最后一个 setTextColor,知道为什么吗?
      • @Architact 很可能是因为从EditText 实现的onDraw 默认情况下会绘制背景,因此第二次调用会覆盖第一次调用。这仅适用于透明背景。如果背景不透明,您需要做的是从 super 复制整个 onDraw 并且只绘制两次文本。
      • 它将永远循环 onDraw
      • 警告!这将永远循环 onDraw 函数,递归
      【解决方案4】:

      我使用上面的第一个解决方案提出了这个想法:放下一个较大的 STROKE,文本,然后用较小的 FILL_AND_STROKE 文本覆盖它:

      mScorePaint = new TextPaint();
      mScorePaint.setTextSize(63);
      mScorePaint.setStyle(Style.STROKE);
      mScorePaint.setStrokeJoin(Join.ROUND);
      mScorePaint.setStrokeMiter(10.0f);
      mScorePaint.setStrokeWidth(frameWidth/50.0f); // about 12
      mScorePaint.setColor(0xffff0000); // black
      
      c.drawText(Integer.toString(mScore), x, y, mScorePaint);  // red first
      
      mScorePaint.setStrokeWidth(frameWidth/125.0f); // about 5
      mScorePaint.setColor(0xff000000); // red
      
      c.drawText(Integer.toString(mScore), x, y, mScorePaint);  // black on top
      

      因为单独的 FILL 看不到任何 Stroke 属性,而且非常薄。

      【讨论】:

      • 这太傻了,我就是想用TextView的布局参数,怎么知道应该把哪个x,y设置成c.drawText方法,没用
      【解决方案5】:

      不完全确定,但也许你可以使用这个:

      link

       TextView test = (TextView) findViewById(R.id.test);
      
       test.setShadowLayer(float, float, float, int);
      

      【讨论】:

      • 阴影层不同,它会在文字后面加上指定的颜色,然后文字会显得有些模糊。
      • 嗯,我想我明白你的意思了,它不会创建干净的边缘吧?我正在考虑使用将文本颜色设置为黑色和阴影红色之类的东西
      • 看看在“Hi”上,背景颜色的边缘不模糊,这就是我所说的干净边缘的意思
      • 没有阴影不会给出干净的边缘,它会显示模糊的颜色。
      【解决方案6】:

      先画笔画,再画文字。

      警告:setTextColor 将递归调用 onDraw,因此您需要避免这种情况,请参阅“callInvalidate”标志。

      class StrokeTextView @JvmOverloads constructor(
          context: Context,
          attrs: AttributeSet? = null,
          defStyleAttr: Int = android.R.attr.textViewStyle
      ) : AppCompatTextView(context, attrs, defStyleAttr) {
      
          private val realTextColor: ColorStateList = textColors
          private var strokeColor: ColorStateList? = null
          private var strokeWidth: Float? = null
      
          private var callInvalidate = true
      
          init {
              context.obtainStyledAttributes(attrs, R.styleable.StrokeTextView, defStyleAttr, 0).use {
                  strokeColor = it.getColorStateList(R.styleable.StrokeTextView_stroke_color)
                  strokeWidth = it.getDimension(R.styleable.StrokeTextView_stroke_width, 0F)
              }
          }
      
          override fun onDraw(canvas: Canvas) {
              if (strokeWidth != null && strokeWidth!! > 0 && strokeColor != null) {
                  //stroke
                  setTextColorOnDraw(strokeColor!!)
                  paint.style = Paint.Style.STROKE
                  paint.strokeWidth = strokeWidth!!
                  super.onDraw(canvas)
                  //text
                  setTextColorOnDraw(realTextColor)
                  paint.style = Paint.Style.FILL
                  paint.strokeWidth = 0F
                  super.onDraw(canvas)
              } else {
                  //default
                  super.onDraw(canvas)
              }
          }
      
          override fun invalidate() {
              if (callInvalidate) {
                  super.invalidate()
              }
          }
      
          /**
           * Call setTextColor in OnDraw.
           */
          private fun setTextColorOnDraw(colors: ColorStateList) {
              callInvalidate = false
              setTextColor(colors)
              callInvalidate = true
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-18
        • 2021-05-16
        • 1970-01-01
        • 2013-02-01
        • 2016-08-02
        • 2011-08-27
        相关资源
        最近更新 更多