QMUICommonDefines.h 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. /**
  2. * Tencent is pleased to support the open source community by making QMUI_iOS available.
  3. * Copyright (C) 2016-2021 THL A29 Limited, a Tencent company. All rights reserved.
  4. * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
  5. * http://opensource.org/licenses/MIT
  6. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
  7. */
  8. //
  9. // QMUICommonDefines.h
  10. // qmui
  11. //
  12. // Created by QMUI Team on 14-6-23.
  13. //
  14. #ifndef QMUICommonDefines_h
  15. #define QMUICommonDefines_h
  16. #import <UIKit/UIKit.h>
  17. #import "QMUIHelper.h"
  18. #import "NSString+QMUI.h"
  19. #pragma mark - 变量-编译相关
  20. /// 判断当前是否debug编译模式
  21. #ifdef DEBUG
  22. #define IS_DEBUG YES
  23. #else
  24. #define IS_DEBUG NO
  25. #endif
  26. #define IS_XCTEST (!!NSProcessInfo.processInfo.environment[@"XCTestConfigurationFilePath"])
  27. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
  28. /// 当前编译使用的 Base SDK 版本为 iOS 9.0 及以上
  29. #define IOS9_SDK_ALLOWED YES
  30. #endif
  31. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
  32. /// 当前编译使用的 Base SDK 版本为 iOS 10.0 及以上
  33. #define IOS10_SDK_ALLOWED YES
  34. #endif
  35. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
  36. /// 当前编译使用的 Base SDK 版本为 iOS 11.0 及以上
  37. #define IOS11_SDK_ALLOWED YES
  38. #endif
  39. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000
  40. /// 当前编译使用的 Base SDK 版本为 iOS 12.0 及以上
  41. #define IOS12_SDK_ALLOWED YES
  42. #endif
  43. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
  44. /// 当前编译使用的 Base SDK 版本为 iOS 13.0 及以上
  45. #define IOS13_SDK_ALLOWED YES
  46. #endif
  47. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000
  48. /// 当前编译使用的 Base SDK 版本为 iOS 14.0 及以上
  49. #define IOS14_SDK_ALLOWED YES
  50. #endif
  51. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
  52. /// 当前编译使用的 Base SDK 版本为 iOS 15.0 及以上
  53. #define IOS15_SDK_ALLOWED YES
  54. #endif
  55. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000
  56. /// 当前编译使用的 Base SDK 版本为 iOS 16.0 及以上
  57. #define IOS16_SDK_ALLOWED YES
  58. #endif
  59. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 170000
  60. /// 当前编译使用的 Base SDK 版本为 iOS 17.0 及以上
  61. #define IOS17_SDK_ALLOWED YES
  62. #endif
  63. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 180000
  64. /// 当前编译使用的 Base SDK 版本为 iOS 18.0 及以上
  65. #define IOS18_SDK_ALLOWED YES
  66. #endif
  67. #pragma mark - Clang
  68. #define ArgumentToString(macro) #macro
  69. #define ClangWarningConcat(warning_name) ArgumentToString(clang diagnostic ignored warning_name)
  70. /// 参数可直接传入 clang 的 warning 名,warning 列表参考:https://clang.llvm.org/docs/DiagnosticsReference.html
  71. #define BeginIgnoreClangWarning(warningName) _Pragma("clang diagnostic push") _Pragma(ClangWarningConcat(#warningName))
  72. #define EndIgnoreClangWarning _Pragma("clang diagnostic pop")
  73. #define BeginIgnorePerformSelectorLeaksWarning BeginIgnoreClangWarning(-Warc-performSelector-leaks)
  74. #define EndIgnorePerformSelectorLeaksWarning EndIgnoreClangWarning
  75. #define BeginIgnoreAvailabilityWarning BeginIgnoreClangWarning(-Wpartial-availability)
  76. #define EndIgnoreAvailabilityWarning EndIgnoreClangWarning
  77. #define BeginIgnoreDeprecatedWarning BeginIgnoreClangWarning(-Wdeprecated-declarations)
  78. #define EndIgnoreDeprecatedWarning EndIgnoreClangWarning
  79. #pragma mark - 忽略 iOS 13 KVC 访问私有属性限制
  80. /// 将 KVC 代码包裹在这个宏中,可忽略系统的 KVC 访问限制
  81. #define BeginIgnoreUIKVCAccessProhibited NSThread.currentThread.qmui_shouldIgnoreUIKVCAccessProhibited = YES;
  82. #define EndIgnoreUIKVCAccessProhibited NSThread.currentThread.qmui_shouldIgnoreUIKVCAccessProhibited = NO;
  83. #pragma mark - 变量-设备相关
  84. /// 设备类型
  85. #define IS_IPAD [QMUIHelper isIPad]
  86. #define IS_IPOD [QMUIHelper isIPod]
  87. #define IS_IPHONE [QMUIHelper isIPhone]
  88. #define IS_SIMULATOR [QMUIHelper isSimulator]
  89. #define IS_MAC [QMUIHelper isMac]
  90. /// 操作系统版本号,只获取第二级的版本号,例如 10.3.1 只会得到 10.3
  91. #define IOS_VERSION ([[[UIDevice currentDevice] systemVersion] doubleValue])
  92. /// 数字形式的操作系统版本号,可直接用于大小比较;如 110205 代表 11.2.5 版本;根据 iOS 规范,版本号最多可能有3位
  93. #define IOS_VERSION_NUMBER [QMUIHelper numbericOSVersion]
  94. /// 是否横竖屏
  95. /// 用户界面横屏了才会返回YES
  96. #define IS_LANDSCAPE UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)
  97. /// 无论支不支持横屏,只要设备横屏了,就会返回YES
  98. #define IS_DEVICE_LANDSCAPE UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation])
  99. /// 屏幕宽度,会根据横竖屏的变化而变化
  100. #define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
  101. /// 屏幕高度,会根据横竖屏的变化而变化
  102. #define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)
  103. /// 设备宽度,跟横竖屏无关
  104. #define DEVICE_WIDTH MIN([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)
  105. /// 设备高度,跟横竖屏无关
  106. #define DEVICE_HEIGHT MAX([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)
  107. /// 在 iPad 分屏模式下等于 app 实际运行宽度,否则等同于 SCREEN_WIDTH
  108. #define APPLICATION_WIDTH [QMUIHelper applicationSize].width
  109. /// 在 iPad 分屏模式下等于 app 实际运行宽度,否则等同于 DEVICE_HEIGHT
  110. #define APPLICATION_HEIGHT [QMUIHelper applicationSize].height
  111. /// 是否全面屏设备
  112. #define IS_NOTCHED_SCREEN [QMUIHelper isNotchedScreen]
  113. /// iPhone 14 Pro Max
  114. #define IS_67INCH_SCREEN_AND_IPHONE14 [QMUIHelper is67InchScreenAndiPhone14Later]
  115. /// iPhone 12 Pro Max
  116. #define IS_67INCH_SCREEN [QMUIHelper is67InchScreen]
  117. /// iPhone XS Max
  118. #define IS_65INCH_SCREEN [QMUIHelper is65InchScreen]
  119. /// iPhone 14 Pro / 15 Pro
  120. #define IS_61INCH_SCREEN_AND_IPHONE14PRO [QMUIHelper is61InchScreenAndiPhone14ProLater]
  121. /// iPhone 12 / 12 Pro
  122. #define IS_61INCH_SCREEN_AND_IPHONE12 [QMUIHelper is61InchScreenAndiPhone12Later]
  123. /// iPhone XR
  124. #define IS_61INCH_SCREEN [QMUIHelper is61InchScreen]
  125. /// iPhone X/XS
  126. #define IS_58INCH_SCREEN [QMUIHelper is58InchScreen]
  127. /// iPhone 6/7/8 Plus
  128. #define IS_55INCH_SCREEN [QMUIHelper is55InchScreen]
  129. /// iPhone 12 mini
  130. #define IS_54INCH_SCREEN [QMUIHelper is54InchScreen]
  131. /// iPhone 6/7/8
  132. #define IS_47INCH_SCREEN [QMUIHelper is47InchScreen]
  133. /// iPhone 5/5S/SE
  134. #define IS_40INCH_SCREEN [QMUIHelper is40InchScreen]
  135. /// iPhone 4/4S
  136. #define IS_35INCH_SCREEN [QMUIHelper is35InchScreen]
  137. /// iPhone 4/4S/5/5S/SE
  138. #define IS_320WIDTH_SCREEN (IS_35INCH_SCREEN || IS_40INCH_SCREEN)
  139. /// 是否Retina
  140. #define IS_RETINASCREEN ([[UIScreen mainScreen] scale] >= 2.0)
  141. /// 是否放大模式(iPhone 6及以上的设备支持放大模式,iPhone X 除外)
  142. #define IS_ZOOMEDMODE [QMUIHelper isZoomedMode]
  143. /// 当前设备是否拥有灵动岛
  144. #define IS_DYNAMICISLAND_DEVICE [QMUIHelper isDynamicIslandDevice]
  145. #pragma mark - 变量-布局相关
  146. /// 获取一个像素
  147. #define PixelOne [QMUIHelper pixelOne]
  148. /// bounds && nativeBounds / scale && nativeScale
  149. #define ScreenBoundsSize ([[UIScreen mainScreen] bounds].size)
  150. #define ScreenNativeBoundsSize ([[UIScreen mainScreen] nativeBounds].size)
  151. #define ScreenScale ([[UIScreen mainScreen] scale])
  152. #define ScreenNativeScale ([[UIScreen mainScreen] nativeScale])
  153. /// toolBar相关frame
  154. #define ToolBarHeight (IS_IPAD ? (IS_NOTCHED_SCREEN ? 70 : 50) : (IS_LANDSCAPE ? PreferredValueForVisualDevice(44, 32) : 44) + SafeAreaInsetsConstantForDeviceWithNotch.bottom)
  155. /// tabBar相关frame
  156. #define TabBarHeight (IS_IPAD ? (IS_NOTCHED_SCREEN ? 65 : 50) : (IS_LANDSCAPE ? PreferredValueForVisualDevice(49, 32) : 49) + SafeAreaInsetsConstantForDeviceWithNotch.bottom)
  157. /// 状态栏高度(来电等情况下,状态栏高度会发生变化,所以应该实时计算,iOS 13 起,来电等情况下状态栏高度不会改变)
  158. #define StatusBarHeight (UIApplication.sharedApplication.statusBarHidden ? 0 : UIApplication.sharedApplication.statusBarFrame.size.height)
  159. /// 状态栏高度(如果状态栏不可见,也会返回一个普通状态下可见的高度)
  160. #define StatusBarHeightConstant [QMUIHelper statusBarHeightConstant]
  161. /// navigationBar 的静态高度
  162. #define NavigationBarHeight (IS_IPAD ? 50 : (IS_LANDSCAPE ? PreferredValueForVisualDevice(44, 32) : 44))
  163. /// 代表(导航栏+状态栏),这里用于获取其高度
  164. /// @warn 如果是用于 viewController,请使用 UIViewController(QMUI) qmui_navigationBarMaxYInViewCoordinator 代替
  165. #define NavigationContentTop (StatusBarHeight + NavigationBarHeight)
  166. /// 同上,这里用于获取它的静态常量值
  167. #define NavigationContentTopConstant (QMUIHelper.navigationBarMaxYConstant)
  168. /// 判断当前是否是处于分屏模式的 iPad 或 iOS 16.1 的台前调度模式
  169. #define IS_SPLIT_SCREEN_IPAD (IS_IPAD && APPLICATION_WIDTH != SCREEN_WIDTH)
  170. /// iPhoneX 系列全面屏手机的安全区域的静态值
  171. #define SafeAreaInsetsConstantForDeviceWithNotch [QMUIHelper safeAreaInsetsForDeviceWithNotch]
  172. /// 将所有屏幕按照宽松/紧凑分类,其中 iPad、iPhone XS Max/XR/Plus 均为宽松屏幕,但开启了放大模式的设备均会视为紧凑屏幕
  173. #define PreferredValueForVisualDevice(_regular, _compact) ([QMUIHelper isRegularScreen] ? _regular : _compact)
  174. /// 将所有屏幕按照 Phone/Pad 分类,由于历史上宽高比最大(最胖)的手机为 iPhone 4,所以这里以它为基准,只要宽高比比 iPhone 4 更小的,都视为 Phone,其他情况均视为 Pad。注意 iPad 分屏则取分屏后的宽高来计算。
  175. #define PreferredValueForInterfaceIdiom(_phone, _pad) (APPLICATION_WIDTH / APPLICATION_HEIGHT <= QMUIHelper.screenSizeFor35Inch.width / QMUIHelper.screenSizeFor35Inch.height ? _phone : _pad)
  176. /// 区分全面屏和非全面屏
  177. #define PreferredValueForNotchedDevice(_notchedDevice, _otherDevice) ([QMUIHelper isNotchedScreen] ? _notchedDevice : _otherDevice)
  178. #pragma mark - 变量-布局相关-已废弃
  179. /// 由于 iOS 设备屏幕碎片化越来越严重,因此以下这些宏不建议使用,以后有设备更新也不再维护,请使用 PreferredValueForVisualDevice、PreferredValueForInterfaceIdiom 代替。
  180. /// 按屏幕宽度来区分不同 iPhone 尺寸,iPhone XS Max/XR/Plus 归为一类,iPhone X/8/7/6 归为一类。
  181. /// iPad 也会视为最大的屏幕宽度来处理
  182. #define PreferredValueForiPhone(_65or61or55inch, _47or58inch, _40inch, _35inch) PreferredValueForDeviceIncludingiPad(_65or61or55inch, _65or61or55inch, _47or58inch, _40inch, _35inch)
  183. /// 同上,单独将 iPad 区分对待
  184. #define PreferredValueForDeviceIncludingiPad(_iPad, _65or61or55inch, _47or58inch, _40inch, _35inch) PreferredValueForAll(_iPad, _65or61or55inch, _65or61or55inch, _47or58inch, _65or61or55inch, _47or58inch, _40inch, _35inch)
  185. /// 若 iPad 处于分屏模式下,返回 iPad 接近 iPhone 宽度(320、375、414)中近似的一种,方便屏幕适配。
  186. #define IPAD_SIMILAR_SCREEN_WIDTH [QMUIHelper preferredLayoutAsSimilarScreenWidthForIPad]
  187. #define _40INCH_WIDTH [QMUIHelper screenSizeFor40Inch].width
  188. #define _58INCH_WIDTH [QMUIHelper screenSizeFor58Inch].width
  189. #define _65INCH_WIDTH [QMUIHelper screenSizeFor65Inch].width
  190. #define AS_IPAD (DynamicPreferredValueForIPad ? ((IS_IPAD && !IS_SPLIT_SCREEN_IPAD) || (IS_SPLIT_SCREEN_IPAD && APPLICATION_WIDTH >= 768)) : IS_IPAD)
  191. #define AS_65INCH_SCREEN (IS_67INCH_SCREEN_AND_IPHONE14 || IS_67INCH_SCREEN || IS_65INCH_SCREEN || (IS_IPAD && DynamicPreferredValueForIPad && IPAD_SIMILAR_SCREEN_WIDTH == _65INCH_WIDTH))
  192. #define AS_61INCH_SCREEN (IS_61INCH_SCREEN_AND_IPHONE12 || IS_61INCH_SCREEN)
  193. #define AS_58INCH_SCREEN (IS_58INCH_SCREEN || IS_54INCH_SCREEN || ((AS_61INCH_SCREEN || AS_65INCH_SCREEN) && IS_ZOOMEDMODE) || (IS_IPAD && DynamicPreferredValueForIPad && IPAD_SIMILAR_SCREEN_WIDTH == _58INCH_WIDTH))
  194. #define AS_55INCH_SCREEN (IS_55INCH_SCREEN)
  195. #define AS_47INCH_SCREEN (IS_47INCH_SCREEN || (IS_55INCH_SCREEN && IS_ZOOMEDMODE))
  196. #define AS_40INCH_SCREEN (IS_40INCH_SCREEN || (IS_IPAD && DynamicPreferredValueForIPad && IPAD_SIMILAR_SCREEN_WIDTH == _40INCH_WIDTH))
  197. #define AS_35INCH_SCREEN IS_35INCH_SCREEN
  198. #define AS_320WIDTH_SCREEN IS_320WIDTH_SCREEN
  199. #define PreferredValueForAll(_iPad, _65inch, _61inch, _58inch, _55inch, _47inch, _40inch, _35inch) \
  200. (AS_IPAD ? _iPad :\
  201. (AS_35INCH_SCREEN ? _35inch :\
  202. (AS_40INCH_SCREEN ? _40inch :\
  203. (AS_47INCH_SCREEN ? _47inch :\
  204. (AS_55INCH_SCREEN ? _55inch :\
  205. (AS_58INCH_SCREEN ? _58inch :\
  206. (AS_61INCH_SCREEN ? _61inch : _65inch)))))))
  207. #pragma mark - 方法-创建器
  208. #define CGSizeMax CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)
  209. #define UIImageMake(img) [UIImage imageNamed:img]
  210. /// 使用文件名(不带后缀名,仅限png)创建一个UIImage对象,不会被系统缓存,用于不被复用的图片,特别是大图
  211. #define UIImageMakeWithFile(name) UIImageMakeWithFileAndSuffix(name, @"png")
  212. #define UIImageMakeWithFileAndSuffix(name, suffix) [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.%@", [[NSBundle mainBundle] resourcePath], name, suffix]]
  213. /// 字体相关的宏,用于快速创建一个字体对象,更多创建宏可查看 UIFont+QMUI.h
  214. #define UIFontMake(size) [UIFont systemFontOfSize:size]
  215. #define UIFontItalicMake(size) [UIFont italicSystemFontOfSize:size] /// 斜体只对数字和字母有效,中文无效
  216. #define UIFontBoldMake(size) [UIFont boldSystemFontOfSize:size]
  217. #define UIFontBoldWithFont(_font) [UIFont boldSystemFontOfSize:_font.pointSize]
  218. /// UIColor 相关的宏,用于快速创建一个 UIColor 对象,更多创建的宏可查看 UIColor+QMUI.h
  219. #define UIColorMake(r, g, b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
  220. #define UIColorMakeWithRGBA(r, g, b, a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a/1.0]
  221. #pragma mark - 数学计算
  222. #define AngleWithDegrees(deg) (M_PI * (deg) / 180.0)
  223. #pragma mark - 动画
  224. #define QMUIViewAnimationOptionsCurveOut (7<<16)
  225. #define QMUIViewAnimationOptionsCurveIn (8<<16)
  226. #pragma mark - 无障碍访问
  227. CG_INLINE void
  228. AddAccessibilityLabel(NSObject *obj, NSString *label) {
  229. obj.accessibilityLabel = label;
  230. }
  231. CG_INLINE void
  232. AddAccessibilityHint(NSObject *obj, NSString *hint) {
  233. obj.accessibilityHint = hint;
  234. }
  235. #pragma mark - 其他
  236. #define StringFromBOOL(_flag) (_flag ? @"YES" : @"NO")
  237. /// 代替 NSAssert 使用,在触发 assert 之前会用 QMUILogWarn 输出日志,当你开启了配置表的 ShouldPrintQMUIWarnLogToConsole 时,会用 QMUIConsole 代替 NSAssert,避免中断当前程序的运行
  238. /// 与 NSAssert 的差异在于,当你使用 NSAssert 时,整条语句默认不会出现在 Release 包里,但 QMUIAssert 依然会存在。
  239. /// 用法:QMUIAssert(a != b, @"UIView (QMUI)", @"xxxx")
  240. /// 用法:QMUIAssert(a != b, @"UIView (QMUI)", @"%@, xxx", @"xxx")
  241. #define QMUIAssert(_condition, _categoryName, ...) ({if (!(_condition)) {QMUILogWarn(_categoryName, __VA_ARGS__);if (!QMUICMIActivated || !ShouldPrintQMUIWarnLogToConsole) {NSAssert(NO, __VA_ARGS__);}}})
  242. #pragma mark - Selector
  243. /**
  244. 根据给定的 getter selector 获取对应的 setter selector
  245. @param getter 目标 getter selector
  246. @return 对应的 setter selector
  247. */
  248. CG_INLINE SEL
  249. setterWithGetter(SEL getter) {
  250. NSString *getterString = NSStringFromSelector(getter);
  251. NSMutableString *setterString = [[NSMutableString alloc] initWithString:@"set"];
  252. [setterString appendString:getterString.qmui_capitalizedString];
  253. [setterString appendString:@":"];
  254. SEL setter = NSSelectorFromString(setterString);
  255. return setter;
  256. }
  257. #pragma mark - CGFloat
  258. /**
  259. * 某些地方可能会将 CGFLOAT_MIN 作为一个数值参与计算(但其实 CGFLOAT_MIN 更应该被视为一个标志位而不是数值),可能导致一些精度问题,所以提供这个方法快速将 CGFLOAT_MIN 转换为 0
  260. * 某些情况可能计算出来是0.0000000x,也靠这个方法抹去尾数。
  261. * issue: https://github.com/Tencent/QMUI_iOS/issues/203
  262. */
  263. CG_INLINE CGFloat
  264. removeFloatMin(CGFloat floatValue) {
  265. return fabs(floatValue) <= 0.001 ? 0 : floatValue;
  266. }
  267. /**
  268. * 基于指定的倍数,对传进来的 floatValue 进行像素取整。若指定倍数为0,则表示以当前设备的屏幕倍数为准。
  269. *
  270. * 例如传进来 “2.1”,在 2x 倍数下会返回 2.5(0.5pt 对应 1px),在 3x 倍数下会返回 2.333(0.333pt 对应 1px)。
  271. */
  272. CG_INLINE CGFloat
  273. flatSpecificScale(CGFloat floatValue, CGFloat scale) {
  274. if (isinf(floatValue) || floatValue == CGFLOAT_MAX) return floatValue;
  275. floatValue = removeFloatMin(floatValue);
  276. scale = scale ?: ScreenScale;
  277. // 这里因为浮点精度的问题,可能会出现一些偏差,例如 161.66666666666669 算出来可能是162,161.66666666666666 算出来是161.66666666667,为了解决这种场景,这里同时用 ceil 和 round 算一遍再取最接近的那个结果
  278. NSInteger pixelValue1 = ceil(floatValue * scale);
  279. NSInteger pixelValue2 = round(floatValue * scale);
  280. NSInteger pixelValue = 0;
  281. if (fabs(pixelValue1 - floatValue) <= fabs(pixelValue2 - floatValue)) {
  282. pixelValue = pixelValue1;
  283. } else {
  284. pixelValue = pixelValue2;
  285. }
  286. CGFloat flattedValue = pixelValue / scale;
  287. return flattedValue;
  288. }
  289. /**
  290. * 基于当前设备的屏幕倍数,对传进来的 floatValue 进行像素取整。
  291. *
  292. * 注意如果在 Core Graphic 绘图里使用时,要注意当前画布的倍数是否和设备屏幕倍数一致,若不一致,不可使用 flat() 函数,而应该用 flatSpecificScale
  293. */
  294. CG_INLINE CGFloat
  295. flat(CGFloat floatValue) {
  296. return flatSpecificScale(floatValue, 0);
  297. }
  298. /**
  299. * 类似flat(),只不过 flat 是向上取整,而 floorInPixel 是向下取整
  300. */
  301. CG_INLINE CGFloat
  302. floorInPixel(CGFloat floatValue) {
  303. floatValue = removeFloatMin(floatValue);
  304. CGFloat resultValue = floor(floatValue * ScreenScale) / ScreenScale;
  305. return resultValue;
  306. }
  307. CG_INLINE BOOL
  308. between(CGFloat minimumValue, CGFloat value, CGFloat maximumValue) {
  309. return minimumValue < value && value < maximumValue;
  310. }
  311. CG_INLINE BOOL
  312. betweenOrEqual(CGFloat minimumValue, CGFloat value, CGFloat maximumValue) {
  313. return minimumValue <= value && value <= maximumValue;
  314. }
  315. /**
  316. * 调整给定的某个 CGFloat 值的小数点精度,超过精度的部分按四舍五入处理。
  317. *
  318. * 例如 CGFloatToFixed(0.3333, 2) 会返回 0.33,而 CGFloatToFixed(0.6666, 2) 会返回 0.67
  319. *
  320. * @warning 参数类型为 CGFloat,也即意味着不管传进来的是 float 还是 double 最终都会被强制转换成 CGFloat 再做计算
  321. * @warning 该方法无法解决浮点数精度运算的问题,如需做浮点数的 == 判断,可用下方的 CGFloatEqualToFloat()
  322. */
  323. CG_INLINE CGFloat
  324. CGFloatToFixed(CGFloat value, NSUInteger precision) {
  325. NSString *formatString = [NSString stringWithFormat:@"%%.%@f", @(precision)];
  326. NSString *toString = [NSString stringWithFormat:formatString, value];
  327. #if CGFLOAT_IS_DOUBLE
  328. CGFloat result = [toString doubleValue];
  329. #else
  330. CGFloat result = [toString floatValue];
  331. #endif
  332. return result;
  333. }
  334. /**
  335. 用于两个 CGFloat 值之间的比较运算,支持 ==、>、<、>=、<= 5种,内部会将浮点数转成整型,从而避免浮点数精度导致的判断错误。
  336. CGFloatEqualToFloatWithPrecision()
  337. CGFloatEqualToFloat()
  338. CGFloatMoreThanFloatWithPrecision()
  339. CGFloatMoreThanFloat()
  340. CGFloatMoreThanOrEqualToFloatWithPrecision()
  341. CGFloatMoreThanOrEqualToFloat()
  342. CGFloatLessThanFloatWithPrecision()
  343. CGFloatLessThanFloat()
  344. CGFloatLessThanOrEqualToFloatWithPrecision()
  345. CGFloatLessThanOrEqualToFloat()
  346. 可通过参数 precision 指定要考虑的小数点后的精度,精度的定义是保证指定的那一位小数点不会因为浮点问题导致计算错误,例如当我们要获取一个 1.0 的浮点数时,有时候会得到 0.99999999,有时候会得到 1.000000001,所以需要对指定的那一位小数点的后一位数进行四舍五入操作。
  347. @code
  348. precision = 0,也即对小数点后0+1位四舍五入
  349. 0.999 -> 0.9 -> round(0.9) -> 1
  350. 1.011 -> 1.0 -> round(1.0) -> 1
  351. 1.033 -> 1.0 -> round(1.0) -> 1
  352. 1.099 -> 1.0 -> round(1.0) -> 1
  353. precision = 1,也即对小数点后1+1位四舍五入
  354. 0.999 -> 9.9 -> round(9.9) -> 10 -> 1.0
  355. 1.011 -> 10.1 -> round(10.1) -> 10 -> 1.0
  356. 1.033 -> 10.3 -> round(10.3) -> 10 -> 1.0
  357. 1.099 -> 10.9 -> round(10.9) -> 11 -> 1.1
  358. precision = 2,也即对小数点后2+1位四舍五入
  359. 0.999 -> 99.9 -> round(99.9) -> 100 -> 1.00
  360. 1.011 -> 101.1 -> round(101.1) -> 101 -> 1.01
  361. 1.033 -> 103.3 -> round(103.3) -> 103 -> 1.03
  362. 1.099 -> 109.9 -> round(109.9) -> 110 -> 1.1
  363. @endcode
  364. */
  365. CG_INLINE NSInteger _RoundedIntegerFromCGFloat(CGFloat value, NSUInteger precision) {
  366. return (NSInteger)(round(value * pow(10, precision)));
  367. }
  368. #define _CGFloatCalcGenerator(_operatorName, _operator) CG_INLINE BOOL CGFloat##_operatorName##FloatWithPrecision(CGFloat value1, CGFloat value2, NSUInteger precision) {\
  369. NSInteger a = _RoundedIntegerFromCGFloat(value1, precision);\
  370. NSInteger b = _RoundedIntegerFromCGFloat(value2, precision);\
  371. return a _operator b;\
  372. }\
  373. CG_INLINE BOOL CGFloat##_operatorName##Float(CGFloat value1, CGFloat value2) {\
  374. return CGFloat##_operatorName##FloatWithPrecision(value1, value2, 0);\
  375. }
  376. _CGFloatCalcGenerator(EqualTo, ==)
  377. _CGFloatCalcGenerator(LessThan, <)
  378. _CGFloatCalcGenerator(LessThanOrEqualTo, <=)
  379. _CGFloatCalcGenerator(MoreThan, >)
  380. _CGFloatCalcGenerator(MoreThanOrEqualTo, >=)
  381. /// 用于居中运算
  382. CG_INLINE CGFloat
  383. CGFloatGetCenter(CGFloat parent, CGFloat child) {
  384. return flat((parent - child) / 2.0);
  385. }
  386. /// 检测某个数值如果为 NaN 则将其转换为 0,避免布局中出现 crash
  387. CG_INLINE CGFloat
  388. CGFloatSafeValue(CGFloat value) {
  389. return isnan(value) ? 0 : value;
  390. }
  391. #pragma mark - CGPoint
  392. /// 两个point相加
  393. CG_INLINE CGPoint
  394. CGPointUnion(CGPoint point1, CGPoint point2) {
  395. return CGPointMake(flat(point1.x + point2.x), flat(point1.y + point2.y));
  396. }
  397. /// 获取rect的center,包括rect本身的x/y偏移
  398. CG_INLINE CGPoint
  399. CGPointGetCenterWithRect(CGRect rect) {
  400. return CGPointMake(flat(CGRectGetMidX(rect)), flat(CGRectGetMidY(rect)));
  401. }
  402. CG_INLINE CGPoint
  403. CGPointGetCenterWithSize(CGSize size) {
  404. return CGPointMake(flat(size.width / 2.0), flat(size.height / 2.0));
  405. }
  406. CG_INLINE CGPoint
  407. CGPointToFixed(CGPoint point, NSUInteger precision) {
  408. CGPoint result = CGPointMake(CGFloatToFixed(point.x, precision), CGFloatToFixed(point.y, precision));
  409. return result;
  410. }
  411. CG_INLINE CGPoint
  412. CGPointRemoveFloatMin(CGPoint point) {
  413. CGPoint result = CGPointMake(removeFloatMin(point.x), removeFloatMin(point.y));
  414. return result;
  415. }
  416. #pragma mark - UIEdgeInsets
  417. /// 获取UIEdgeInsets在水平方向上的值
  418. CG_INLINE CGFloat
  419. UIEdgeInsetsGetHorizontalValue(UIEdgeInsets insets) {
  420. return insets.left + insets.right;
  421. }
  422. /// 获取UIEdgeInsets在垂直方向上的值
  423. CG_INLINE CGFloat
  424. UIEdgeInsetsGetVerticalValue(UIEdgeInsets insets) {
  425. return insets.top + insets.bottom;
  426. }
  427. /// 将两个UIEdgeInsets合并为一个
  428. CG_INLINE UIEdgeInsets
  429. UIEdgeInsetsConcat(UIEdgeInsets insets1, UIEdgeInsets insets2) {
  430. insets1.top += insets2.top;
  431. insets1.left += insets2.left;
  432. insets1.bottom += insets2.bottom;
  433. insets1.right += insets2.right;
  434. return insets1;
  435. }
  436. CG_INLINE UIEdgeInsets
  437. UIEdgeInsetsSetTop(UIEdgeInsets insets, CGFloat top) {
  438. insets.top = flat(top);
  439. return insets;
  440. }
  441. CG_INLINE UIEdgeInsets
  442. UIEdgeInsetsSetLeft(UIEdgeInsets insets, CGFloat left) {
  443. insets.left = flat(left);
  444. return insets;
  445. }
  446. CG_INLINE UIEdgeInsets
  447. UIEdgeInsetsSetBottom(UIEdgeInsets insets, CGFloat bottom) {
  448. insets.bottom = flat(bottom);
  449. return insets;
  450. }
  451. CG_INLINE UIEdgeInsets
  452. UIEdgeInsetsSetRight(UIEdgeInsets insets, CGFloat right) {
  453. insets.right = flat(right);
  454. return insets;
  455. }
  456. CG_INLINE UIEdgeInsets
  457. UIEdgeInsetsToFixed(UIEdgeInsets insets, NSUInteger precision) {
  458. UIEdgeInsets result = UIEdgeInsetsMake(CGFloatToFixed(insets.top, precision), CGFloatToFixed(insets.left, precision), CGFloatToFixed(insets.bottom, precision), CGFloatToFixed(insets.right, precision));
  459. return result;
  460. }
  461. CG_INLINE UIEdgeInsets
  462. UIEdgeInsetsRemoveFloatMin(UIEdgeInsets insets) {
  463. UIEdgeInsets result = UIEdgeInsetsMake(removeFloatMin(insets.top), removeFloatMin(insets.left), removeFloatMin(insets.bottom), removeFloatMin(insets.right));
  464. return result;
  465. }
  466. #pragma mark - CGSize
  467. /// 判断一个 CGSize 是否存在 NaN
  468. CG_INLINE BOOL
  469. CGSizeIsNaN(CGSize size) {
  470. return isnan(size.width) || isnan(size.height);
  471. }
  472. /// 判断一个 CGSize 是否存在 infinite
  473. CG_INLINE BOOL
  474. CGSizeIsInf(CGSize size) {
  475. return isinf(size.width) || isinf(size.height);
  476. }
  477. /// 判断一个 CGSize 是否为空(宽或高为0)
  478. CG_INLINE BOOL
  479. CGSizeIsEmpty(CGSize size) {
  480. return size.width <= 0 || size.height <= 0;
  481. }
  482. /// 判断一个 CGSize 是否合法(例如不带无穷大的值、不带非法数字)
  483. CG_INLINE BOOL
  484. CGSizeIsValidated(CGSize size) {
  485. return !CGSizeIsEmpty(size) && !CGSizeIsInf(size) && !CGSizeIsNaN(size);
  486. }
  487. /// 将一个 CGSize 像素对齐
  488. CG_INLINE CGSize
  489. CGSizeFlatted(CGSize size) {
  490. return CGSizeMake(flat(size.width), flat(size.height));
  491. }
  492. /// 将一个 CGSize 以 pt 为单位向上取整
  493. CG_INLINE CGSize
  494. CGSizeCeil(CGSize size) {
  495. return CGSizeMake(ceil(size.width), ceil(size.height));
  496. }
  497. /// 将一个 CGSize 以 pt 为单位向下取整
  498. CG_INLINE CGSize
  499. CGSizeFloor(CGSize size) {
  500. return CGSizeMake(floor(size.width), floor(size.height));
  501. }
  502. CG_INLINE CGSize
  503. CGSizeToFixed(CGSize size, NSUInteger precision) {
  504. CGSize result = CGSizeMake(CGFloatToFixed(size.width, precision), CGFloatToFixed(size.height, precision));
  505. return result;
  506. }
  507. CG_INLINE CGSize
  508. CGSizeRemoveFloatMin(CGSize size) {
  509. CGSize result = CGSizeMake(removeFloatMin(size.width), removeFloatMin(size.height));
  510. return result;
  511. }
  512. #pragma mark - CGRect
  513. /// 判断一个 CGRect 是否存在 NaN
  514. CG_INLINE BOOL
  515. CGRectIsNaN(CGRect rect) {
  516. return isnan(rect.origin.x) || isnan(rect.origin.y) || isnan(rect.size.width) || isnan(rect.size.height);
  517. }
  518. /// 系统提供的 CGRectIsInfinite 接口只能判断 CGRectInfinite 的情况,而该接口可以用于判断 INFINITY 的值
  519. CG_INLINE BOOL
  520. CGRectIsInf(CGRect rect) {
  521. return isinf(rect.origin.x) || isinf(rect.origin.y) || isinf(rect.size.width) || isinf(rect.size.height);
  522. }
  523. /// 判断一个 CGRect 是否合法(例如不带无穷大的值、不带非法数字)
  524. CG_INLINE BOOL
  525. CGRectIsValidated(CGRect rect) {
  526. return !CGRectIsNull(rect) && !CGRectIsInfinite(rect) && !CGRectIsNaN(rect) && !CGRectIsInf(rect);
  527. }
  528. /// 检测某个 CGRect 如果存在数值为 NaN 的则将其转换为 0,避免布局中出现 crash
  529. CG_INLINE CGRect
  530. CGRectSafeValue(CGRect rect) {
  531. return CGRectMake(CGFloatSafeValue(CGRectGetMinX(rect)), CGFloatSafeValue(CGRectGetMinY(rect)), CGFloatSafeValue(CGRectGetWidth(rect)), CGFloatSafeValue(CGRectGetHeight(rect)));
  532. }
  533. /// 创建一个像素对齐的CGRect
  534. CG_INLINE CGRect
  535. CGRectFlatMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height) {
  536. return CGRectMake(flat(x), flat(y), flat(width), flat(height));
  537. }
  538. /// 对CGRect的x/y、width/height都调用一次flat,以保证像素对齐
  539. CG_INLINE CGRect
  540. CGRectFlatted(CGRect rect) {
  541. return CGRectMake(flat(rect.origin.x), flat(rect.origin.y), flat(rect.size.width), flat(rect.size.height));
  542. }
  543. /// 计算目标点 targetPoint 围绕坐标点 coordinatePoint 通过 transform 之后此点的坐标
  544. CG_INLINE CGPoint
  545. CGPointApplyAffineTransformWithCoordinatePoint(CGPoint coordinatePoint, CGPoint targetPoint, CGAffineTransform t) {
  546. CGPoint p;
  547. p.x = (targetPoint.x - coordinatePoint.x) * t.a + (targetPoint.y - coordinatePoint.y) * t.c + coordinatePoint.x;
  548. p.y = (targetPoint.x - coordinatePoint.x) * t.b + (targetPoint.y - coordinatePoint.y) * t.d + coordinatePoint.y;
  549. p.x += t.tx;
  550. p.y += t.ty;
  551. return p;
  552. }
  553. /// 系统的 CGRectApplyAffineTransform 只会按照 anchorPoint 为 (0, 0) 的方式去计算,但通常情况下我们面对的是 UIView/CALayer,它们默认的 anchorPoint 为 (.5, .5),所以增加这个函数,在计算 transform 时可以考虑上 anchorPoint 的影响
  554. CG_INLINE CGRect
  555. CGRectApplyAffineTransformWithAnchorPoint(CGRect rect, CGAffineTransform t, CGPoint anchorPoint) {
  556. CGFloat width = CGRectGetWidth(rect);
  557. CGFloat height = CGRectGetHeight(rect);
  558. CGPoint oPoint = CGPointMake(rect.origin.x + width * anchorPoint.x, rect.origin.y + height * anchorPoint.y);
  559. CGPoint top_left = CGPointApplyAffineTransformWithCoordinatePoint(oPoint, CGPointMake(rect.origin.x, rect.origin.y), t);
  560. CGPoint bottom_left = CGPointApplyAffineTransformWithCoordinatePoint(oPoint, CGPointMake(rect.origin.x, rect.origin.y + height), t);
  561. CGPoint top_right = CGPointApplyAffineTransformWithCoordinatePoint(oPoint, CGPointMake(rect.origin.x + width, rect.origin.y), t);
  562. CGPoint bottom_right = CGPointApplyAffineTransformWithCoordinatePoint(oPoint, CGPointMake(rect.origin.x + width, rect.origin.y + height), t);
  563. CGFloat minX = MIN(MIN(MIN(top_left.x, bottom_left.x), top_right.x), bottom_right.x);
  564. CGFloat maxX = MAX(MAX(MAX(top_left.x, bottom_left.x), top_right.x), bottom_right.x);
  565. CGFloat minY = MIN(MIN(MIN(top_left.y, bottom_left.y), top_right.y), bottom_right.y);
  566. CGFloat maxY = MAX(MAX(MAX(top_left.y, bottom_left.y), top_right.y), bottom_right.y);
  567. CGFloat newWidth = maxX - minX;
  568. CGFloat newHeight = maxY - minY;
  569. CGRect result = CGRectMake(minX, minY, newWidth, newHeight);
  570. return result;
  571. }
  572. /// 为一个CGRect叠加scale计算
  573. CG_INLINE CGRect
  574. CGRectApplyScale(CGRect rect, CGFloat scale) {
  575. return CGRectFlatted(CGRectMake(CGRectGetMinX(rect) * scale, CGRectGetMinY(rect) * scale, CGRectGetWidth(rect) * scale, CGRectGetHeight(rect) * scale));
  576. }
  577. /// 计算view的水平居中,传入父view和子view的frame,返回子view在水平居中时的x值
  578. CG_INLINE CGFloat
  579. CGRectGetMinXHorizontallyCenterInParentRect(CGRect parentRect, CGRect childRect) {
  580. return flat((CGRectGetWidth(parentRect) - CGRectGetWidth(childRect)) / 2.0);
  581. }
  582. /// 计算view的垂直居中,传入父view和子view的frame,返回子view在垂直居中时的y值
  583. CG_INLINE CGFloat
  584. CGRectGetMinYVerticallyCenterInParentRect(CGRect parentRect, CGRect childRect) {
  585. return flat((CGRectGetHeight(parentRect) - CGRectGetHeight(childRect)) / 2.0);
  586. }
  587. /// 返回值:同一个坐标系内,想要layoutingRect和已布局完成的referenceRect保持垂直居中时,layoutingRect的originY
  588. CG_INLINE CGFloat
  589. CGRectGetMinYVerticallyCenter(CGRect referenceRect, CGRect layoutingRect) {
  590. return CGRectGetMinY(referenceRect) + CGRectGetMinYVerticallyCenterInParentRect(referenceRect, layoutingRect);
  591. }
  592. /// 返回值:同一个坐标系内,想要layoutingRect和已布局完成的referenceRect保持水平居中时,layoutingRect的originX
  593. CG_INLINE CGFloat
  594. CGRectGetMinXHorizontallyCenter(CGRect referenceRect, CGRect layoutingRect) {
  595. return CGRectGetMinX(referenceRect) + CGRectGetMinXHorizontallyCenterInParentRect(referenceRect, layoutingRect);
  596. }
  597. /// 为给定的rect往内部缩小insets的大小(系统那个方法的命名太难联想了,所以定义了一个新函数)
  598. CG_INLINE CGRect
  599. CGRectInsetEdges(CGRect rect, UIEdgeInsets insets) {
  600. return UIEdgeInsetsInsetRect(rect, insets);
  601. }
  602. /// 传入size,返回一个x/y为0的CGRect
  603. CG_INLINE CGRect
  604. CGRectMakeWithSize(CGSize size) {
  605. return CGRectMake(0, 0, size.width, size.height);
  606. }
  607. CG_INLINE CGRect
  608. CGRectFloatTop(CGRect rect, CGFloat top) {
  609. rect.origin.y = top;
  610. return rect;
  611. }
  612. CG_INLINE CGRect
  613. CGRectFloatBottom(CGRect rect, CGFloat bottom) {
  614. rect.origin.y = bottom - CGRectGetHeight(rect);
  615. return rect;
  616. }
  617. CG_INLINE CGRect
  618. CGRectFloatRight(CGRect rect, CGFloat right) {
  619. rect.origin.x = right - CGRectGetWidth(rect);
  620. return rect;
  621. }
  622. CG_INLINE CGRect
  623. CGRectFloatLeft(CGRect rect, CGFloat left) {
  624. rect.origin.x = left;
  625. return rect;
  626. }
  627. /// 保持rect的左边缘不变,改变其宽度,使右边缘靠在right上
  628. CG_INLINE CGRect
  629. CGRectLimitRight(CGRect rect, CGFloat rightLimit) {
  630. rect.size.width = rightLimit - rect.origin.x;
  631. return rect;
  632. }
  633. /// 保持rect右边缘不变,改变其宽度和origin.x,使其左边缘靠在left上。只适合那种右边缘不动的view
  634. /// 先改变origin.x,让其靠在offset上
  635. /// 再改变size.width,减少同样的宽度,以抵消改变origin.x带来的view移动,从而保证view的右边缘是不动的
  636. CG_INLINE CGRect
  637. CGRectLimitLeft(CGRect rect, CGFloat leftLimit) {
  638. CGFloat subOffset = leftLimit - rect.origin.x;
  639. rect.origin.x = leftLimit;
  640. rect.size.width = rect.size.width - subOffset;
  641. return rect;
  642. }
  643. /// 限制rect的宽度,超过最大宽度则截断,否则保持rect的宽度不变
  644. CG_INLINE CGRect
  645. CGRectLimitMaxWidth(CGRect rect, CGFloat maxWidth) {
  646. CGFloat width = CGRectGetWidth(rect);
  647. rect.size.width = width > maxWidth ? maxWidth : width;
  648. return rect;
  649. }
  650. CG_INLINE CGRect
  651. CGRectSetX(CGRect rect, CGFloat x) {
  652. rect.origin.x = flat(x);
  653. return rect;
  654. }
  655. CG_INLINE CGRect
  656. CGRectSetY(CGRect rect, CGFloat y) {
  657. rect.origin.y = flat(y);
  658. return rect;
  659. }
  660. CG_INLINE CGRect
  661. CGRectSetXY(CGRect rect, CGFloat x, CGFloat y) {
  662. rect.origin.x = flat(x);
  663. rect.origin.y = flat(y);
  664. return rect;
  665. }
  666. CG_INLINE CGRect
  667. CGRectSetWidth(CGRect rect, CGFloat width) {
  668. if (width < 0) {
  669. return rect;
  670. }
  671. rect.size.width = flat(width);
  672. return rect;
  673. }
  674. CG_INLINE CGRect
  675. CGRectSetHeight(CGRect rect, CGFloat height) {
  676. if (height < 0) {
  677. return rect;
  678. }
  679. rect.size.height = flat(height);
  680. return rect;
  681. }
  682. CG_INLINE CGRect
  683. CGRectSetSize(CGRect rect, CGSize size) {
  684. rect.size = CGSizeFlatted(size);
  685. return rect;
  686. }
  687. CG_INLINE CGRect
  688. CGRectToFixed(CGRect rect, NSUInteger precision) {
  689. CGRect result = CGRectMake(CGFloatToFixed(CGRectGetMinX(rect), precision),
  690. CGFloatToFixed(CGRectGetMinY(rect), precision),
  691. CGFloatToFixed(CGRectGetWidth(rect), precision),
  692. CGFloatToFixed(CGRectGetHeight(rect), precision));
  693. return result;
  694. }
  695. CG_INLINE CGRect
  696. CGRectRemoveFloatMin(CGRect rect) {
  697. CGRect result = CGRectMake(removeFloatMin(CGRectGetMinX(rect)),
  698. removeFloatMin(CGRectGetMinY(rect)),
  699. removeFloatMin(CGRectGetWidth(rect)),
  700. removeFloatMin(CGRectGetHeight(rect)));
  701. return result;
  702. }
  703. /// outerRange 是否包含了 innerRange
  704. CG_INLINE BOOL
  705. NSContainingRanges(NSRange outerRange, NSRange innerRange) {
  706. if (innerRange.location >= outerRange.location && outerRange.location + outerRange.length >= innerRange.location + innerRange.length) {
  707. return YES;
  708. }
  709. return NO;
  710. }
  711. #endif /* QMUICommonDefines_h */