CGGeometry中常用与不常用的方法

在iOS中布局一个组件,必需的一个属性就是CGRect,由于它是C中的结构体的构造方式,而在iOS的面向对象编程的过程中,使用着还是有一些不方便的地方,于是我们在开发的时候经常的都会对View做一个扩展(Category),用来方便的操作组件的坐标、尺寸。而有一些方法,其实苹果在封装的过程中已经给我们想好了,下面是CGGeometry中一些常见、不常见的、常用、不常用的方法的说明。

一、系统定义的结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 定义二维坐标系中的一个点
struct CGPoint {
CGFloat x;
CGFloat y;
};
typedef struct CGPoint CGPoint;
// 定义一个尺寸
struct CGSize {
CGFloat width;
CGFloat height;
};
typedef struct CGSize CGSize;
// 定义一个向量
struct CGVector {
CGFloat dx;
CGFloat dy;
};
typedef struct CGVector CGVector;
// 定义二维坐标系中的一个长方形
struct CGRect {
CGPoint origin;
CGSize size;
};
typedef struct CGRect CGRect;

二、一些常量

1
2
3
4
5
CGPoint CGPointZero // 等同于CGPoint{0, 0}
CGSize CGSizeZero // 等同于CGSize{0, 0}
CGRect CGRectZero // 等同于CGRect{0,0,0,0}
CGRect CGRectNull // 为空,null
CGRect CGRectInfinite // 无穷大

三、结构体的创建

系统内联函数有实现在最下方。

1
2
3
4
CGPoint CGPointMake(CGFloat x, CGFloat y);
CGSize CGSizeMake(CGFloat width, CGFloat height);
CGVector CGVectorMake(CGFloat dx, CGFloat dy);
CGRect CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height);

四、单个属性的获取

1
2
3
4
5
6
7
8
CGFloat CGRectGetMinX(CGRect rect)
CGFloat CGRectGetMidX(CGRect rect)
CGFloat CGRectGetMaxX(CGRect rect)
CGFloat CGRectGetMinY(CGRect rect)
CGFloat CGRectGetMidY(CGRect rect)
CGFloat CGRectGetMaxY(CGRect rect)
CGFloat CGRectGetWidth(CGRect rect)
CGFloat CGRectGetHeight(CGRect rect)

各个方法的含义如下图:

五、比较类的方法

1
2
3
4
5
6
7
8
9
10
11
12
// 比较两个坐标点是否相同
bool CGPointEqualToPoint(CGPoint point1, CGPoint point2)
// 比较两个size是否相同
bool CGSizeEqualToSize(CGSize size1, CGSize size2)
// 比较两个rect是否相同
bool CGRectEqualToRect(CGRect rect1, CGRect rect2)
// 判断是否为无穷大
bool CGRectIsInfinite(CGRect rect)
// 判断是否为空,有时返回null的时候,当做rect去处理了,可以这样来判断
bool CGRectIsNull(CGRect rect)
// 判断是否为空,即width、height为0
bool CGRectIsEmpty(CGRect rect)

六、有效的辅助方法

  • CGRect CGRectStandardize(CGRect rect)
    对于一个CGRect来说,其中的size都只能是大于0的数值,所以这个方法就是将size转成有效值的方法,比如:
    1
    2
    3
    4
    CGRectMake(1, 1, 1, 1)返回(1, 1, 1, 1)
    CGRectMake(1, 1, 1, -1)返回(1, 0, 1, 1)
    CGRectMake(1, 1, -1, 1)返回(0, 1, 1, 1)
    CGRectMake(1, 1, -1, -1)返回(0, 0, 1, 1)

需要注意的是,只有当widthheight小于零时才有改变
其实现大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
CGRect CGRectStandardize(CGRect rect)
{
CGRect standardizeRect = rect;
if (rect.size.width < 0) {
standardizeRect.origin.x += rect.size.width;
standardizeRect.size.width = fabs(standardizeRect.size.width);
}
if (rect.size.height < 0) {
standardizeRect.origin.y += rect.size.height;
standardizeRect.size.height = fabs(standardizeRect.size.height);
}
return standardizeRect;
}
  • CGRect CGRectInset(CGRect rect, CGFloat dx, CGFloat dy)
    用于获得一个CGRect内间距一定距离的CGRect,如下图

    代码实现如下:
1
2
3
4
5
6
7
CGRect CGRectInset(CGRect rect, CGFloat dx, CGFloat dy)
{
return CGRectMake(rect.origin.x + dx,
rect.origin.y + dy,
rect.size.width - dx * 2,
rect.size.height - dy * 2);
}
  • CGRect CGRectIntegral(CGRect rect)
    类似 CGRectStandardize

  • CGRect CGRectUnion(CGRect r1, CGRect r2)
    两个CGRect的合集,区别于数学中的交际,由于在iOS中CGRect表示的是平面中某一位置的矩形,所以这里的合集如下图中的矩形AOPG:

    代码如下:

1
2
3
4
5
6
7
8
CGRect CGRectUnion(CGRect r1, CGRect r2)
{
CGFloat minx = MIN(r1.origin.x, r2.origin.x);
CGFloat miny = MIN(r1.origin.y, r2.origin.y);
CGFloat maxx = MAX(r1.origin.x + r1.size.width , r2.origin.x + r2.size.width);
CGFloat maxy = MAX(r1.origin.y + r1.size.height, r2.origin.y + r2.size.height);
return CGRectMake(minx, miny, maxx - minx, maxy - miny);
}
  • CGRect CGRectIntersection(CGRect r1, CGRect r2)
    两个CGRect的交集,如上图中蓝色部分矩形ETCR,代码实现如下:
1
2
3
4
5
6
7
8
9
10
11
CGRect CGRectIntersection(CGRect r1, CGRect r2)
{
if (CGRectIntersectsRect(r1, r2)) {
CGFloat maxX = MAX(r1.origin.x, r2.origin.x);
CGFloat maxY = MAX(r1.origin.y, r2.origin.y);
CGFloat minRight = MIN(r1.origin.x + r1.size.width , r2.origin.x + r2.size.width);
CGFloat minBottom = MIN(r1.origin.y + r1.size.height, r2.origin.y + r2.size.height);
return CGRectMake(maxX, maxY, minRight - maxX, minBottom - maxY);
}
return CGRectNull;
}
  • CGRect CGRectOffset(CGRect rect, CGFloat dx, CGFloat dy)
    CGRectxy方向偏移
1
2
3
4
5
6
CGRect CGRectOffset(CGRect rect, CGFloat dx, CGFloat dy)
{
CGRect trect = rect;
trect.origin = CGPointMake(rect.origin.x + dx, rect.origin.y + dy);
return trect;
}
  • void CGRectDivide(CGRect rect, CGRect * slice, CGRect * remainder, CGFloat amount, CGRectEdge edge)
    CGRect从指定的方向(edge)按给定的大小(amount)进行切割,如下图所示:

    函数中的各个参数含义如下:

    rect 要切割的CGRect
    slice 按制定要求切割出来的CGRect
    remainder 切割后剩下的CGRect
    amount 要切割的长度
    edge 开始切割的方向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void CGRectDivide(CGRect rect, CGRect *slice, CGRect *remainder, CGFloat amount, CGRectEdge edge)
{
switch (edge) {
case CGRectMinXEdge:
{
slice->origin = rect.origin;
slice->size = CGSizeMake(amount, rect.size.height);
remainder->origin = CGPointMake(rect.origin.x + amount, rect.origin.y);
remainder->size = CGSizeMake(rect.size.width - amount, rect.size.height);
}
break;
case CGRectMaxXEdge:
{
slice->origin = CGPointMake(rect.origin.x + rect.size.width - amount, rect.origin.y);
slice->size = CGSizeMake(amount, rect.size.height);
remainder->origin = rect.origin;
remainder->size = CGSizeMake(rect.size.width - amount, rect.size.height);
}
break;
case CGRectMinYEdge:
{
slice->origin = rect.origin;
slice->size = CGSizeMake(rect.size.width, amount);
remainder->origin = CGPointMake(rect.origin.x, rect.origin.y + amount);
remainder->size = CGSizeMake(rect.size.width, rect.size.height - amount);
}
break;
case CGRectMaxYEdge:
{
slice->origin = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height - amount);
slice->size = CGSizeMake(rect.size.width, amount);
remainder->origin = rect.origin;
remainder->size = CGSizeMake(rect.size.width, rect.size.height - amount);
}
break;
default:
break;
}
}
  • bool CGRectContainsPoint(CGRect rect, CGPoint point)
    检查给定的点位置是否在CGRect区域,实现如下:
1
2
3
4
5
6
7
bool CGRectContainsPoint(CGRect rect, CGPoint point)
{
return point.x >= rect.origin.x &&
point.y >= rect.origin.y &&
point.x <= rect.origin.x + rect.size.width &&
point.y <= rect.origin.y + rect.size.height;
}
  • bool CGRectContainsRect(CGRect rect1, CGRect rect2)
    检查rect1是否完全包含rect2,实现如下:
1
2
3
4
5
6
7
bool CGRectContainsRect(CGRect rect1, CGRect rect2)
{
return rect2.origin.x >= rect1.origin.x &&
rect2.origin.y >= rect1.origin.y &&
rect2.origin.x + rect2.size.width <= rect1.origin.x + rect1.size.width &&
rect2.origin.y + rect2.size.height <= rect1.origin.y + rect1.size.height;
}
  • bool CGRectIntersectsRect(CGRect rect1, CGRect rect2)
    检查两个CGRect是否相交,实现如下:
1
2
3
4
5
6
7
bool CGRectIntersectsRect(CGRect rect1, CGRect rect2)
{
return CGRectContainsPoint(rect1, rect2.origin) ||
CGRectContainsPoint(rect1, CGPointMake(rect2.origin.x + rect2.size.width, rect2.origin.y)) ||
CGRectContainsPoint(rect1, CGPointMake(rect2.origin.x, rect2.origin.y + rect2.size.height)) ||
CGRectContainsPoint(rect1, CGPointMake(rect2.origin.x + rect2.size.width, rect2.origin.y + rect2.size.height));
}

七、一些持久化的方法

  • CFDictionaryRef CGPointCreateDictionaryRepresentation(CGPoint point)
    将一个点坐标转换成对应的一个不可变的字典,如CGPoint{1,2},转换成{"X":"1","Y":"2"}

  • bool CGPointMakeWithDictionaryRepresentation(CFDictionaryRef cg_nullable dict, CGPoint * cg_nullable point)
    将一个字典类型转的值转换成一个CGPoint

  • CFDictionaryRef CGSizeCreateDictionaryRepresentation(CGSize size)
    将一个CGSize转换成一个字典,如CGSize{1,2},转换成{"Width":"1","Height":"2"}

  • bool CGSizeMakeWithDictionaryRepresentation(CFDictionaryRef cg_nullable dict, CGSize * cg_nullable size)
    将一个字典转换成CGSize

  • CFDictionaryRef CGRectCreateDictionaryRepresentation(CGRect rect)
    将CGRect转换成一个字典,如CGRect{1,2,3,4},转换成{"X":"1","Y":"2","Width":"3","Height":"4"}

  • bool CGRectMakeWithDictionaryRepresentation(CFDictionaryRef cg_nullable dict, CGRect * cg_nullable rect)
    将一个字典转换成一个CGRect

八、系统内联函数的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
CGPoint CGPointMake(CGFloat x, CGFloat y)
{
CGPoint p; p.x = x; p.y = y; return p;
}
CGSize CGSizeMake(CGFloat width, CGFloat height)
{
CGSize size; size.width = width; size.height = height; return size;
}
CGVector CGVectorMake(CGFloat dx, CGFloat dy)
{
CGVector vector; vector.dx = dx; vector.dy = dy; return vector;
}
CGRect CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
CGRect rect;
rect.origin.x = x; rect.origin.y = y;
rect.size.width = width; rect.size.height = height;
return rect;
}
bool __CGPointEqualToPoint(CGPoint point1, CGPoint point2)
{
return point1.x == point2.x && point1.y == point2.y;
}
#define CGPointEqualToPoint __CGPointEqualToPoint
bool __CGSizeEqualToSize(CGSize size1, CGSize size2)
{
return size1.width == size2.width && size1.height == size2.height;
}
#define CGSizeEqualToSize __CGSizeEqualToSize