Canvas drawText


Paint的一个测量字体的内部类

FontMetrics

FontMetrics fm = mTextPaint.getFontMetrics();


 /**
     * Class that describes the various metrics for a font at a given text size.
     * Remember, Y values increase going down, so those values will be positive,
     * and values that measure distances going up will be negative. This class
     * is returned by getFontMetrics().
     */
    public static class FontMetrics {
        /**
         * The maximum distance above the baseline for the tallest glyph in
         * the font at a given text size.
         */
        public float   top;
        /**
         * The recommended distance above the baseline for singled spaced text.
         */
        public float   ascent;
        /**
         * The recommended distance below the baseline for singled spaced text.
         */
        public float   descent;
        /**
         * The maximum distance below the baseline for the lowest glyph in
         * the font at a given text size.
         */
        public float   bottom;
        /**
         * The recommended additional space to add between lines of text.
         */
        public float   leading;
    }



这张图很简单但是也很扼要的说明了top,ascent,descent,bottom,leading这五个参数。首先我们要知道Baseline基线,在Android中,文字的绘制都是从Baseline处开始的,Baseline往上至字符最高处的距离我们称之为ascent(上坡度),Baseline往下至字符最底处的距离我们称之为descent(下坡度),而leading(行间距)则表示上一行字符的descent到该行字符的ascent之间的距离,top和bottom文档描述地很模糊,其实这里我们可以借鉴一下TextView对文本的绘制,TextView在绘制文本的时候总会在文本的最外层留出一些内边距,为什么要这样做?因为TextView在绘制文本的时候考虑到了类似读音符号,可能大家很久没写过拼音了已经忘了什么叫读音符号了吧……下图中的A上面的符号就是一个拉丁文的类似读音符号的东西:




top的意思其实就是除了Baseline到字符顶端的距离外还应该包含这些符号的高度,bottom的意思也是一样,一般情况下我们极少使用到类似的符号所以往往会忽略掉这些符号的存在,但是Android依然会在绘制文本的时候在文本外层留出一定的边距,这就是为什么top和bottom总会比ascent和descent大一点的原因。而在TextView中我们可以通过xml设置其属性android:includeFontPadding="false"去掉一定的边距值但是不能完全去掉。下面我们在Canvas上绘制一段文本并尝试打印文本的top,ascent,descent,bottom和leading:

class MyView extends View {

		private Paint mPaint;
		 private FontMetrics mFontMetrics;
		String text = "dfM★○€гежтkjǎíìǖл";
		
		public MyView(Context context) {
			super(context);
			mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
			
			mPaint.setTextSize(100);  
			//mPaint.setTypeface(Typeface.SERIF);  
			
			//TextSize和Typeface都会影响FontMetrics
			mFontMetrics = mPaint.getFontMetrics();
		    mPaint.setColor(Color.BLACK);
		    
		    Log.d("Font", "ascent:" + mFontMetrics.ascent);  
	        Log.d("Font", "top:" + mFontMetrics.top);  
	        Log.d("Font", "leading:" + mFontMetrics.leading);  
	        Log.d("Font", "descent:" + mFontMetrics.descent);  
	        Log.d("Font", "bottom:" + mFontMetrics.bottom);  
		}
		
		@Override
		protected void onDraw(Canvas canvas) {
			super.onDraw(canvas);
			canvas.drawColor(Color.WHITE);
			canvas.drawText(text, 0,Math.abs(mFontMetrics.top), mPaint);
		}
		
	}





我们把注释掉的打开

mPaint.setTypeface(Typeface.SERIF);  


同样所有的值也改变了,那么我们知道这样的一个东西有什么用呢?如上所说文本的绘制是从Baseline开始,并且Baseline并非文本的分割线,当我们想让文本绘制的时候居中屏幕或其他的东西时就需要计算Baseline的Y轴坐标,比如我们让我们的文本居中画布






局部放大图


class MyView extends View {

		private Paint textPaint,linePaint,tagPaint;
		 private FontMetrics mFontMetrics;
		String TEXT = "dfM★○€гежтkjǎíìǖл";
		private int baseX, baseY;// Baseline绘制的XY坐标  
		 Rect bounds ;
		public MyView(Context context) {
			super(context);
			textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
			textPaint.setDither(true);
			textPaint.setTextSize(120);  
//			textPaint.setTypeface(Typeface.SERIF);  
			
			//TextSize和Typeface都会影响FontMetrics
			mFontMetrics = textPaint.getFontMetrics();
			textPaint.setColor(Color.BLACK);
		    
			linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
	        linePaint.setStyle(Paint.Style.STROKE);  
	        linePaint.setStrokeWidth(1);  
	        linePaint.setColor(Color.RED);  
			
		    Log.d("Font", "ascent:" + mFontMetrics.ascent);  
	        Log.d("Font", "top:" + mFontMetrics.top);  
	        Log.d("Font", "leading:" + mFontMetrics.leading);  
	        Log.d("Font", "descent:" + mFontMetrics.descent);  
	        Log.d("Font", "bottom:" + mFontMetrics.bottom);  
	        bounds= new Rect();
	        
	        tagPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
	        tagPaint.setTextSize(50);
	        tagPaint.setStrokeWidth(20);
	        
		}
		
		@Override
		protected void onDraw(Canvas canvas) {
			super.onDraw(canvas);
			canvas.drawColor(Color.WHITE);
			   // 计算Baseline绘制的起点X轴坐标  
	        baseX = (int) (canvas.getWidth() / 2 - textPaint.measureText(TEXT) / 2);  
	  
	        // 计算Baseline绘制的Y坐标  
	        baseY = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2));  
	        canvas.drawText(TEXT, baseX, baseY, textPaint);  
	  
	        canvas.drawLine(0, canvas.getHeight() / 2, canvas.getWidth(), canvas.getHeight() / 2, linePaint); 
	        canvas.drawLine(canvas.getWidth()/2, 0, canvas.getWidth()/2, canvas.getHeight() , linePaint); 
	    	
	        
	        canvas.save();
	        canvas.translate(baseX, canvas.getHeight() / 2 - ((textPaint.descent() + textPaint.ascent()) / 2));
	        textPaint.getTextBounds(TEXT, 0, TEXT.length(), bounds);
	        canvas.drawRect(bounds, linePaint);  
	        canvas.restore();
	       
	        
	        
	        linePaint.setColor(Color.BLUE);
	        canvas.drawLine(baseX,baseY+mFontMetrics.top , baseX+textPaint.measureText(TEXT), baseY+mFontMetrics.top, linePaint);
	        tagPaint.setColor(Color.BLUE);
	        canvas.drawPoint(baseX, baseY+textPaint.descent() - textPaint.ascent(), tagPaint);
	        canvas.drawText("top", 
	        		baseX+20, 
	        		baseY+textPaint.descent() - textPaint.ascent()-(tagPaint.descent()+tagPaint.ascent())/2,
	        		tagPaint);
	        
	        
	        
	        linePaint.setColor(Color.GREEN);
	        canvas.drawLine(baseX,baseY+mFontMetrics.ascent , baseX+textPaint.measureText(TEXT), baseY+mFontMetrics.ascent, linePaint);
	        tagPaint.setColor(Color.GREEN);
	        canvas.drawPoint(baseX, baseY+textPaint.descent() - textPaint.ascent()+50, tagPaint);
	        canvas.drawText("ascent", 
	        		baseX+20, 
	        		baseY+textPaint.descent() - textPaint.ascent()+50-(tagPaint.descent()+tagPaint.ascent())/2,
	        		tagPaint);
	        
	        
	        linePaint.setColor(Color.MAGENTA);
	        canvas.drawLine(baseX,baseY , baseX+textPaint.measureText(TEXT), baseY, linePaint);
	        tagPaint.setColor(Color.MAGENTA);
	        canvas.drawPoint(baseX, baseY+textPaint.descent() - textPaint.ascent()+100, tagPaint);
	        canvas.drawText("baseline", 
	        		baseX+20, 
	        		baseY+textPaint.descent() - textPaint.ascent()+100-(tagPaint.descent()+tagPaint.ascent())/2,
	        		tagPaint);
	        
	        
	        linePaint.setColor(Color.parseColor("#545654"));
	        canvas.drawLine(baseX,baseY+mFontMetrics.descent , baseX+textPaint.measureText(TEXT), baseY+mFontMetrics.descent, linePaint);
	        tagPaint.setColor(Color.parseColor("#545654"));
	        canvas.drawPoint(baseX, baseY+textPaint.descent() - textPaint.ascent()+150, tagPaint);
	        canvas.drawText("descent", 
	        		baseX+20, 
	        		baseY+textPaint.descent() - textPaint.ascent()+150-(tagPaint.descent()+tagPaint.ascent())/2,
	        		tagPaint);
	        
	        
	        linePaint.setColor(Color.CYAN);
	        canvas.drawLine(baseX,baseY+mFontMetrics.bottom , baseX+textPaint.measureText(TEXT), baseY+mFontMetrics.bottom, linePaint);
	        tagPaint.setColor(Color.CYAN);
	        canvas.drawPoint(baseX, baseY+textPaint.descent() - textPaint.ascent()+200, tagPaint);
	        canvas.drawText("bottom", 
	        		baseX+20, 
	        		baseY+textPaint.descent() - textPaint.ascent()+200-(tagPaint.descent()+tagPaint.ascent())/2,
	        		tagPaint);
	        
	        TextPaint textPaint = new TextPaint(Paint .ANTI_ALIAS_FLAG);
	        textPaint.setTextSize(30);
	        StaticLayout staticLayout =new StaticLayout(
	        		"StaticLayout is a Layout for text that will not be edited after it is laid out.  Use {@link DynamicLayout} for text that may change. This is used by widgets to control text layout. You should not need to use this class directly unless you are implementing your own widget or custom display object, or would be tempted to call", 
	        		textPaint, 
	        		canvas.getWidth()/2, 
	        		Alignment.ALIGN_NORMAL, 1.0F, 0.0F, false); 
	        staticLayout.draw(canvas);
		
		}
		
	}






参考:爱哥的自定义控件其实很简单1/4

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值