【问题标题】:Android - Drawing Lines In A TextViewAndroid - 在 TextView 中绘制线条
【发布时间】:2013-10-14 22:59:11
【问题描述】:

我有一个应用程序,它接收用户的输入,然后单击按钮以如下格式显示计算结果:

123456
213456
214356
124365

当它们沿着 TextView 向下移动时,我需要一条线(最好是蓝色的)来加入列表中的每个数字 2。

如果用户不想要,我还需要选择不设置此行。

到目前为止我所尝试的: 我扩展了一个 TextView 类并覆盖了 onDraw(Canvas) 方法,并试图让某些东西正常工作并设法显示垂直的蓝线,但无法获得数字 2 的加入。我不确定 android 是如何决定何时调用 onDraw() 的,因为我没有在我的代码中调用它,但我希望我可以控制它何时显示线条。

【问题讨论】:

  • 你不能把'2'画成另一种颜色吗?这样做会更容易,而且可能会更好看;)
  • 相信我,你不需要“控制”onDraw()。没有必要,因为invalidated() 视图将在队列中显示一条消息以调用它,而这一切都与绘制线条无关。为此,您将需要一个复杂的控件并测量文本。 stackoverflow.com/questions/3257293/…
  • 在下面查看我的答案,但我认为您应该提供更多代码,以向我们解释您到目前为止尝试了什么。

标签: java android textview


【解决方案1】:

这只是想法:

你有什么:

  • 给定文本大小让我们说:20px

  • 视图的 X 和 Y 坐标。

  • TextView 为内容提供的重力(如果有)

  • 以像素为单位的文本大小。 getTextSize() or paint.measureText(); [rect.right on Canvas 是文字大小]

  • 文本 ems。 getEms()

  • 可选:填充或边距(如果有)

您需要找到的内容:

  • 画布上每个字母的每个 x 坐标。

  • 画布上每个字母的每个 y 坐标。

如何:

  • x = 文本中的字母位置 * 字体大小(或 ems)。如果有填充或边距,则向 x 添加填充左侧 + 右侧填充; [画布上的rect.left是x]

  • 每换行重置字母位置

  • y = 行号 * 字体大小(或 ems)。 + padding top + padding bottom [画布上的rect.bottom是y]

  • 收集所有近似的 x 和 y 以形成 Point

  • 匹配onDraw()中的每个Point

如果你认为你想使用paint.measureText("13332", 0, "13332".indexOf("2")),测量的宽度将是近似和绝对的,它自身的 x 坐标为“2”。相对于其父级的查找可能要复杂得多。

编辑: 使用paint.[getTextBounds()][1] 方法可以轻松获得我上面写的内容,该方法将为您提供Rect,您可以从中形成Point

【讨论】:

  • 如果我设法让它工作,我该如何显示和取消显示该行?
  • "画布上每个字母的每个 x 坐标。"不了解获取每个字母的坐标的需要,获取绘制线条的位置的坐标以及可能是 2's 的坐标就足够了。如果我很好地理解了这个问题。重绘将完成剩下的工作。
  • 这正是寻找每个字母的 x 的目的,后来我们只对 2 感兴趣,所以我们丢弃所有 Points 并从 2 的 Point 开始绘制。
【解决方案2】:

我会这样做。

  • 用户输入值并点击按钮
  • 点击按钮时隐藏 TextView 并用 ImageView 替换它或保留 TextView 并将 ImageView 放在 TextView 的顶部(可以通过 FrameLayout 实现 ImageView 在 TextView 上的重叠
  • 在 ImageView 中用 OnDraw() 方法绘制线条和数字
  • 当用户点击 ImageView 时,隐藏 ImageView 并再次显示 TextView。

最后,如果 2 的位置是固定的,则无需测量文本。 如果位置不固定,您可以将数字放入数组中。这是一些混合顺序的代码(未测试)

var resStr1 = Integer.toString(resultNumber);
var position = 0;

...
// METHOD 1, multiple 2's in a number
var j = 0;
for (int i = 0; i < resStr1.length(); i++){

    char c = s.charAt(i);
    if (c == '2') {
        position[j] = i;
        j++;
    }
}

// METHOD 2. ONLY ONE 2 in a number
position = resStr1.indexOf('2');



// CONTINUE
...
Paint p = new Paint();
...
float left = customMarginLeft + p.measureText(resStr1.substring(0, position)); 
float top = customMarginTop;
...
canvas.drawRect( bla bla bla...
drawText() // ??

如果您也想获取文本高度,还可以查看 getTextBounds()。

关于 onDraw 方法,不要关心它会被系统调用多少时间,如果性能很关键,只需保持包含结果的变量范围和全局预计算,放在主类中控制绘图方法行为的属性和方法。每当另一个元素与您的控件重叠或系统中发生某些事情时,系统将一次又一次地重绘线条,因此一次又一次调用 onDraw 的事实是正常的,否则您的线条将不会再次重绘并且可能会消失如果发生任何事情,请从屏幕上显示。 当然上面的代码也可以放在自定义控件(组合控件)中。

要清除这些行,您应该调用 invalidate() 或 postInvalidate() 方法。此方法将清除整个区域并强制再次调用 onDraw()。然后全局放置一个像

这样的标志
shouldRedrawLines = false;

在 onDraw() 中做这样的事情:

if (shouldRedrawLines) { // please note that the onDraw is called again and again and this condition allows you to check if in another part of the program you decided to clear the lines
    DrawLines();  // contains the code for redrawing lines
}
DrawNumbersFromResult(); // contains the code for redrawing Numbers

简单不?

【讨论】:

    猜你喜欢
    • 2011-12-23
    • 2011-06-19
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多