Paint类解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 在自定义组件中,Paint类是一个很重要的类,主要包含颜色、文本、图形样式、位图模式、滤镜等几个方面。Paint类的相关方法如下:1、颜色是指绘图时使用的颜色,在 Android 中颜色可以指定透明度,使用 16...
在自定义组件中,Paint类是一个很重要的类,主要包含颜色、文本、图形样式、位图模式、滤镜等几个方面。Paint类的相关方法如下:

1、颜色是指绘图时使用的颜色,在 Android 中颜色可以指定透明度,使用 16 进制来表示颜色
时,格式通常为#AARRGGBB,其中,AA 表示透明度、RR 表示红色、GG 表示绿色、BB 表示蓝色,
Color 类定义了颜色信息,内置了常用颜色的 int 型常量,比如 Color.RED 是红色,Color.BLUE 是
蓝色……如果您习惯了 16 进制的颜色, Color 类的静态方法 parseColor(String colorString)可以将 16进制颜色转换成 Color 类型。需要注意的是,Android 的颜色都是 int 类型的,Color 类只负责颜色的管理而不是代表某种颜色。
Paint 类中与颜色相关的方法有:
public native void setColor(int color);//设置颜色
public native void setAlpha(int a);//设置透明度,a 的范围取 0~255 之间的整数
public void setARGB(int a,int r,int g,int b);//指定透明度、红、绿、蓝定义一种颜色

2、绘制文本时,可以指定文本的大小、对齐方式、文本样式等属性,文本样式主要是为文本指定粗体、下划线、删除线等修饰性属性,主要说明下设置字体大小这个:
public native void setTextSize(float textSize);// 设置文本大小,单位是 px,这个和我们平时使用的字体单位 sp 不同,所以最好进行转换,这个要注意。
比较麻烦的是绘制文字时,我们还要考虑字体的基本结构,字体的信息使用 Paint.FontMetrics 类来表示,该类源码如下:
public static class FontMetrics {
public float ascent;
public float bottom;
public float descent;
public float leading;
public float top;
}
从文字上理解可能比较晦涩,看下示意图也许很容易找到答案:

简单来说,常用字符的高度是 ascent 和 descent 的和,但是,一些特殊字符比如拼音的音调等则会延伸到 top 的位置。
baseline:基准点(绿色虚线所指);
ascent:baseline 之上至字符最高处的距离;
descent:baseline 之下至字符最低处的距离;
top:字符可达最高处到 baseline 的值,即 ascent 的最大值;
bottom:字符可达最低处到 baseline 的值,即 descent 的最大值。
leading:行间距,表示上一行字符的descent到该行字符的ascent之间的距离
根据世界范围内已入案的使用语言中能够标注在字符上方或者下方的除了类似的符号肯定是数不胜数的,一般情况下我们极少使用到类似的符号所以往往会忽略掉这些符号的存在,但是Android依然会在绘制文本的时候在文本外层留出一定的边距,这就是为什么 top和bottom总会比ascent和descent大一点的原因。而在TextView中我们可以通过xml设置其属性 android:includeFontPadding="false"去掉一定的边距值但是不能完全去掉。
要获取 FontMetrics 对象,调用 Paint 类的 getFontMetrics()即可,而在 drawText()方法中,参数 y 就是 baseline 的值,因为 FontMetrics 类并没有声明 baseline 属性,所以,我们需要通过下面的公式计算出来:
int baseline=(int) (viewHeight - fontMetrics.descent - fontMetrics.ascent) /2;
其中,viewHeight 是文字所在区域的高度。
下面自定义一个文本绘制的View
public class TextView1 extends View {
private static final String TEXT = "Android自定义";
private Paint paint;
public TextView1(Context context) {
super(context);
}
public TextView1(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
FontMetrics fontMetrics = paint.getFontMetrics();
Log.d("xmr", "ascent:" + fontMetrics.ascent);
Log.d("xmr", "top:" + fontMetrics.top);
Log.d("xmr", "leading:" + fontMetrics.leading);
Log.d("xmr", "descent:" + fontMetrics.descent);
Log.d("xmr", "bottom:" + fontMetrics.bottom);
}
public TextView1(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 将文字放在正中间
Rect textRect = this.getTextRect();
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
int x = (viewWidth - textRect.width()) / 2;
int y = (int) (viewHeight - fontMetrics.descent - fontMetrics.ascent) / 2;
canvas.drawText(TEXT, x, y, paint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Rect rect = getTextRect();
int textWidth = rect.width();
int textHeight = rect.height();
int width = measureWidth(widthMeasureSpec, textWidth);
int height = measureHeight(heightMeasureSpec, textHeight);
setMeasuredDimension(width, height);
}
/**
* 获取文字所占的尺寸
*
* @return
*/
private Rect getTextRect() {
// 根据 Paint 设置的绘制参数计算文字所占的宽度
Rect rect = new Rect();
// 文字所占的区域大小保存在 rect 中
paint.getTextBounds(TEXT, 0, TEXT.length(), rect);
return rect;
}
/**
* 测量组件宽度
*
* @param widthMeasureSpec
* @param textWidth
* 文字所占宽度
* @return
*/
private int measureWidth(int widthMeasureSpec, int textWidth) {
int mode = MeasureSpec.getMode(widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
int width = 0;
if (mode == MeasureSpec.EXACTLY) {
// 宽度为 match_parent 和具体值时,直接将 size 作为组件的宽度
width = size;
} else if (mode == MeasureSpec.AT_MOST) {
// 宽度为 wrap_content,宽度需要计算,此处为文字宽度
width = textWidth;
}
return width;
}
/**
* 测量组件高度
*
* @param heightMeasureSpec
* @param textHeight
* 文字所占高度
* @return
*/
private int measureHeight(int heightMeasureSpec, int textHeight) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
int height = 0;
if (mode == MeasureSpec.EXACTLY) {
// 宽度为 match_parent 和具体值时,直接将 size 作为组件的高度
height = size;
} else if (mode == MeasureSpec.AT_MOST) {
// 高度为 wrap_content,高度需要计算,此处为文字高度
height = textHeight;
}
return height;
}
}
效果如下:

logcat输出如下:
如图我们得到了top,ascent,descent,bottom和leading的值,因为只有一行文本所以leading恒为0。
从代码中可以发现在我们绘制文本之前我们便可以获取文本的FontMetrics属性值,也就是说我们FontMetrics的这些值跟我们要绘制什么文本是无关的,而仅与绘制文本Paint的size和typeface有关,我们来分别更改这两个值看看效果:
paint.setTextSize(36);
如图所示所有值都改变了,我们再为Paint设置一个typeface:
paint.setTypeface(Typeface.defaultFromStyle(Typeface.ITALIC));
3、图形样式包含绘制的图形是空心样式还是实心样式,同时还能指定落笔和收笔时的笔触效
果。绘制直线或折线时,图形样式能影响到一些绘制细节。
Paint 类与图形样式相关的方法有:
public void setStyle(Paint.Style style);//设置绘制的图形是空心样式还是实心样式,默认为实心样式,style 的可选值有:
public static enum Style{
FILL,
FILL_AND_STROKE,
STROKE
}
其中,FILL 表示实心样式,对于闭合图形来说,会用指定的颜色进行填充;STROKE 表
示空心样式,绘制时只有线条而无填充效果;FILL_AND_STROKE 表示同时使用实心样
式和空心样式。
public void setStrokeJoin(Paint.Join join)
当绘图样式为 STROKE 时,该方法用于指定线条连接处的拐角样式,能使绘制的图形
更加平滑。可选值如下:
public static enum Join {
BEVEL,
MITER,
ROUND
}
我们通过下图来区别上面三个枚举值(比较右上角即可) ,默认值为 MITER:
public void setStrokeCap(Paint.Cap cap)
该方法用于设置落笔时的样式,控制我们的画笔在离开画板时留下的最后一点图形,可选值如下:
public static enum Cap {
BUTT,
ROUND,
SQUARE
}
我们通过下图来区别上面三个枚举值,默认值为 BUTT:
public native void setStrokeWidth(float width)
设置线条的宽度,注意是 float 类型,在 Android 中最细的线条不是 1,可以比 1 更小更细。
参考:
http://blog.csdn.net/abcdef314159/article/details/51720686
相关文章
|
20天前
|
数据可视化 数据挖掘 BI
团队管理者必读:高效看板类协同软件的功能解析
在现代职场中,团队协作的效率直接影响项目成败。看板类协同软件通过可视化界面,帮助团队清晰规划任务、追踪进度,提高协作效率。本文介绍看板类软件的优势,并推荐五款优质工具:板栗看板、Trello、Monday.com、ClickUp 和 Asana,助力团队实现高效管理。
45 2
|
3月前
|
安全 编译器 程序员
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
64 2
|
3月前
|
存储 Java API
详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
【10月更文挑战第19天】深入剖析Java Map:不仅是高效存储键值对的数据结构,更是展现设计艺术的典范。本文从基本概念、设计艺术和使用技巧三个方面,详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
77 3
|
3月前
|
存储 编译器 C语言
C++类与对象深度解析(一):从抽象到实践的全面入门指南
C++类与对象深度解析(一):从抽象到实践的全面入门指南
58 8
|
3月前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
57 4
|
3月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
47 3
|
3月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
58 3
|
3月前
|
安全 编译器 C++
【C++篇】C++类与对象深度解析(三):类的默认成员函数详解
【C++篇】C++类与对象深度解析(三):类的默认成员函数详解
31 3
|
3月前
|
存储 设计模式 编译器
【C++篇】C++类与对象深度解析(五):友元机制、内部类与匿名对象的高级应用
【C++篇】C++类与对象深度解析(五):友元机制、内部类与匿名对象的高级应用
42 2
|
3月前
|
程序员 开发者 Python
深度解析Python中的元编程:从装饰器到自定义类创建工具
【10月更文挑战第5天】在现代软件开发中,元编程是一种高级技术,它允许程序员编写能够生成或修改其他程序的代码。这使得开发者可以更灵活地控制和扩展他们的应用逻辑。Python作为一种动态类型语言,提供了丰富的元编程特性,如装饰器、元类以及动态函数和类的创建等。本文将深入探讨这些特性,并通过具体的代码示例来展示如何有效地利用它们。
60 0

推荐镜像

更多