-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathQMUIHelper.h
303 lines (228 loc) · 13.1 KB
/
QMUIHelper.h
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/**
* Tencent is pleased to support the open source community by making QMUI_iOS available.
* Copyright (C) 2016-2021 THL A29 Limited, a Tencent company. All rights reserved.
* 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
* http://opensource.org/licenses/MIT
* 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.
*/
//
// QMUIHelper.h
// qmui
//
// Created by QMUI Team on 14/10/25.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "QMUICommonDefines.h"
NS_ASSUME_NONNULL_BEGIN
@interface QMUIHelper : NSObject
+ (instancetype)sharedInstance;
/**
用一个 identifier 标记某一段 block,使其对应该 identifier 只会被运行一次
@param block 要执行的一段逻辑
@param identifier 唯一的标记,建议在 identifier 里添加当前这段业务的特有名称,例如用于 swizzle 的可以加“swizzled”前缀,以避免与其他业务共用同一个 identifier 引发 bug
*/
+ (BOOL)executeBlock:(void (NS_NOESCAPE ^)(void))block oncePerIdentifier:(NSString *)identifier;
/**
将 UIViewContentMode 转为对应的 CALayerContentsGravity
*/
+ (CALayerContentsGravity)layerContentsGravityWithContentMode:(UIViewContentMode)contentMode;
@end
@interface QMUIHelper (Bundle)
/// 获取 QMUIKit.framework Images.xcassets 内的图片资源
/// @param name 图片名
+ (nullable UIImage *)imageWithName:(NSString *)name;
@end
@interface QMUIHelper (SystemVersion)
+ (NSInteger)numbericOSVersion;
+ (NSComparisonResult)compareSystemVersion:(nonnull NSString *)currentVersion toVersion:(nonnull NSString *)targetVersion;
+ (BOOL)isCurrentSystemAtLeastVersion:(nonnull NSString *)targetVersion;
+ (BOOL)isCurrentSystemLowerThanVersion:(nonnull NSString *)targetVersion;
@end
@interface QMUIHelper (DynamicType)
/// 返回当前 contentSize 的 level,这个值可以在设置里面的“字体大小”查看,辅助功能里面有个“更大字体”可以设置更大的字体,不过这里我们这个接口将更大字体都做了统一,都返回“字体大小”里面最大值。
/// Returns the level of contentSize
/// The value can be set in Settings - Display & Brightness - Text Size as well as in General - Accessibility - Larger Text
/// This method returns the value set by user or the maximum value in Text Size, whichever is smaller
+ (nonnull NSNumber *)preferredContentSizeLevel;
/// 设置当前 cell 的高度,heights 是有七个数值的数组,对于不支持的iOS版本,则选择中间的值返回。
/// Sets height of the cell; Heights consist of 7 numberic values; Returns the middle value on legacy iOS versions.
+ (CGFloat)heightForDynamicTypeCell:(nonnull NSArray *)heights;
@end
@interface QMUIHelper (Keyboard)
/**
* 判断当前 App 里的键盘是否升起,默认为 NO
* Returns the visibility of the keybord. Default value is NO.
*/
+ (BOOL)isKeyboardVisible;
/**
* 记录上一次键盘显示时的高度(基于整个 App 所在的 window 的坐标系),注意使用前用 `isKeyboardVisible` 判断键盘是否显示,因为即便是键盘被隐藏的情况下,调用 `lastKeyboardHeightInApplicationWindowWhenVisible` 也会得到高度值。
*/
+ (CGFloat)lastKeyboardHeightInApplicationWindowWhenVisible;
/**
* 获取当前键盘frame相关
* @warning 注意iOS8以下的系统在横屏时得到的rect,宽度和高度相反了,所以不建议直接通过这个方法获取高度,而是使用<code>keyboardHeightWithNotification:inView:</code>,因为在后者的实现里会将键盘的rect转换坐标系,转换过程就会处理横竖屏旋转问题。
*/
+ (CGRect)keyboardRectWithNotification:(nullable NSNotification *)notification;
/// 获取当前键盘的高度,注意高度可能为0(例如第三方键盘会发出两次notification,其中第一次的高度就为0)
+ (CGFloat)keyboardHeightWithNotification:(nullable NSNotification *)notification;
/**
* 获取当前键盘在屏幕上的可见高度,注意外接键盘(iPad那种)时,[QMUIHelper keyboardRectWithNotification]得到的键盘rect里有一部分是超出屏幕,不可见的,如果直接拿rect的高度来计算就会与意图相悖。
* @param notification 接收到的键盘事件的UINotification对象
* @param view 要得到的键盘高度是相对于哪个View的键盘高度,若为nil,则等同于调用[QMUIHelper keyboardHeightWithNotification:]
* @warning 如果view.window为空(当前View尚不可见),则会使用App默认的UIWindow来做坐标转换,可能会导致一些计算错误
* @return 键盘在view里的可视高度
*/
+ (CGFloat)keyboardHeightWithNotification:(nullable NSNotification *)notification inView:(nullable UIView *)view;
/// 获取键盘显示/隐藏的动画时长,注意返回值可能为0
+ (NSTimeInterval)keyboardAnimationDurationWithNotification:(nullable NSNotification *)notification;
/// 获取键盘显示/隐藏的动画时间函数
+ (UIViewAnimationCurve)keyboardAnimationCurveWithNotification:(nullable NSNotification *)notification;
/// 获取键盘显示/隐藏的动画时间函数
+ (UIViewAnimationOptions)keyboardAnimationOptionsWithNotification:(nullable NSNotification *)notification;
@end
@interface QMUIHelper (AudioSession)
/**
* 听筒和扬声器的切换
*
* @param speaker 是否转为扬声器,NO则听筒
* @param temporary 决定使用kAudioSessionProperty_OverrideAudioRoute还是kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,两者的区别请查看本组的博客文章:http://km.oa.com/group/gyui/articles/show/235957
*/
+ (void)redirectAudioRouteWithSpeaker:(BOOL)speaker temporary:(BOOL)temporary;
/**
* 设置category
*
* @param category 使用iOS7的category,iOS6的会自动适配
*/
+ (void)setAudioSessionCategory:(nullable NSString *)category;
@end
@interface QMUIHelper (UIGraphic)
/// 获取一像素的大小
@property(class, nonatomic, readonly) CGFloat pixelOne;
/// 判断size是否超出范围
+ (void)inspectContextSize:(CGSize)size;
/// context是否合法
+ (BOOL)inspectContextIfInvalidated:(CGContextRef)context;
@end
@interface QMUIHelper (Device)
/// 如 iPhone12,5、iPad6,8
/// @NEW_DEVICE_CHECKER
@property(class, nonatomic, readonly) NSString *deviceModel;
/// 如 iPhone 11 Pro Max、iPad Pro (12.9 inch),如果是模拟器,会在后面带上“ Simulator”字样。
/// @NEW_DEVICE_CHECKER
@property(class, nonatomic, readonly) NSString *deviceName;
@property(class, nonatomic, readonly) BOOL isIPad;
@property(class, nonatomic, readonly) BOOL isIPod;
@property(class, nonatomic, readonly) BOOL isIPhone;
@property(class, nonatomic, readonly) BOOL isSimulator;
@property(class, nonatomic, readonly) BOOL isMac;
/// 带物理凹槽的刘海屏或者使用 Home Indicator 类型的设备
/// @NEW_DEVICE_CHECKER
@property(class, nonatomic, readonly) BOOL isNotchedScreen;
/// 将屏幕分为普通和紧凑两种,这个方法用于判断普通屏幕(也即大屏幕)。
/// @note 注意,这里普通/紧凑的标准是 QMUI 自行制定的,与系统 UITraitCollection.horizontalSizeClass/verticalSizeClass 的值无关。只要是通常意义上的“大屏幕手机”(例如 Plus 系列)都会被视为 Regular Screen。
/// @NEW_DEVICE_CHECKER
@property(class, nonatomic, readonly) BOOL isRegularScreen;
/// iPhone 16 Pro Max
@property(class, nonatomic, readonly) BOOL is69InchScreen;
/// iPhone 14 Pro Max
@property(class, nonatomic, readonly) BOOL is67InchScreenAndiPhone14Later;
/// iPhone 14 Plus / 13 Pro Max / 12 Pro Max
@property(class, nonatomic, readonly) BOOL is67InchScreen;
/// iPhone XS Max / 11 Pro Max
@property(class, nonatomic, readonly) BOOL is65InchScreen;
/// iPhone 16 Pro
@property(class, nonatomic, readonly) BOOL is63InchScreen;
/// iPhone 12 / 12 Pro
@property(class, nonatomic, readonly) BOOL is61InchScreenAndiPhone12Later;
/// iPhone 14 Pro / 15 Pro
@property(class, nonatomic, readonly) BOOL is61InchScreenAndiPhone14ProLater;
/// iPhone XR / 11
@property(class, nonatomic, readonly) BOOL is61InchScreen;
/// iPhone X / XS / 11Pro
@property(class, nonatomic, readonly) BOOL is58InchScreen;
/// iPhone 8 Plus
@property(class, nonatomic, readonly) BOOL is55InchScreen;
/// iPhone 12 mini
@property(class, nonatomic, readonly) BOOL is54InchScreen;
/// iPhone 8
@property(class, nonatomic, readonly) BOOL is47InchScreen;
/// iPhone 5
@property(class, nonatomic, readonly) BOOL is40InchScreen;
/// iPhone 4
@property(class, nonatomic, readonly) BOOL is35InchScreen;
@property(class, nonatomic, readonly) CGSize screenSizeFor69Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor67InchAndiPhone14Later;
@property(class, nonatomic, readonly) CGSize screenSizeFor67Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor65Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor63Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor61InchAndiPhone14ProLater;
@property(class, nonatomic, readonly) CGSize screenSizeFor61InchAndiPhone12Later;
@property(class, nonatomic, readonly) CGSize screenSizeFor61Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor58Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor55Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor54Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor47Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor40Inch;
@property(class, nonatomic, readonly) CGSize screenSizeFor35Inch;
@property(class, nonatomic, readonly) CGFloat preferredLayoutAsSimilarScreenWidthForIPad;
/// 用于获取 isNotchedScreen 设备的 insets,注意对于无 Home 键的新款 iPad 而言,它不一定有物理凹槽,但因为使用了 Home Indicator,所以它的 safeAreaInsets 也是非0。
/// @NEW_DEVICE_CHECKER
@property(class, nonatomic, readonly) UIEdgeInsets safeAreaInsetsForDeviceWithNotch;
/// 判断当前设备是否高性能设备,只会判断一次,以后都直接读取结果,所以没有性能问题
@property(class, nonatomic, readonly) BOOL isHighPerformanceDevice;
/// 系统设置里是否开启了“放大显示-试图-放大”,支持放大模式的 iPhone 设备可在官方文档中查询 https://support.apple.com/zh-cn/guide/iphone/iphd6804774e/ios
/// @NEW_DEVICE_CHECKER
@property(class, nonatomic, readonly) BOOL isZoomedMode;
/// 当前设备是否拥有灵动岛
/// @NEW_DEVICE_CHECKER
@property(class, nonatomic, readonly) BOOL isDynamicIslandDevice;
/**
在 iPad 分屏模式下可获得实际运行区域的窗口大小,如需适配 iPad 分屏,建议用这个方法来代替 [UIScreen mainScreen].bounds.size
@return 应用运行的窗口大小
*/
@property(class, nonatomic, readonly) CGSize applicationSize;
/**
静态的状态栏高度,在状态栏不可见时也会根据机型返回状态栏的固定高度
@NEW_DEVICE_CHECKER
*/
@property(class, nonatomic, readonly) CGFloat statusBarHeightConstant;
/**
静态的导航栏高度,在导航栏不可见时也会根据机型返回导航栏的固定高度
*/
@property(class, nonatomic, readonly) CGFloat navigationBarMaxYConstant;
@end
@interface QMUIHelper (UIApplication)
/**
* 把App的主要window置灰,用于浮层弹出时,请注意要在适当时机调用`resetDimmedApplicationWindow`恢复到正常状态
*/
+ (void)dimmedApplicationWindow;
/**
* 恢复对App的主要window的置灰操作,与`dimmedApplicationWindow`成对调用
*/
+ (void)resetDimmedApplicationWindow;
/**
在非 UIApplicationStateActive 的时机去设置 UIAppearance 可能引发第三方输入法 crash,因此提供这个方法判断当前是否可以更新 UIAppearance。
详情请见 https://github.com/Tencent/QMUI_iOS/issues/1281
*/
@property(class, nonatomic, assign, readonly) BOOL canUpdateAppearance;
@end
@interface QMUIHelper (Animation)
/**
在 animationBlock 里的操作完成之后会调用 completionBlock,常用于一些不提供 completionBlock 的系统动画操作。
@param animationBlock 要进行的带动画的操作
@param completionBlock 操作完成后的回调
@note 注意 UIScrollView 系列的滚动无法使用这个方法。
*/
+ (void)executeAnimationBlock:(nonnull __attribute__((noescape)) void (^)(void))animationBlock completionBlock:(nullable __attribute__((noescape)) void (^)(void))completionBlock;
@end
@interface QMUIHelper (Text)
/**
该方法计算一个 baselineOffset,使得指定字体的文本在指定高度里能达到视觉上的垂直居中(系统默认是底对齐)。
@param height 单行文本占据的高度,通常可传入文本的 lineHeight 或者 UILabel 的 height。
@param font 当前文本的字体。
@return 可使文本垂直居中的 baselineOffset 偏移值,正值往上,负值往下。注意如果某段 NSAttributedString 通过 NSParagraphStyle 指定了行高,则负值的 baselineOffset 对其无效。
*/
+ (CGFloat)baselineOffsetWhenVerticalAlignCenterInHeight:(CGFloat)height withFont:(UIFont *)font;
@end
NS_ASSUME_NONNULL_END