YMUtilsMacro.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. //
  2. // YMUtilsMacro.h
  3. // MSYOUPAI
  4. //
  5. // Created by YoMi on 2024/2/4.
  6. // Copyright © 2024 MS. All rights reserved.
  7. //
  8. /** 字符串是否为空*/
  9. #define OCStringIsEmpty(str) ([str isKindOfClass:[NSNull class]] || str == nil || [str length] < 1 ? YES : NO )
  10. /** 数组是否为空*/
  11. #define OCArrayIsEmpty(array) (array == nil || [array isKindOfClass:[NSNull class]] || array.count == 0)
  12. /** 字典是否为空*/
  13. #define OCDictionaryIsEmpty(dic) (dic == nil || [dic isKindOfClass:[NSNull class]] || dic.allKeys.count == 0)
  14. #define stringFormat(format,...) [NSString stringWithFormat:format,##__VA_ARGS__]
  15. #define ImageByName(value) [UIImage imageNamed:NSLocalizedString((value), nil)]
  16. /** 创建weakSelf*/
  17. #define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;
  18. /** 数据存储*/
  19. #define OCUserDefaults [NSUserDefaults standardUserDefaults]
  20. /** 通知*/
  21. #define OCNotificationCenter [NSNotificationCenter defaultCenter]
  22. /** 自定义打印log*/
  23. //#ifdef DEBUG
  24. #define YMLog(FORMAT, ...) {\
  25. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];\
  26. [dateFormatter setDateStyle:NSDateFormatterMediumStyle];\
  27. [dateFormatter setTimeStyle:NSDateFormatterShortStyle];\
  28. NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Beijing"];\
  29. [dateFormatter setTimeZone:timeZone];\
  30. [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSSZ"];\
  31. NSString *str = [dateFormatter stringFromDate:[NSDate date]];\
  32. fprintf(stderr,"[💻DEBUG信息打印]\n[打印时间:%s]\n[打印文件来源:%s--打印字段来源第%d行]\n[文件方法:%s]\n%s\n",[str UTF8String],[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__,__PRETTY_FUNCTION__,[[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);\
  33. }
  34. //#else
  35. //#define YMLog(...);
  36. //#endif
  37. /** 状态条高度*/
  38. #define OC_STATUSBAR_HEIGHT \
  39. ^(){\
  40. if (@available(iOS 13.0, *)) {\
  41. UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.firstObject.windowScene.statusBarManager;\
  42. return statusBarManager.statusBarFrame.size.height;\
  43. } else {\
  44. return [UIApplication sharedApplication].statusBarFrame.size.height;\
  45. }\
  46. }()
  47. /** 底部指示条*/
  48. #define OC_INDICATOR_HEIGHT \
  49. ^(){\
  50. if (@available(iOS 13.0, *)) {\
  51. NSSet *set = [UIApplication sharedApplication].connectedScenes;\
  52. UIWindowScene *windowScene = [set anyObject];\
  53. UIWindow *window = windowScene.windows.firstObject;\
  54. return window.safeAreaInsets.bottom;\
  55. } else if (@available(iOS 11.0, *)) {\
  56. UIWindow *window = [UIApplication sharedApplication].windows.firstObject;\
  57. return window.safeAreaInsets.bottom;\
  58. }\
  59. }()
  60. #define kYMStatusBarHeight OC_STATUSBAR_HEIGHT
  61. #define kYMTopSafeHeight OC_STATUSBAR_HEIGHT
  62. #define kYMBottomSafeHeight OC_INDICATOR_HEIGHT
  63. /// 导航条高度
  64. #define kYMContentNavBarHeight 44.0
  65. #define kYMNavHeight (kYMStatusBarHeight + kYMContentNavBarHeight)
  66. #define kYMTabBarHeight (49.0 + kYMBottomSafeHeight)
  67. /** 是否首次进入App*/
  68. #define kIS_FIRST_ENTER_APP @"IS_FIRST_ENTER_APP"
  69. #pragma mark - CGFloat
  70. /**
  71. * 某些地方可能会将 CGFLOAT_MIN 作为一个数值参与计算(但其实 CGFLOAT_MIN 更应该被视为一个标志位而不是数值),可能导致一些精度问题,所以提供这个方法快速将 CGFLOAT_MIN 转换为 0
  72. * issue: https://github.com/Tencent/QMUI_iOS/issues/203
  73. */
  74. CG_INLINE CGFloat
  75. removeFloatMin(CGFloat floatValue) {
  76. return floatValue == CGFLOAT_MIN ? 0 : floatValue;
  77. }
  78. /**
  79. * 基于指定的倍数,对传进来的 floatValue 进行像素取整。若指定倍数为0,则表示以当前设备的屏幕倍数为准。
  80. *
  81. * 例如传进来 “2.1”,在 2x 倍数下会返回 2.5(0.5pt 对应 1px),在 3x 倍数下会返回 2.333(0.333pt 对应 1px)。
  82. */
  83. CG_INLINE CGFloat
  84. flatSpecificScale(CGFloat floatValue, CGFloat scale) {
  85. floatValue = removeFloatMin(floatValue);
  86. scale = scale ?: ([[UIScreen mainScreen] scale]);
  87. CGFloat flattedValue = ceil(floatValue * scale) / scale;
  88. return flattedValue;
  89. }
  90. /**
  91. * 基于当前设备的屏幕倍数,对传进来的 floatValue 进行像素取整。
  92. *
  93. * 注意如果在 Core Graphic 绘图里使用时,要注意当前画布的倍数是否和设备屏幕倍数一致,若不一致,不可使用 flat() 函数,而应该用 flatSpecificScale
  94. */
  95. CG_INLINE CGFloat
  96. flat(CGFloat floatValue) {
  97. return flatSpecificScale(floatValue, 0);
  98. }
  99. /**
  100. * 类似flat(),只不过 flat 是向上取整,而 floorInPixel 是向下取整
  101. */
  102. CG_INLINE CGFloat
  103. floorInPixel(CGFloat floatValue) {
  104. floatValue = removeFloatMin(floatValue);
  105. CGFloat resultValue = floor(floatValue * ([[UIScreen mainScreen] scale])) / ([[UIScreen mainScreen] scale]);
  106. return resultValue;
  107. }
  108. CG_INLINE BOOL
  109. between(CGFloat minimumValue, CGFloat value, CGFloat maximumValue) {
  110. return minimumValue < value && value < maximumValue;
  111. }
  112. CG_INLINE BOOL
  113. betweenOrEqual(CGFloat minimumValue, CGFloat value, CGFloat maximumValue) {
  114. return minimumValue <= value && value <= maximumValue;
  115. }
  116. /**
  117. * 调整给定的某个 CGFloat 值的小数点精度,超过精度的部分按四舍五入处理。
  118. *
  119. * 例如 CGFloatToFixed(0.3333, 2) 会返回 0.33,而 CGFloatToFixed(0.6666, 2) 会返回 0.67
  120. *
  121. * @warning 参数类型为 CGFloat,也即意味着不管传进来的是 float 还是 double 最终都会被强制转换成 CGFloat 再做计算
  122. * @warning 该方法无法解决浮点数精度运算的问题,如需做浮点数的 == 判断,可用下方的 CGFloatEqualToFloat()
  123. */
  124. CG_INLINE CGFloat
  125. CGFloatToFixed(CGFloat value, NSUInteger precision) {
  126. NSString *formatString = [NSString stringWithFormat:@"%%.%@f", @(precision)];
  127. NSString *toString = [NSString stringWithFormat:formatString, value];
  128. #if CGFLOAT_IS_DOUBLE
  129. CGFloat result = [toString doubleValue];
  130. #else
  131. CGFloat result = [toString floatValue];
  132. #endif
  133. return result;
  134. }
  135. /**
  136. 用于两个 CGFloat 值之间的比较运算,支持 ==、>、<、>=、<= 5种,内部会将浮点数转成整型,从而避免浮点数精度导致的判断错误。
  137. CGFloatEqualToFloatWithPrecision()
  138. CGFloatEqualToFloat()
  139. CGFloatMoreThanFloatWithPrecision()
  140. CGFloatMoreThanFloat()
  141. CGFloatMoreThanOrEqualToFloatWithPrecision()
  142. CGFloatMoreThanOrEqualToFloat()
  143. CGFloatLessThanFloatWithPrecision()
  144. CGFloatLessThanFloat()
  145. CGFloatLessThanOrEqualToFloatWithPrecision()
  146. CGFloatLessThanOrEqualToFloat()
  147. 可通过参数 precision 指定要考虑的小数点后的精度,精度的定义是保证指定的那一位小数点不会因为浮点问题导致计算错误,例如当我们要获取一个 1.0 的浮点数时,有时候会得到 0.99999999,有时候会得到 1.000000001,所以需要对指定的那一位小数点的后一位数进行四舍五入操作。
  148. @code
  149. precision = 0,也即对小数点后0+1位四舍五入
  150. 0.999 -> 0.9 -> round(0.9) -> 1
  151. 1.011 -> 1.0 -> round(1.0) -> 1
  152. 1.033 -> 1.0 -> round(1.0) -> 1
  153. 1.099 -> 1.0 -> round(1.0) -> 1
  154. precision = 1,也即对小数点后1+1位四舍五入
  155. 0.999 -> 9.9 -> round(9.9) -> 10 -> 1.0
  156. 1.011 -> 10.1 -> round(10.1) -> 10 -> 1.0
  157. 1.033 -> 10.3 -> round(10.3) -> 10 -> 1.0
  158. 1.099 -> 10.9 -> round(10.9) -> 11 -> 1.1
  159. precision = 2,也即对小数点后2+1位四舍五入
  160. 0.999 -> 99.9 -> round(99.9) -> 100 -> 1.00
  161. 1.011 -> 101.1 -> round(101.1) -> 101 -> 1.01
  162. 1.033 -> 103.3 -> round(103.3) -> 103 -> 1.03
  163. 1.099 -> 109.9 -> round(109.9) -> 110 -> 1.1
  164. @endcode
  165. */
  166. CG_INLINE NSInteger _RoundedIntegerFromCGFloat(CGFloat value, NSUInteger precision) {
  167. return (NSInteger)(round(value * pow(10, precision)));
  168. }
  169. #define _CGFloatCalcGenerator(_operatorName, _operator) CG_INLINE BOOL CGFloat##_operatorName##FloatWithPrecision(CGFloat value1, CGFloat value2, NSUInteger precision) {\
  170. NSInteger a = _RoundedIntegerFromCGFloat(value1, precision);\
  171. NSInteger b = _RoundedIntegerFromCGFloat(value2, precision);\
  172. return a _operator b;\
  173. }\
  174. CG_INLINE BOOL CGFloat##_operatorName##Float(CGFloat value1, CGFloat value2) {\
  175. return CGFloat##_operatorName##FloatWithPrecision(value1, value2, 0);\
  176. }
  177. _CGFloatCalcGenerator(EqualTo, ==)
  178. _CGFloatCalcGenerator(LessThan, <)
  179. _CGFloatCalcGenerator(LessThanOrEqualTo, <=)
  180. _CGFloatCalcGenerator(MoreThan, >)
  181. _CGFloatCalcGenerator(MoreThanOrEqualTo, >=)
  182. /// 用于居中运算
  183. CG_INLINE CGFloat
  184. CGFloatGetCenter(CGFloat parent, CGFloat child) {
  185. return flat((parent - child) / 2.0);
  186. }
  187. /// 检测某个数值如果为 NaN 则将其转换为 0,避免布局中出现 crash
  188. CG_INLINE CGFloat
  189. CGFloatSafeValue(CGFloat value) {
  190. return isnan(value) ? 0 : value;
  191. }
  192. #pragma mark - CGPoint
  193. /// 两个point相加
  194. CG_INLINE CGPoint
  195. CGPointUnion(CGPoint point1, CGPoint point2) {
  196. return CGPointMake(flat(point1.x + point2.x), flat(point1.y + point2.y));
  197. }
  198. /// 获取rect的center,包括rect本身的x/y偏移
  199. CG_INLINE CGPoint
  200. CGPointGetCenterWithRect(CGRect rect) {
  201. return CGPointMake(flat(CGRectGetMidX(rect)), flat(CGRectGetMidY(rect)));
  202. }
  203. CG_INLINE CGPoint
  204. CGPointGetCenterWithSize(CGSize size) {
  205. return CGPointMake(flat(size.width / 2.0), flat(size.height / 2.0));
  206. }
  207. CG_INLINE CGPoint
  208. CGPointToFixed(CGPoint point, NSUInteger precision) {
  209. CGPoint result = CGPointMake(CGFloatToFixed(point.x, precision), CGFloatToFixed(point.y, precision));
  210. return result;
  211. }
  212. CG_INLINE CGPoint
  213. CGPointRemoveFloatMin(CGPoint point) {
  214. CGPoint result = CGPointMake(removeFloatMin(point.x), removeFloatMin(point.y));
  215. return result;
  216. }
  217. #pragma mark - UIEdgeInsets
  218. /// 获取UIEdgeInsets在水平方向上的值
  219. CG_INLINE CGFloat
  220. UIEdgeInsetsGetHorizontalValue(UIEdgeInsets insets) {
  221. return insets.left + insets.right;
  222. }
  223. /// 获取UIEdgeInsets在垂直方向上的值
  224. CG_INLINE CGFloat
  225. UIEdgeInsetsGetVerticalValue(UIEdgeInsets insets) {
  226. return insets.top + insets.bottom;
  227. }
  228. /// 将两个UIEdgeInsets合并为一个
  229. CG_INLINE UIEdgeInsets
  230. UIEdgeInsetsConcat(UIEdgeInsets insets1, UIEdgeInsets insets2) {
  231. insets1.top += insets2.top;
  232. insets1.left += insets2.left;
  233. insets1.bottom += insets2.bottom;
  234. insets1.right += insets2.right;
  235. return insets1;
  236. }
  237. CG_INLINE UIEdgeInsets
  238. UIEdgeInsetsSetTop(UIEdgeInsets insets, CGFloat top) {
  239. insets.top = flat(top);
  240. return insets;
  241. }
  242. CG_INLINE UIEdgeInsets
  243. UIEdgeInsetsSetLeft(UIEdgeInsets insets, CGFloat left) {
  244. insets.left = flat(left);
  245. return insets;
  246. }
  247. CG_INLINE UIEdgeInsets
  248. UIEdgeInsetsSetBottom(UIEdgeInsets insets, CGFloat bottom) {
  249. insets.bottom = flat(bottom);
  250. return insets;
  251. }
  252. CG_INLINE UIEdgeInsets
  253. UIEdgeInsetsSetRight(UIEdgeInsets insets, CGFloat right) {
  254. insets.right = flat(right);
  255. return insets;
  256. }
  257. CG_INLINE UIEdgeInsets
  258. UIEdgeInsetsToFixed(UIEdgeInsets insets, NSUInteger precision) {
  259. UIEdgeInsets result = UIEdgeInsetsMake(CGFloatToFixed(insets.top, precision), CGFloatToFixed(insets.left, precision), CGFloatToFixed(insets.bottom, precision), CGFloatToFixed(insets.right, precision));
  260. return result;
  261. }
  262. CG_INLINE UIEdgeInsets
  263. UIEdgeInsetsRemoveFloatMin(UIEdgeInsets insets) {
  264. UIEdgeInsets result = UIEdgeInsetsMake(removeFloatMin(insets.top), removeFloatMin(insets.left), removeFloatMin(insets.bottom), removeFloatMin(insets.right));
  265. return result;
  266. }
  267. #pragma mark - CGSize
  268. /// 判断一个 CGSize 是否存在 NaN
  269. CG_INLINE BOOL
  270. CGSizeIsNaN(CGSize size) {
  271. return isnan(size.width) || isnan(size.height);
  272. }
  273. /// 判断一个 CGSize 是否存在 infinite
  274. CG_INLINE BOOL
  275. CGSizeIsInf(CGSize size) {
  276. return isinf(size.width) || isinf(size.height);
  277. }
  278. /// 判断一个 CGSize 是否为空(宽或高为0)
  279. CG_INLINE BOOL
  280. CGSizeIsEmpty(CGSize size) {
  281. return size.width <= 0 || size.height <= 0;
  282. }
  283. /// 判断一个 CGSize 是否合法(例如不带无穷大的值、不带非法数字)
  284. CG_INLINE BOOL
  285. CGSizeIsValidated(CGSize size) {
  286. return !CGSizeIsEmpty(size) && !CGSizeIsInf(size) && !CGSizeIsNaN(size);
  287. }
  288. /// 将一个 CGSize 像素对齐
  289. CG_INLINE CGSize
  290. CGSizeFlatted(CGSize size) {
  291. return CGSizeMake(flat(size.width), flat(size.height));
  292. }
  293. /// 将一个 CGSize 以 pt 为单位向上取整
  294. CG_INLINE CGSize
  295. CGSizeCeil(CGSize size) {
  296. return CGSizeMake(ceil(size.width), ceil(size.height));
  297. }
  298. /// 将一个 CGSize 以 pt 为单位向下取整
  299. CG_INLINE CGSize
  300. CGSizeFloor(CGSize size) {
  301. return CGSizeMake(floor(size.width), floor(size.height));
  302. }
  303. CG_INLINE CGSize
  304. CGSizeToFixed(CGSize size, NSUInteger precision) {
  305. CGSize result = CGSizeMake(CGFloatToFixed(size.width, precision), CGFloatToFixed(size.height, precision));
  306. return result;
  307. }
  308. CG_INLINE CGSize
  309. CGSizeRemoveFloatMin(CGSize size) {
  310. CGSize result = CGSizeMake(removeFloatMin(size.width), removeFloatMin(size.height));
  311. return result;
  312. }
  313. #pragma mark - CGRect
  314. /// 判断一个 CGRect 是否存在 NaN
  315. CG_INLINE BOOL
  316. CGRectIsNaN(CGRect rect) {
  317. return isnan(rect.origin.x) || isnan(rect.origin.y) || isnan(rect.size.width) || isnan(rect.size.height);
  318. }
  319. /// 系统提供的 CGRectIsInfinite 接口只能判断 CGRectInfinite 的情况,而该接口可以用于判断 INFINITY 的值
  320. CG_INLINE BOOL
  321. CGRectIsInf(CGRect rect) {
  322. return isinf(rect.origin.x) || isinf(rect.origin.y) || isinf(rect.size.width) || isinf(rect.size.height);
  323. }
  324. /// 判断一个 CGRect 是否合法(例如不带无穷大的值、不带非法数字)
  325. CG_INLINE BOOL
  326. CGRectIsValidated(CGRect rect) {
  327. return !CGRectIsNull(rect) && !CGRectIsInfinite(rect) && !CGRectIsNaN(rect) && !CGRectIsInf(rect);
  328. }
  329. /// 检测某个 CGRect 如果存在数值为 NaN 的则将其转换为 0,避免布局中出现 crash
  330. CG_INLINE CGRect
  331. CGRectSafeValue(CGRect rect) {
  332. return CGRectMake(CGFloatSafeValue(CGRectGetMinX(rect)), CGFloatSafeValue(CGRectGetMinY(rect)), CGFloatSafeValue(CGRectGetWidth(rect)), CGFloatSafeValue(CGRectGetHeight(rect)));
  333. }
  334. /// 创建一个像素对齐的CGRect
  335. CG_INLINE CGRect
  336. CGRectFlatMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height) {
  337. return CGRectMake(flat(x), flat(y), flat(width), flat(height));
  338. }
  339. /// 对CGRect的x/y、width/height都调用一次flat,以保证像素对齐
  340. CG_INLINE CGRect
  341. CGRectFlatted(CGRect rect) {
  342. return CGRectMake(flat(rect.origin.x), flat(rect.origin.y), flat(rect.size.width), flat(rect.size.height));
  343. }
  344. /// 计算目标点 targetPoint 围绕坐标点 coordinatePoint 通过 transform 之后此点的坐标
  345. CG_INLINE CGPoint
  346. CGPointApplyAffineTransformWithCoordinatePoint(CGPoint coordinatePoint, CGPoint targetPoint, CGAffineTransform t) {
  347. CGPoint p;
  348. p.x = (targetPoint.x - coordinatePoint.x) * t.a + (targetPoint.y - coordinatePoint.y) * t.c + coordinatePoint.x;
  349. p.y = (targetPoint.x - coordinatePoint.x) * t.b + (targetPoint.y - coordinatePoint.y) * t.d + coordinatePoint.y;
  350. p.x += t.tx;
  351. p.y += t.ty;
  352. return p;
  353. }
  354. /// 系统的 CGRectApplyAffineTransform 只会按照 anchorPoint 为 (0, 0) 的方式去计算,但通常情况下我们面对的是 UIView/CALayer,它们默认的 anchorPoint 为 (.5, .5),所以增加这个函数,在计算 transform 时可以考虑上 anchorPoint 的影响
  355. CG_INLINE CGRect
  356. CGRectApplyAffineTransformWithAnchorPoint(CGRect rect, CGAffineTransform t, CGPoint anchorPoint) {
  357. CGFloat width = CGRectGetWidth(rect);
  358. CGFloat height = CGRectGetHeight(rect);
  359. CGPoint oPoint = CGPointMake(rect.origin.x + width * anchorPoint.x, rect.origin.y + height * anchorPoint.y);
  360. CGPoint top_left = CGPointApplyAffineTransformWithCoordinatePoint(oPoint, CGPointMake(rect.origin.x, rect.origin.y), t);
  361. CGPoint bottom_left = CGPointApplyAffineTransformWithCoordinatePoint(oPoint, CGPointMake(rect.origin.x, rect.origin.y + height), t);
  362. CGPoint top_right = CGPointApplyAffineTransformWithCoordinatePoint(oPoint, CGPointMake(rect.origin.x + width, rect.origin.y), t);
  363. CGPoint bottom_right = CGPointApplyAffineTransformWithCoordinatePoint(oPoint, CGPointMake(rect.origin.x + width, rect.origin.y + height), t);
  364. CGFloat minX = MIN(MIN(MIN(top_left.x, bottom_left.x), top_right.x), bottom_right.x);
  365. CGFloat maxX = MAX(MAX(MAX(top_left.x, bottom_left.x), top_right.x), bottom_right.x);
  366. CGFloat minY = MIN(MIN(MIN(top_left.y, bottom_left.y), top_right.y), bottom_right.y);
  367. CGFloat maxY = MAX(MAX(MAX(top_left.y, bottom_left.y), top_right.y), bottom_right.y);
  368. CGFloat newWidth = maxX - minX;
  369. CGFloat newHeight = maxY - minY;
  370. CGRect result = CGRectMake(minX, minY, newWidth, newHeight);
  371. return result;
  372. }
  373. /// 为一个CGRect叠加scale计算
  374. CG_INLINE CGRect
  375. CGRectApplyScale(CGRect rect, CGFloat scale) {
  376. return CGRectFlatted(CGRectMake(CGRectGetMinX(rect) * scale, CGRectGetMinY(rect) * scale, CGRectGetWidth(rect) * scale, CGRectGetHeight(rect) * scale));
  377. }
  378. /// 计算view的水平居中,传入父view和子view的frame,返回子view在水平居中时的x值
  379. CG_INLINE CGFloat
  380. CGRectGetMinXHorizontallyCenterInParentRect(CGRect parentRect, CGRect childRect) {
  381. return flat((CGRectGetWidth(parentRect) - CGRectGetWidth(childRect)) / 2.0);
  382. }
  383. /// 计算view的垂直居中,传入父view和子view的frame,返回子view在垂直居中时的y值
  384. CG_INLINE CGFloat
  385. CGRectGetMinYVerticallyCenterInParentRect(CGRect parentRect, CGRect childRect) {
  386. return flat((CGRectGetHeight(parentRect) - CGRectGetHeight(childRect)) / 2.0);
  387. }
  388. /// 返回值:同一个坐标系内,想要layoutingRect和已布局完成的referenceRect保持垂直居中时,layoutingRect的originY
  389. CG_INLINE CGFloat
  390. CGRectGetMinYVerticallyCenter(CGRect referenceRect, CGRect layoutingRect) {
  391. return CGRectGetMinY(referenceRect) + CGRectGetMinYVerticallyCenterInParentRect(referenceRect, layoutingRect);
  392. }
  393. /// 返回值:同一个坐标系内,想要layoutingRect和已布局完成的referenceRect保持水平居中时,layoutingRect的originX
  394. CG_INLINE CGFloat
  395. CGRectGetMinXHorizontallyCenter(CGRect referenceRect, CGRect layoutingRect) {
  396. return CGRectGetMinX(referenceRect) + CGRectGetMinXHorizontallyCenterInParentRect(referenceRect, layoutingRect);
  397. }
  398. /// 为给定的rect往内部缩小insets的大小(系统那个方法的命名太难联想了,所以定义了一个新函数)
  399. CG_INLINE CGRect
  400. CGRectInsetEdges(CGRect rect, UIEdgeInsets insets) {
  401. return UIEdgeInsetsInsetRect(rect, insets);
  402. }
  403. /// 传入size,返回一个x/y为0的CGRect
  404. CG_INLINE CGRect
  405. CGRectMakeWithSize(CGSize size) {
  406. return CGRectMake(0, 0, size.width, size.height);
  407. }
  408. CG_INLINE CGRect
  409. CGRectFloatTop(CGRect rect, CGFloat top) {
  410. rect.origin.y = top;
  411. return rect;
  412. }
  413. CG_INLINE CGRect
  414. CGRectFloatBottom(CGRect rect, CGFloat bottom) {
  415. rect.origin.y = bottom - CGRectGetHeight(rect);
  416. return rect;
  417. }
  418. CG_INLINE CGRect
  419. CGRectFloatRight(CGRect rect, CGFloat right) {
  420. rect.origin.x = right - CGRectGetWidth(rect);
  421. return rect;
  422. }
  423. CG_INLINE CGRect
  424. CGRectFloatLeft(CGRect rect, CGFloat left) {
  425. rect.origin.x = left;
  426. return rect;
  427. }
  428. /// 保持rect的左边缘不变,改变其宽度,使右边缘靠在right上
  429. CG_INLINE CGRect
  430. CGRectLimitRight(CGRect rect, CGFloat rightLimit) {
  431. rect.size.width = rightLimit - rect.origin.x;
  432. return rect;
  433. }
  434. /// 保持rect右边缘不变,改变其宽度和origin.x,使其左边缘靠在left上。只适合那种右边缘不动的view
  435. /// 先改变origin.x,让其靠在offset上
  436. /// 再改变size.width,减少同样的宽度,以抵消改变origin.x带来的view移动,从而保证view的右边缘是不动的
  437. CG_INLINE CGRect
  438. CGRectLimitLeft(CGRect rect, CGFloat leftLimit) {
  439. CGFloat subOffset = leftLimit - rect.origin.x;
  440. rect.origin.x = leftLimit;
  441. rect.size.width = rect.size.width - subOffset;
  442. return rect;
  443. }
  444. /// 限制rect的宽度,超过最大宽度则截断,否则保持rect的宽度不变
  445. CG_INLINE CGRect
  446. CGRectLimitMaxWidth(CGRect rect, CGFloat maxWidth) {
  447. CGFloat width = CGRectGetWidth(rect);
  448. rect.size.width = width > maxWidth ? maxWidth : width;
  449. return rect;
  450. }
  451. CG_INLINE CGRect
  452. CGRectSetX(CGRect rect, CGFloat x) {
  453. rect.origin.x = flat(x);
  454. return rect;
  455. }
  456. CG_INLINE CGRect
  457. CGRectSetY(CGRect rect, CGFloat y) {
  458. rect.origin.y = flat(y);
  459. return rect;
  460. }
  461. CG_INLINE CGRect
  462. CGRectSetXY(CGRect rect, CGFloat x, CGFloat y) {
  463. rect.origin.x = flat(x);
  464. rect.origin.y = flat(y);
  465. return rect;
  466. }
  467. CG_INLINE CGRect
  468. CGRectSetWidth(CGRect rect, CGFloat width) {
  469. if (width < 0) {
  470. return rect;
  471. }
  472. rect.size.width = flat(width);
  473. return rect;
  474. }
  475. CG_INLINE CGRect
  476. CGRectSetHeight(CGRect rect, CGFloat height) {
  477. if (height < 0) {
  478. return rect;
  479. }
  480. rect.size.height = flat(height);
  481. return rect;
  482. }
  483. CG_INLINE CGRect
  484. CGRectSetSize(CGRect rect, CGSize size) {
  485. rect.size = CGSizeFlatted(size);
  486. return rect;
  487. }
  488. CG_INLINE CGRect
  489. CGRectToFixed(CGRect rect, NSUInteger precision) {
  490. CGRect result = CGRectMake(CGFloatToFixed(CGRectGetMinX(rect), precision),
  491. CGFloatToFixed(CGRectGetMinY(rect), precision),
  492. CGFloatToFixed(CGRectGetWidth(rect), precision),
  493. CGFloatToFixed(CGRectGetHeight(rect), precision));
  494. return result;
  495. }
  496. CG_INLINE CGRect
  497. CGRectRemoveFloatMin(CGRect rect) {
  498. CGRect result = CGRectMake(removeFloatMin(CGRectGetMinX(rect)),
  499. removeFloatMin(CGRectGetMinY(rect)),
  500. removeFloatMin(CGRectGetWidth(rect)),
  501. removeFloatMin(CGRectGetHeight(rect)));
  502. return result;
  503. }
  504. /// outerRange 是否包含了 innerRange
  505. CG_INLINE BOOL
  506. NSContainingRanges(NSRange outerRange, NSRange innerRange) {
  507. if (innerRange.location >= outerRange.location && outerRange.location + outerRange.length >= innerRange.location + innerRange.length) {
  508. return YES;
  509. }
  510. return NO;
  511. }