Objectives:
Draw Chinese characters to the center of the target rectangle.
Problem:
In the Canvas drawing of Android, the origin in drawText is baseline and is directly transmitted to drawText based on the bottom of the target rectangle. The character position is down. Write the Code as follows:
@ Overridepublic void onDraw (Canvas canvas) {Rect targetRect = new Rect (50, 50,100 0, 200); Paint paint = new Paint (Paint. ANTI_ALIAS_FLAG); paint. setStrokeWidth (3); paint. setTextSize (80); String testString = "test: ijkJQKA: 1234"; paint. setColor (Color. CYAN); canvas. drawRect (targetRect, paint); paint. setColor (Color. RED); canvas. drawText (testString, targetRect. left, targetRect. bottom, paint );}The following is an ugly result:
Find a solution:
First, let's do the experiment by hand, set a baseline, draw the text, and draw several lines of FontMetrics. FontMetrics contains the font pattern information, including float and int versions, which can be obtained from the Paint. Each of its member values is calculated based on baseline, so the negative value is above baseline. Lab code:
@ Overridepublic void onDraw (Canvas canvas) {Paint paint = new Paint (Paint. ANTI_ALIAS_FLAG); paint. setStrokeWidth (3); paint. setTextSize (80); FontMetricsInt fmi = paint. getFontMetricsInt (); String testString = "test: ijkJQKA: 1234"; Rect bounds1 = new Rect (); paint. getTextBounds ("test", 0, 1, bounds1); Rect bounds2 = new Rect (); paint. getTextBounds ("test: ijk", 0, 6, bounds2); // set a random position as baselineint x = 200; int y = 4 00; // draw testString on baseline canvas. drawText (testString, x, y, paint); // bounds1paint. setStyle (Style. STROKE); // draw a hollow rectangular canvas. save (); canvas. translate (x, y); // note that there is translate here. The rectangle obtained by getTextBounds is also the baseline-based paint. setColor (Color. GREEN); canvas. drawRect (bounds1, paint); canvas. restore (); // bounds2canvas. save (); paint. setColor (Color. MAGENTA); canvas. translate (x, y); canvas. drawRect (bounds2, paint); canvas. restore (); // baselinepaint. setColor (Color. RED); canvas. drawLine (x, y, 1024, y, paint); // ascentpaint. setColor (Color. YELLOW); canvas. drawLine (x, y + fmi. ascent, 1024, y + fmi. ascent, paint); // descentpaint. setColor (Color. BLUE); canvas. drawLine (x, y + fmi. descent, 1024, y + fmi. descent, paint); // toppaint. setColor (Color. DKGRAY); canvas. drawLine (x, y + fmi. top, 1024, y + fmi. top, paint); // bottompaint. setColor (Color. GREEN); canvas. drawLine (x, y + fmi. bottom, 1024, y + fmi. bottom, paint );}Result:
The red line is baseline, the top gray line is FontMetrics. top, and the bottom green line is FontMetrics. bottom. (The green bottom and the blue descent are very close)
Yes,The character itself is centered between the gray line and the Green LineYou can understand this. Use paint. the getTextBounds method is unreliable. You can see that the bounds obtained from a "test" word and six words are different, the rectangle in the figure can represent the character boundary of the function, rather than the font boundary.
The FontMetrics. top value is a negative number, and its absolute value is the distance from the character draw boundary to baseline.
Therefore, if you want to draw text in a FontMetrics height rectangle, drawText should be passed in-FontMetrics. top.
The baseline calculation formula is as follows:
TargetRect. top + (targetRect. bottom-targetRect. top)/2-(FontMetrics. bottom-FontMetrics. top)/2-FontMetrics. top
Solution:
So the initial code should be changed to (by the way, the horizontal center should be added ):
@ Overridepublic void onDraw (Canvas canvas) {Rect targetRect = new Rect (50, 50,100 0, 200); Paint paint = new Paint (Paint. ANTI_ALIAS_FLAG); paint. setStrokeWidth (3); paint. setTextSize (80); String testString = "test: ijkJQKA: 1234"; paint. setColor (Color. CYAN); canvas. drawRect (targetRect, paint); paint. setColor (Color. RED); FontMetricsInt fontMetrics = paint. getFontMetricsInt (); // reprinted please indicate the source: http://blog.csdn.net/hursingint baseline = targetRect. top + (targetRect. bottom-targetRect. top-fontMetrics. bottom + fontMetrics. top)/2-fontMetrics. top; // The following row is horizontally centered. The drawText field is changed to targetRect. centerX () paint. setTextAlign (Paint. align. CENTER); canvas. drawText (testString, targetRect. centerX (), baseline, paint );}Effect (click to view the chart ):
Source code,
$ Android4.2/frameworks/base/corej/ava/android/text/BoringLayout. java is the TextView text painting algorithm.
Reprinted please indicate the source: http://blog.csdn.net/hursing