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
相关文章
|
18天前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
24 3
|
18天前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
40 3
|
4月前
|
缓存 开发者 索引
深入解析 `org.elasticsearch.action.search.SearchRequest` 类
深入解析 `org.elasticsearch.action.search.SearchRequest` 类
|
12天前
|
程序员 开发者 Python
深度解析Python中的元编程:从装饰器到自定义类创建工具
【10月更文挑战第5天】在现代软件开发中,元编程是一种高级技术,它允许程序员编写能够生成或修改其他程序的代码。这使得开发者可以更灵活地控制和扩展他们的应用逻辑。Python作为一种动态类型语言,提供了丰富的元编程特性,如装饰器、元类以及动态函数和类的创建等。本文将深入探讨这些特性,并通过具体的代码示例来展示如何有效地利用它们。
17 0
|
2月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
37 0
Spring高手之路22——AOP切面类的封装与解析
|
2月前
|
JSON 图形学 数据格式
Json☀️ 一、认识Json是如何解析成类的
Json☀️ 一、认识Json是如何解析成类的
|
2月前
|
开发者 编解码
界面适应奥秘:从自适应布局到图片管理,Xamarin响应式设计全解析
【8月更文挑战第31天】在 Xamarin 的世界里,构建灵活且适应性强的界面是每位开发者的必修课。本文将带您探索 Xamarin 的响应式设计技巧,包括自适应布局、设备服务协商和高效图片管理,帮助您的应用在各种设备上表现出色。通过 Grid 和 StackLayout 实现弹性空间分配,利用 Device 类检测设备类型以加载最优布局,以及使用 Image 控件自动选择合适图片资源,让您轻松应对不同屏幕尺寸的挑战。掌握这些技巧,让您的应用在多变的市场中持续领先。
32 0
|
2月前
|
存储 开发者 Ruby
【揭秘Ruby高手秘籍】OOP编程精髓全解析:玩转类、继承与多态,成就编程大师之路!
【8月更文挑战第31天】面向对象编程(OOP)是通过“对象”来设计软件的编程范式。Ruby作为一种纯面向对象的语言,几乎所有事物都是对象。本文通过具体代码示例介绍了Ruby中OOP的核心概念,包括类与对象、继承、封装、多态及模块混合,展示了如何利用这些技术更好地组织和扩展代码。例如,通过定义类、继承关系及私有方法,可以创建具有特定行为的对象,并实现灵活的方法重写和功能扩展。掌握这些概念有助于提升代码质量和可维护性。
32 0
|
4月前
|
存储 JavaScript 前端开发
【JavaScript】JavaScript 中的 Class 类:全面解析
【JavaScript】JavaScript 中的 Class 类:全面解析
84 1
|
4月前
|
缓存 算法 Java
提升编程效率的利器: 解析Google Guava库之常用工具类-40个示例(七)
提升编程效率的利器: 解析Google Guava库之常用工具类-40个示例(七)

推荐镜像

更多