0

I have an app that takes in input from the user and then on the clicking of a button displays the calculated results in a format like so:

123456
213456
214356
124365

I need a line ( preferably blue) to join each of the number 2's in the list as they make their way down the TextView.

I also need the option of not having this line if the user does not want it.

What I have tried so far: I extended a TextView class and overrode the onDraw(Canvas) method and tried to get something working and managed to display vertical blue lines but couldnt get the joining of the number 2's. I am unsure how android decides when onDraw() is called, as I dont call it in my code but I would rather I could so I could control when it displays the lines or not.

Allan Macmillan
  • 1,481
  • 3
  • 18
  • 30
  • Couldn't you draw the '2's in another color? It would be easier to do, and maybe better looking ;) – nicopico Oct 14 '13 at 23:04
  • Trust me, you don't need to "control" `onDraw()`. There is no need since an `invalidated()` view will have a message on the queue to call it anyway and this all has nothing to do with drawing lines. You will need a complex control for this and measure the text. http://stackoverflow.com/questions/3257293/measuring-text-width-to-be-drawn-on-canvas-android – Simon Oct 14 '13 at 23:17
  • 1
    Check my answer below but I think that you should provide some more code, to explain us what have you tried so far. – Claudio Ferraro Oct 15 '13 at 22:50

2 Answers2

0

I would proceed this way.

  • The user enters the value and clicks the button
  • As the button is tapped hide the TextView and replace it with an ImageView or keep the TextView and put the ImageView on the top of the TextView (Overlap of the ImageView on the TextView can be achieved with a FrameLayout
  • Draw in the ImageView the lines and the numbers in the OnDraw() method
  • As the user taps on the ImageView, hide the ImageView and display the TextView again.

Finally if the position of the 2's is fixed you don't need to measure the text. If the posision is not fixed you can put the numbers in an array. Here is some code in mixed order (not tested)

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() // ??

Get a look also to getTextBounds() if you wanna to get the text height too.

About the onDraw method, don't take care of how much time it will be called by the system, if performance is critical just mantain the scope of the variables containing the results and the precalculations global, put in the main class the properties and methods that controls the behaviour of the drawing method. The system will redraw every time the lines again and again as soon as another element overlaps your control or something happens in the system so the fact that the onDraw is called again and again is normal, otherwise your lines will not be redrawn again and could disappear from the screen if something happens. Of course the code above can be also put in a custom control (combined control).

To clear the lines you should call the invalidate() or postInvalidate() method. This methods will clear the whole area and force the onDraw() to be called again. Then put globally a flag like

shouldRedrawLines = false;

and in the onDraw() do something like this:

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

Simple not ?

Claudio Ferraro
  • 4,551
  • 6
  • 43
  • 78
0

This is only idea:

What you have:

  • Given the text size lets say: 20px

  • X and Y coordinates of the view.

  • Gravity supplied to the content by the TextView if any

  • Text size in px. getTextSize() or paint.measureText(); [rect.right on Canvas is the text size]

  • Text ems. getEms()

  • Optional: Padding or margin if any

What you need to find:

  • Each x-coordinate of each letter on the canvas.

  • Each y-coordinate of each letter on the canvas.

How to:

  • x = letter position in the text * font size(or ems). if there is padding or margin add padding left + padding right to the x; [rect.left on Canvas is x]

  • Reset letter position each new line

  • y = line number * font size (or ems). + padding top + padding bottom [rect.bottom on Canvas is y]

  • Collect all approximate x and y's to form a Point.

  • Match each Point in onDraw()

If you think you want to use paint.measureText("13332", 0, "13332".indexOf("2")), measured width will be approximate and absolute to itself x-coordinate of "2". Relative to its parent might be much more complex to find.

Edit: What I wrote above can be easily obtained using paint.[getTextBounds()][1] method which will give you Rect from which you can form a Point

Nikola Despotoski
  • 49,966
  • 15
  • 119
  • 148
  • If I manage to get this working how can I show and unshow the line? – Allan Macmillan Oct 15 '13 at 10:28
  • "Each x-coordinate of each letter on the canvas." Don't understand the need to get coordinates of each letter, it would be sufficient to get the cordinates of where to draw the lines and maybe the coordinates of the 2's . If I understood well the question. Redraw will do the rest. – Claudio Ferraro Oct 22 '13 at 11:49
  • Thats exactly the purpose of finding x of each letter, later we are interested only of 2's so we discard all of `Point`s and start drawing from the 2's `Point`. – Nikola Despotoski Oct 22 '13 at 15:38