自定义View基础1

在上一篇博客中,我们基本了解了Android中View的绘制流程,知道了绘制流程以后,是不是想要马上写一些自定义控件来玩一下呢?不急,在这一篇博客中,我们先来了解一下Android给我们提供的一些常见的绘图的API。绘图的API是什么呢,我就用一个比喻吧。当Android工程师在自定义view是就相当于一个画家,那么画家作画是不是需要了工具了,如画板、画布、画笔以及颜料等,而Android系统也给我们提供了很多这样的工具,就是Android中的一些绘图相关的API。这篇文章主要介绍Point/PointF、Rect/RectF、Bitmap/BitmapDrawable几个类;在下一篇文章中将主要介绍Paint类和Canvas类。

1.Point类和PointF类(讨论的是android.graphics包下面的,不是java.awt包下面的)

Point类是一个简单的类,代表一个"点",实现了Parcelable序列化接口,支付序列化和反序列化。Point类中定义了两个成员变量x和y,表示一个点的横坐标和纵坐标。在Android中的坐标与数学中的平面坐标有所不同,Android中x轴向右为正,向左为负;y轴向下为正,向上为负,坐标原点在屏幕的左上角,也就是说屏幕内的所有点不管是x坐标还是y坐标都是正数。

自定义View基础1

Point类作为最简单的类,提供的功能也很简单

① 通过Point类创建一个点的方法

[java] view plain copy
  1. // 创建一个新的点  
  2. public Point() {}  
  3. // 根据x,y坐标创建一个新的点  
  4. public Point(int x, int y) {  
  5.     this.x = x;  
  6.     this.y = y;  
  7. }  
  8. // 通过一个点创建一个新的点,就是将一个点的坐标赋值给另一个点  
  9. public Point(Point src) {  
  10.     this.x = src.x;  
  11.     this.y = src.y;  
  12. }  
② 对Point点进行操作的方法

[java] view plain copy
  1. // 对点进行重新设置x和y  
  2. public void set(int x, int y) {  
  3.     this.x = x;  
  4.     this.y = y;  
  5. }  
  6. // 将x和y取反值  
  7. public final void negate() {  
  8.     x = -x;  
  9.     y = -y;  
  10. }  
  11. // 对x和y的值做改变,dx、dy表示偏移量,正负号决定偏移的方向  
  12. public final void offset(int dx, int dy) {  
  13.     x += dx;  
  14.     y += dy;  
  15. }  
③ 判断方法

[java] view plain copy
  1. // 通过x和y坐标判断是否为同一点  
  2. public final boolean equals(int x, int y) {  
  3.     return this.x == x && this.y == y;  
  4. }  
  5. // 判断一个对象是否和当前点是否是同一个点或者重合  
  6. @Override  
  7. public boolean equals(Object o) {  
  8.     if (this == o) return true;  
  9.     if (o == null || getClass() != o.getClass()) return false;  
  10.   
  11.     Point point = (Point) o;  
  12.   
  13.     if (x != point.x) return false;  
  14.     if (y != point.y) return false;  
  15.   
  16.     return true;  
  17. }  
PointF类和Point类功能和用法完全一样,唯一不同的就是Point类的成员变量x、y是int类型的;PointF类的成员变量x、y是float类型的。

2.Rect类和RectF类

Rect 类定义了一个矩形结构,同样实现了Parcelable序列化接口。Rect类定义了left、top、right、bottom 四个成员变量,我们需要正确理解这4个成员变量的作用:
◆ left: 矩形左边线条离 y 轴的距离
◆ top:矩形上面线条离 x 轴的距离
◆ right:矩形右边线条离 y 轴的距离
◆ bottom:矩形底部线条离 x 轴的距离

自定义View基础1

矩形是一种非常常见的图形结构,并且能衍生出更多的图形,如椭圆、扇形、弧线等等;矩形还能进行各种图形运算,如交集、并集等等,所以与之对应的 Rect 类功能也更加复杂。
① 创建一个Rect,主要有3个构造方法

[java] view plain copy
  1. // 创建一个空对象,left、topright、bottom都为0  
  2. public Rect() {}  
  3. // 根据指定的left、topright、bottom创建一个Rect对象  
  4. public Rect(int left, int top, int right, int bottom) {...}  
  5. // 从另外一个Rect对象复制出一个新的Rect对象  
  6. public Rect(Rect r) {...}  
② 对Rect重新设置值的方法

[java] view plain copy
  1. // 将Rect对象置空,就是将left、topright、bottom的值都设置为0  
  2. public void setEmpty() {  
  3.     left = right = top = bottom = 0;  
  4. }  
  5. // 重新设置left、topright、bottom的值  
  6.  public void set(int left, int top, int right, int bottom) {  
  7.     this.left = left;  
  8.     this.top = top;  
  9.     this.right = right;  
  10.     this.bottom = bottom;  
  11. }  
  12. // 将另外一个Rect对象的值设置到当前Rect对象中  
  13. public void set(Rect src) {  
  14.     this.left = src.left;  
  15.     this.top = src.top;  
  16.     this.right = src.right;  
  17.     this.bottom = src.bottom;  
  18. }  

③ Rect类中的计算相关的方法

[java] view plain copy
  1. // 获取Rect的宽    
  2. public final int width() {    
  3.     return right - left;    
  4. }    
  5. // 获取Rect的高    
  6. public final int height() {    
  7.     return bottom - top;    
  8. }    
  9. // 计算Rect中心点的x坐标,返回int类型的值    
  10. public final int centerX() {    
  11.     return (left + right) >> 1// >>1 相当于 /2    
  12. }    
  13. // 计算Rect中心点的y坐标,返回int类型的值  
  14. public final int centerY() {    
  15.     return (top + bottom) >> 1;    
  16. }    
  17. // 计算Rect中心点的x坐标,返回float类型的值,结果更精确    
  18. public final float exactCenterX() {    
  19.     return (left + right) * 0.5f;    
  20. }    
  21. // 计算Rect中心点的y坐标,返回float类型的值,结果更精确    
  22. public final float exactCenterY() {    
  23.     return (top + bottom) * 0.5f;    
  24. }  

④ Rect类中的判断相关的方法
[java] view plain copy
  1. // 判断是否为空  
  2. public final boolean isEmpty() {  
  3.     return left >= right || top >= bottom;  
  4. }  
  5. // 判断是否包含点x、y  
  6. public boolean contains(int x, int y) {  
  7.     return left < right && top < bottom  // check for empty first  
  8.            && x >= left && x < right && y >= top && y < bottom;  
  9. }  
  10. // 判断是否包含另外一个矩形  
  11. public boolean contains(int left, int top, int right, int bottom) {  
  12.     return this.left < this.right && this.top < this.bottom  
  13.             && this.left <= left && this.top <= top  
  14.             && this.right >= right && this.bottom >= bottom;  
  15. }  
  16. // 判断是否包含另外一个矩形  
  17. public boolean contains(Rect r) {  
  18.     return this.left < this.right && this.top < this.bottom  
  19.            && left <= r.left && top <= r.top && right >= r.right && bottom >= r.bottom;  
  20. }  
⑤ 缩放和平移相关的方法

[java] view plain copy
  1. // 实现矩形的缩放功能,缩放中心就是矩形的中心点,dx、 dy为正数时表示缩小,负数表示放大  
  2. public void inset(int dx, int dy) {  
  3.     left += dx;  
  4.     top += dy;  
  5.     right -= dx;  
  6.     bottom -= dy;  
  7. }  
  8. // 矩形的left和right同时移动相同的距离dx,矩形的top和bottom同时移动相同的距离dy,正负决定移动方向  
  9. public void offset(int dx, int dy) {  
  10.     left += dx;  
  11.     top += dy;  
  12.     right += dx;  
  13.     bottom += dy;  
  14. }  
  15. // 也是移位, 只是offset()是绝对定位,offsetTo()是相对定位。  
  16. public void offsetTo(int newLeft, int newTop) {  
  17.     right += newLeft - left;  
  18.     bottom += newTop - top;  
  19.     left = newLeft;  
  20.     top = newTop;  
  21. }  
⑥ 运算相关的方法

[java] view plain copy
  1. // 取交集  
  2. public boolean intersect(int left, int top, int right, int bottom) {  
  3.     if (this.left < right && left < this.right && this.top < bottom && top < this.bottom) {  
  4.         if (this.left < left) this.left = left;  
  5.         if (this.top < top) this.top = top;  
  6.         if (this.right > right) this.right = right;  
  7.         if (this.bottom > bottom) this.bottom = bottom;  
  8.         return true;  
  9.     }  
  10.     return false;  
  11. }  
  12. // 取交集  
  13. public boolean intersect(Rect r) {  
  14.     return intersect(r.left, r.top, r.right, r.bottom);  
  15. }  
  16. // 取并集  
  17. public void union(int left, int top, int right, int bottom) {  
  18.     if ((left < right) && (top < bottom)) {  
  19.         if ((this.left < this.right) && (this.top < this.bottom)) {  
  20.             if (this.left > left) this.left = left;  
  21.             if (this.top > top) this.top = top;  
  22.             if (this.right < right) this.right = right;  
  23.             if (this.bottom < bottom) this.bottom = bottom;  
  24.         } else {  
  25.             this.left = left;  
  26.             this.top = top;  
  27.             this.right = right;  
  28.             this.bottom = bottom;  
  29.         }  
  30.     }  
  31. }  
  32. // 取并集  
  33. public void union(Rect r) {  
  34.     union(r.left, r.top, r.right, r.bottom);  
  35. }  
  36. // 更新矩形的值,扩大范围  
  37. public void union(int x, int y) {  
  38.     if (x < left) {  
  39.         left = x;  
  40.     } else if (x > right) {  
  41.         right = x;  
  42.     }  
  43.     if (y < top) {  
  44.         top = y;  
  45.     } else if (y > bottom) {  
  46.         bottom = y;  
  47.     }  
  48. }  
自定义View基础1

RectF类与Rect类功能和用法完全一样,不同是Rect的left、topright、 bottom四个成员变量为int类型,而RectF为float类型。另外在开发中可能会用到Rect和RectF的相互转换,在RectF类中定义了两个方法用于将RectF装换成Rect

[java] view plain copy
  1. // 将float类型的left、top、right、 bottom都以四舍五入的方式变为int类型  
  2. public void round(Rect dst) {  
  3.     dst.set(FastMath.round(left), FastMath.round(top),  
  4.             FastMath.round(right), FastMath.round(bottom));  
  5. }  
  6. // 将float类型的left、top做floor()运算:返回最大的值,该值小于等于参数,并等于某个整数(如15.3、15.8都返回15)  
  7. // 将float类型的right、 bottom做ceil()运算:返回最小的值,该值大于等于参数,并等于某个整数(如15.3、15.8都返回16)  
  8. public void roundOut(Rect dst) {  
  9.     dst.set((int) Math.floor(left), (int) Math.floor(top),  
  10.             (int) Math.ceil(right), (int) Math.ceil(bottom));  
  11. }  
而Rect转换成RectF就可以直接通过构造函数就可以实现转换了

[java] view plain copy
  1. public RectF(Rect r) {...}  


3.Bitmap类和BitmapDrawable类

Bitmap表示“位图”,用于存储png、jpg、gif等格式的图片数据,在Android中对图片进行处理,需要先将图片读成Bitmap对象,然后在对Bitmap对象进行操作,图片读取操作是BitmapFactory 类完成的,该类定义了一些方法用于读取不同路径下的图片数据:

[java] view plain copy
  1. // 从指定的文件路径中读取图片  
  2. public static Bitmap decodeFile(String pathName)  
  3. // 通过资源id读取res/drawable或res/mipmap目录下的图片  
  4. public static Bitmap decodeResource(Resources res, int id)  
  5. // 从InputStream输入流中读取图片数据  
  6. public static Bitmap decodeStream(InputStream is)  
  7. // 从字节数组中读取图片数据  
  8. public static Bitmap decodeByteArray(byte[] data, int offset, int length)  
当然上面的方法还有很多的重载方法,能在读取图片数据的同时设置一些参数。
如果需要创建一个图片的话,在Bitmap中提供了createBitmap()方法可以创建,这个方法同样有很多的重载版本,可以在创建图片的同时指定图片的各种参数,下面提供一种比较常见的做法做参考:

[java] view plain copy
  1. // 创建一个宽和高都是500的ARGB_8888类型的空白位图对象  
  2. Bitmap bitmap = Bitmap.createBitmap(500500, Bitmap.Config.ARGB_8888);  
在Bitmap类中还有一些比较常用的方法:

[java] view plain copy
  1. // 压缩图片 format:图片格式;quality:压缩率;stream:保存压缩后的数据  
  2. public boolean compress(CompressFormat format, int quality, OutputStream stream)  
  3. // 复制一张图片 config:图片的配置;isMutable:复制后得到的图片是否可以修改,true表示可以  
  4. public Bitmap copy(Config config, boolean isMutable)  
  5. // 获取Bitmap的宽  
  6. public final int getWidth()  
  7. // 获取Bitmap的高  
  8. public final int getHeight()  
  9. // 设置Bitmap的宽  
  10. public final int setWidth()  
  11. // 设置Bitmap的高  
  12. public final int setHeight()  
  13. // 判断图片是否已经回收  
  14. public final boolean isRecycled()  
  15. // 回收Bitmap内存  
  16. public void recycle()  
  17. // 返回Bitmap的字节数  
  18. public final int getByteCount()  
在Android中Bitmap是一个比较消耗资源的对象,所以在使用完成时候要释放掉Bitmap对象,一般释放Bitmap的代码如下:

[java] view plain copy
  1. // 判断bitmap是否为null或者已经释放掉  
  2. if (bitmap != null && !bitmap.isRecycled()) {  
  3.     bitmap.recycle(); // 释放Bitmap内存  
  4.     bitmap = null;    // 将bitmap对象置为null  
  5.     System.gc();      // 手动调用gc(),提醒JVM释放资源  
  6. }  
BimapDrawable是Android 的一种通用位图格式,也可以理解成Bitmap的另外一种表现形式。 但比Bitmap占用资源更少、性能更高。
在BitmapDrawable中的一些常用方法,同时也提供了BitmapDrawable和Bitmap的相互转化的方法:

[java] view plain copy
  1. // 通过构造可以将Bitmap对象转换成BitmapDrawable对象  
  2. public BitmapDrawable(Bitmap bitmap)  
  3. // 将Bitmap对象设置到BitmapDrawable对象中  
  4. protected void setBitmap(Bitmap bitmap)  
  5. // 从BitmapDrawable对象中得到Bitmap对象  
  6. public final Bitmap getBitmap()  
  7. // 获取BitmapDrawable的宽,和Bitmap有一点区别  
  8. public int getIntrinsicWidth()  
  9. // 获取BitmapDrawable的高,和Bitmap有一点区别  
  10. public int getIntrinsicHeight()  
  11. // 获取BitmapDrawable的透明度  
  12. public int getAlpha()  
  13. // 获取BitmapDrawable中的Paint对象  
  14. public final Paint getPaint()