BRPickerStyle.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. //
  2. // BRPickerStyle.m
  3. // BRPickerViewDemo
  4. //
  5. // Created by renbo on 2019/10/2.
  6. // Copyright © 2019 irenb. All dones reserved.
  7. //
  8. // 最新代码下载地址:https://github.com/91renb/BRPickerView
  9. #import "BRPickerStyle.h"
  10. #import "NSBundle+BRPickerView.h"
  11. // 标题颜色
  12. #define kBRDefaultTextColor BR_RGB_HEX(0x333333, 1.0f)
  13. @implementation BRPickerStyle
  14. - (instancetype)init {
  15. if (self = [super init]) {
  16. self.clearPickerNewStyle = YES;
  17. }
  18. return self;
  19. }
  20. /// 设置默认样式
  21. - (UIColor *)maskColor {
  22. if (!_maskColor) {
  23. _maskColor = [self br_colorWithLightColor:BR_RGB_HEX(0x000000, 0.3f) darkColor:BR_RGB_HEX(0x666666, 0.3f)];
  24. }
  25. return _maskColor;
  26. }
  27. - (UIColor *)shadowLineColor {
  28. if (!_shadowLineColor) {
  29. if (@available(iOS 13.0, *)) {
  30. // 边框线颜色,有透明度
  31. _shadowLineColor = [UIColor separatorColor];
  32. } else {
  33. _shadowLineColor = BR_RGB_HEX(0xc6c6c8, 1.0f);
  34. }
  35. }
  36. return _shadowLineColor;
  37. }
  38. - (CGFloat)shadowLineHeight {
  39. if (_shadowLineHeight <= 0 || _shadowLineHeight > 5.0f) {
  40. _shadowLineHeight = 0.5f;
  41. }
  42. return _shadowLineHeight;
  43. }
  44. - (CGFloat)paddingBottom {
  45. if (_paddingBottom <= 0) {
  46. _paddingBottom = BR_BOTTOM_MARGIN;
  47. }
  48. return _paddingBottom;
  49. }
  50. - (UIColor *)titleBarColor {
  51. if (!_titleBarColor) {
  52. if (@available(iOS 13.0, *)) {
  53. // #ffffff(正常)、#1c1c1e(深色)
  54. _titleBarColor = [UIColor secondarySystemGroupedBackgroundColor];
  55. } else {
  56. _titleBarColor = [UIColor whiteColor];
  57. }
  58. }
  59. return _titleBarColor;
  60. }
  61. - (CGFloat)titleBarHeight {
  62. if (!self.hiddenTitleBarView) {
  63. if (_titleBarHeight < 44.0f && (!self.hiddenCancelBtn || !self.hiddenDoneBtn || !self.hiddenTitleLabel)) {
  64. _titleBarHeight = 44.0f;
  65. }
  66. } else {
  67. _titleBarHeight = 0;
  68. }
  69. return _titleBarHeight;
  70. }
  71. - (UIColor *)titleLineColor {
  72. if (!_titleLineColor) {
  73. _titleLineColor = [self br_colorWithLightColor:BR_RGB_HEX(0xededee, 1.0f) darkColor:BR_RGB_HEX(0x18181c, 1.0f)];
  74. }
  75. return _titleLineColor;
  76. }
  77. - (UIColor *)cancelColor {
  78. if (!_cancelColor) {
  79. _cancelColor = [UIColor clearColor];
  80. }
  81. return _cancelColor;
  82. }
  83. - (UIColor *)cancelTextColor {
  84. if (!_cancelTextColor) {
  85. if (@available(iOS 13.0, *)) {
  86. _cancelTextColor = [UIColor labelColor];
  87. } else {
  88. _cancelTextColor = kBRDefaultTextColor;
  89. }
  90. }
  91. return _cancelTextColor;
  92. }
  93. - (UIFont *)cancelTextFont {
  94. if (!_cancelTextFont) {
  95. _cancelTextFont = [UIFont systemFontOfSize:16.0f];
  96. }
  97. return _cancelTextFont;
  98. }
  99. - (NSString *)cancelBtnTitle {
  100. if (!_cancelBtnTitle && !_cancelBtnImage) {
  101. _cancelBtnTitle = [NSBundle br_localizedStringForKey:@"取消" language:self.language];
  102. }
  103. return _cancelBtnTitle;
  104. }
  105. - (CGRect)cancelBtnFrame {
  106. if (CGRectEqualToRect(_cancelBtnFrame, CGRectZero) || _cancelBtnFrame.size.height == 0) {
  107. _cancelBtnFrame = CGRectMake(5, 8, 60, 28);
  108. }
  109. return _cancelBtnFrame;
  110. }
  111. - (UIColor *)titleLabelColor {
  112. if (!_titleLabelColor) {
  113. _titleLabelColor = [UIColor clearColor];
  114. }
  115. return _titleLabelColor;
  116. }
  117. - (UIColor *)titleTextColor {
  118. if (!_titleTextColor) {
  119. if (@available(iOS 13.0, *)) {
  120. _titleTextColor = [UIColor secondaryLabelColor];
  121. } else {
  122. _titleTextColor = BR_RGB_HEX(0x999999, 1.0f);
  123. }
  124. }
  125. return _titleTextColor;
  126. }
  127. - (UIFont *)titleTextFont {
  128. if (!_titleTextFont) {
  129. _titleTextFont = [UIFont systemFontOfSize:15.0f];
  130. }
  131. return _titleTextFont;
  132. }
  133. - (CGRect)titleLabelFrame {
  134. if (CGRectEqualToRect(_titleLabelFrame, CGRectZero) || _titleLabelFrame.size.height == 0) {
  135. _titleLabelFrame = CGRectMake(5 + 60 + 2, 0, BRGetKeyWindow().bounds.size.width - 2 * (5 + 60 + 2), 44);
  136. }
  137. return _titleLabelFrame;
  138. }
  139. - (UIColor *)doneColor {
  140. if (!_doneColor) {
  141. _doneColor = [UIColor clearColor];
  142. }
  143. return _doneColor;
  144. }
  145. - (UIColor *)doneTextColor {
  146. if (!_doneTextColor) {
  147. if (@available(iOS 13.0, *)) {
  148. _doneTextColor = [UIColor labelColor];
  149. } else {
  150. _doneTextColor = kBRDefaultTextColor;
  151. }
  152. }
  153. return _doneTextColor;
  154. }
  155. - (UIFont *)doneTextFont {
  156. if (!_doneTextFont) {
  157. _doneTextFont = [UIFont systemFontOfSize:16.0f];
  158. }
  159. return _doneTextFont;
  160. }
  161. - (NSString *)doneBtnTitle {
  162. if (!_doneBtnTitle && !_doneBtnImage) {
  163. _doneBtnTitle = [NSBundle br_localizedStringForKey:@"确定" language:self.language];
  164. }
  165. return _doneBtnTitle;
  166. }
  167. - (CGRect)doneBtnFrame {
  168. if (CGRectEqualToRect(_doneBtnFrame, CGRectZero) || _doneBtnFrame.size.height == 0) {
  169. _doneBtnFrame = CGRectMake(BRGetKeyWindow().bounds.size.width - 60 - 5, 8, 60, 28);
  170. }
  171. return _doneBtnFrame;
  172. }
  173. - (UIColor *)pickerColor {
  174. if (!_pickerColor) {
  175. if (@available(iOS 13.0, *)) {
  176. // #ffffff(正常)、#1c1c1e(深色)
  177. _pickerColor = [UIColor secondarySystemGroupedBackgroundColor];
  178. } else {
  179. _pickerColor = [UIColor whiteColor];
  180. }
  181. }
  182. return _pickerColor;
  183. }
  184. - (UIColor *)separatorColor {
  185. if (!_separatorColor) {
  186. if (@available(iOS 13.0, *)) {
  187. // 分割线颜色,无透明度
  188. _separatorColor = [UIColor opaqueSeparatorColor];
  189. } else {
  190. _separatorColor = BR_RGB_HEX(0xc6c6c8, 1.0f);
  191. }
  192. }
  193. return _separatorColor;
  194. }
  195. - (UIColor *)pickerTextColor {
  196. if (!_pickerTextColor) {
  197. if (@available(iOS 13.0, *)) {
  198. _pickerTextColor = [UIColor labelColor];
  199. } else {
  200. _pickerTextColor = kBRDefaultTextColor;
  201. }
  202. }
  203. return _pickerTextColor;
  204. }
  205. - (UIFont *)pickerTextFont {
  206. if (!_pickerTextFont) {
  207. _pickerTextFont = [UIFont systemFontOfSize:18.0f];
  208. }
  209. return _pickerTextFont;
  210. }
  211. - (CGFloat)pickerHeight {
  212. if (_pickerHeight < 40) {
  213. _pickerHeight = 216.0f;
  214. }
  215. return _pickerHeight;
  216. }
  217. - (CGFloat)rowHeight {
  218. if (_rowHeight < 20) {
  219. _rowHeight = 35.0f;
  220. }
  221. return _rowHeight;
  222. }
  223. - (NSString *)language {
  224. if (!_language) {
  225. // 跟随系统的首选语言自动改变
  226. // zh-Hans-CN(简体中文)、zh-Hant-CN(繁体中文)、en-CN(美式英语)、en-GB(英式英语)
  227. // 其中`CN`是iOS9以后新增的地区代码,如:CN 代表中国,US 代表美国
  228. _language = [NSLocale preferredLanguages].firstObject;
  229. }
  230. return _language;
  231. }
  232. - (UIColor *)dateUnitTextColor {
  233. if (!_dateUnitTextColor) {
  234. if (@available(iOS 13.0, *)) {
  235. _dateUnitTextColor = [UIColor labelColor];
  236. } else {
  237. _dateUnitTextColor = kBRDefaultTextColor;
  238. }
  239. }
  240. return _dateUnitTextColor;
  241. }
  242. - (UIFont *)dateUnitTextFont {
  243. if (!_dateUnitTextFont) {
  244. _dateUnitTextFont = [UIFont systemFontOfSize:18.0f];
  245. }
  246. return _dateUnitTextFont;
  247. }
  248. #pragma mark - 创建自定义动态颜色(适配深色模式)
  249. - (UIColor *)br_colorWithLightColor:(UIColor *)lightColor darkColor:(UIColor *)darkColor {
  250. if (@available(iOS 13.0, *)) {
  251. UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
  252. if ([traitCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
  253. return lightColor;
  254. } else {
  255. return darkColor;
  256. }
  257. }];
  258. return dyColor;
  259. } else {
  260. return lightColor;
  261. }
  262. }
  263. #pragma mark - 弹框模板样式1 - 取消/确定按钮圆角样式
  264. + (instancetype)pickerStyleWithThemeColor:(UIColor *)themeColor {
  265. BRPickerStyle *customStyle = [[self alloc]init];
  266. if (themeColor) {
  267. customStyle.cancelTextColor = themeColor;
  268. customStyle.cancelBorderStyle = BRBorderStyleSolid;
  269. customStyle.doneColor = themeColor;
  270. customStyle.doneTextColor = [UIColor whiteColor];
  271. customStyle.doneBorderStyle = BRBorderStyleFill;
  272. }
  273. return customStyle;
  274. }
  275. #pragma mark - 弹框模板样式2 - 顶部圆角样式 + 完成按钮
  276. + (instancetype)pickerStyleWithDoneTextColor:(UIColor *)doneTextColor {
  277. BRPickerStyle *customStyle = [[self alloc]init];
  278. if (doneTextColor) {
  279. customStyle.topCornerRadius = 16.0f;
  280. customStyle.hiddenCancelBtn = YES;
  281. customStyle.hiddenTitleLine = YES;
  282. customStyle.titleLabelFrame = CGRectMake(20, 4, 100, 40);
  283. customStyle.doneTextColor = doneTextColor;
  284. customStyle.doneTextFont = [UIFont boldSystemFontOfSize:18.0f];
  285. customStyle.doneBtnFrame = CGRectMake(BRGetKeyWindow().bounds.size.width - 60, 4, 60, 40);
  286. customStyle.doneBtnTitle = [NSBundle br_localizedStringForKey:@"完成" language:customStyle.language];
  287. customStyle.selectRowTextColor = doneTextColor;
  288. customStyle.selectRowTextFont = [UIFont boldSystemFontOfSize:20.0f];
  289. }
  290. return customStyle;
  291. }
  292. #pragma mark - 弹框模板样式3 - 顶部圆角样式 + 图标按钮
  293. + (instancetype)pickerStyleWithDoneBtnImage:(UIImage *)doneBtnImage {
  294. BRPickerStyle *customStyle = [[self alloc]init];
  295. if (doneBtnImage) {
  296. customStyle.topCornerRadius = 16.0f;
  297. customStyle.hiddenTitleLine = YES;
  298. customStyle.hiddenCancelBtn = YES;
  299. customStyle.titleLabelFrame = CGRectMake(20, 4, 100, 40);
  300. customStyle.doneBtnImage = doneBtnImage;
  301. customStyle.doneBtnFrame = CGRectMake(BRGetKeyWindow().bounds.size.width - 44, 4, 40, 40);
  302. }
  303. return customStyle;
  304. }
  305. #pragma mark - 设置选择器中间选中行的样式
  306. - (void)setupPickerSelectRowStyle:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
  307. // 1.设置分割线的颜色
  308. NSString *systemVersion = [UIDevice currentDevice].systemVersion;
  309. if (systemVersion.doubleValue < 14.0) {
  310. for (UIView *subView in pickerView.subviews) {
  311. if (subView && [subView isKindOfClass:[UIView class]] && subView.frame.size.height <= 1) {
  312. subView.backgroundColor = self.separatorColor;
  313. // 设置分割线高度
  314. if (self.separatorHeight > 0) {
  315. CGRect rect = subView.frame;
  316. rect.size.height = self.separatorHeight;
  317. subView.frame = rect;
  318. }
  319. }
  320. }
  321. }
  322. // 2.设置选择器中间选中行的背景颜色
  323. UIView *contentView = nil;
  324. NSArray *subviews = pickerView.subviews;
  325. if (subviews.count > 0) {
  326. id firstView = subviews.firstObject;
  327. if (firstView && [firstView isKindOfClass:[UIView class]]) {
  328. contentView = (UIView *)firstView;
  329. }
  330. }
  331. if (self.selectRowColor) {
  332. UIView *columnView = nil;
  333. if (contentView) {
  334. id obj = [contentView valueForKey:@"subviewCache"];
  335. if (obj && [obj isKindOfClass:[NSArray class]]) {
  336. NSArray *columnViews = (NSArray *)obj;
  337. if (columnViews.count > 0) {
  338. id columnObj = columnViews.firstObject;
  339. if (columnObj && [columnObj isKindOfClass:[UIView class]]) {
  340. columnView = (UIView *)columnObj;
  341. }
  342. }
  343. }
  344. }
  345. if (columnView) {
  346. id obj = [columnView valueForKey:@"middleContainerView"];
  347. if (obj && [obj isKindOfClass:[UIView class]]) {
  348. UIView *selectRowView = (UIView *)obj;
  349. // 中间选中行的背景颜色
  350. selectRowView.backgroundColor = self.selectRowColor;
  351. }
  352. }
  353. }
  354. if (contentView && self.clearPickerNewStyle) {
  355. if (systemVersion.doubleValue >= 14.0) {
  356. // ①隐藏中间选择行的背景样式
  357. id lastView = subviews.lastObject;
  358. if (lastView && [lastView isKindOfClass:[UIView class]]) {
  359. UIView *rectBgView = (UIView *)lastView;
  360. rectBgView.hidden = YES;
  361. }
  362. // ②清除iOS14上选择器默认的内边距
  363. if (systemVersion.doubleValue < 15.0f) {
  364. [self setPickerAllSubViewsStyle:contentView];
  365. }
  366. }
  367. }
  368. // 3.设置选择器中间选中行的字体颜色/字体大小
  369. if (self.selectRowTextColor || self.selectRowTextFont) {
  370. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  371. // 当前选中的 label
  372. UILabel *selectLabel = (UILabel *)[pickerView viewForRow:row forComponent:component];
  373. if (selectLabel) {
  374. if (self.selectRowTextColor) {
  375. selectLabel.textColor = self.selectRowTextColor;
  376. }
  377. if (self.selectRowTextFont) {
  378. selectLabel.font = self.selectRowTextFont;
  379. }
  380. }
  381. });
  382. }
  383. }
  384. // 遍历子视图,重新设置 frame(清空在 iOS14 上 UIPickerView 出现的内边距)
  385. - (void)setPickerAllSubViewsStyle:(UIView *)view {
  386. NSArray *subViews = view.subviews;
  387. if (subViews.count == 0 || [view isKindOfClass:[UILabel class]]) return;
  388. for (UIView *subView in subViews) {
  389. NSString *className = NSStringFromClass([subView class]);
  390. if ([className isEqualToString:@"UIPickerColumnView"]) {
  391. CGRect rect = subView.frame;
  392. rect.origin.x = 0;
  393. rect.size.width = view.bounds.size.width;
  394. subView.frame = rect;
  395. }
  396. NSString *superClassName = NSStringFromClass([view class]);
  397. if ([superClassName isEqualToString:@"UIPickerColumnView"]) {
  398. CGRect rect = subView.frame;
  399. rect.size.width = view.bounds.size.width;
  400. subView.frame = rect;
  401. }
  402. if ([subView isKindOfClass:[UILabel class]]) {
  403. CGRect rect = subView.frame;
  404. rect.origin.x = 10;
  405. subView.frame = rect;
  406. }
  407. [self setPickerAllSubViewsStyle:subView];
  408. }
  409. }
  410. #pragma mark - 添加选择器中间行上下两条分割线(iOS14之后系统默认去掉,需要手动添加)
  411. - (void)addSeparatorLineView:(UIView *)pickerView {
  412. if ([UIDevice currentDevice].systemVersion.doubleValue >= 14.0) {
  413. UIView *topLineView = [[UIView alloc]initWithFrame:CGRectMake(0, pickerView.bounds.size.height / 2 - self.rowHeight / 2, pickerView.bounds.size.width, 0.5f)];
  414. topLineView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
  415. topLineView.backgroundColor = self.separatorColor;
  416. // 设置分割线高度
  417. if (self.separatorHeight > 0) {
  418. CGRect topRect = topLineView.frame;
  419. topRect.size.height = self.separatorHeight;
  420. topLineView.frame = topRect;
  421. }
  422. [pickerView addSubview:topLineView];
  423. UIView *bottomLineView = [[UIView alloc]initWithFrame:CGRectMake(0, pickerView.bounds.size.height / 2 + self.rowHeight / 2, pickerView.bounds.size.width, 0.5f)];
  424. bottomLineView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
  425. bottomLineView.backgroundColor = self.separatorColor;
  426. // 设置分割线高度
  427. if (self.separatorHeight > 0) {
  428. CGRect bottomRect = bottomLineView.frame;
  429. bottomRect.size.height = self.separatorHeight;
  430. bottomLineView.frame = bottomRect;
  431. }
  432. [pickerView addSubview:bottomLineView];
  433. }
  434. }
  435. @end