YPTabBar.m 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. //
  2. // YPTabBar.m
  3. // YPTabBarController
  4. //
  5. // Created by 喻平 on 15/8/11.
  6. // Copyright (c) 2015年 YPTabBarController. All rights reserved.
  7. //
  8. #import "YPTabBar.h"
  9. #define BADGE_BG_COLOR_DEFAULT [UIColor colorWithRed:252 / 255.0f green:15 / 255.0f blue:29 / 255.0f alpha:1.0f]
  10. @interface YPTabBar ()<UIScrollViewDelegate>
  11. @property (nonatomic, strong) UIScrollView *scrollView;
  12. @property (nonatomic, strong) UIImageView *itemSelectedBgImageView;
  13. @property (nonatomic, assign) BOOL itemSelectedBgSwitchAnimated; // TabItem选中切换时,是否显示动画
  14. @property (nonatomic, assign) UIEdgeInsets itemSelectedBgInsets;
  15. @property (nonatomic, assign) BOOL itemFitTextWidth;
  16. //@property (nonatomic, assign) BOOL scrollEnabled;
  17. @property (nonatomic, assign) CGFloat itemFitTextWidthSpacing;
  18. @property (nonatomic, assign) CGFloat itemWidth;
  19. @property (nonatomic, assign) CGFloat itemContentHorizontalCenterVerticalOffset;
  20. @property (nonatomic, assign) CGFloat itemContentHorizontalCenterSpacing;
  21. @property (nonatomic, strong) NSMutableArray *separatorLayers;
  22. @property (nonatomic, assign) CGFloat numberBadgeMarginTop;
  23. @property (nonatomic, assign) CGFloat numberBadgeCenterMarginRight;
  24. @property (nonatomic, assign) CGFloat numberBadgeTitleHorizonalSpace;
  25. @property (nonatomic, assign) CGFloat numberBadgeTitleVerticalSpace;
  26. @property (nonatomic, assign) CGFloat dotBadgeMarginTop;
  27. @property (nonatomic, assign) CGFloat dotBadgeCenterMarginRight;
  28. @property (nonatomic, assign) CGFloat dotBadgeSideLength;
  29. @property (nonatomic, strong) UIColor *itemSeparatorColor;
  30. @property (nonatomic, assign) CGFloat itemSeparatorWidth;
  31. @property (nonatomic, assign) CGFloat itemSeparatorMarginTop;
  32. @property (nonatomic, assign) CGFloat itemSeparatorMarginBottom;
  33. @end
  34. @implementation YPTabBar
  35. - (instancetype)initWithFrame:(CGRect)frame {
  36. self = [super initWithFrame:frame];
  37. if (self) {
  38. [self awakeFromNib];
  39. }
  40. return self;
  41. }
  42. - (void)awakeFromNib {
  43. [super awakeFromNib];
  44. self.backgroundColor = [UIColor whiteColor];
  45. _selectedItemIndex = -1;
  46. _itemTitleColor = [UIColor grayColor];
  47. _itemTitleSelectedColor = [UIColor blackColor];
  48. _itemTitleFont = [UIFont systemFontOfSize:20 weight:UIFontWeightMedium];
  49. _itemSelectedBgImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
  50. _itemContentHorizontalCenter = YES;
  51. _itemFontChangeFollowContentScroll = NO;
  52. _itemColorChangeFollowContentScroll = YES;
  53. _itemSelectedBgScrollFollowContent = NO;
  54. _badgeTitleColor = [UIColor whiteColor];
  55. _badgeTitleFont = [UIFont systemFontOfSize:13];
  56. _badgeBackgroundColor = BADGE_BG_COLOR_DEFAULT;
  57. // _numberBadgeFrame = YPTabItemBadgeFrameMake(2, 30, 16);
  58. // _dotBadgeFrame = YPTabItemBadgeFrameMake(5, 25, 10);
  59. _numberBadgeMarginTop = 2;
  60. _numberBadgeCenterMarginRight = 30;
  61. _numberBadgeTitleHorizonalSpace = 8;
  62. _numberBadgeTitleVerticalSpace = 2;
  63. _dotBadgeMarginTop = 5;
  64. _dotBadgeCenterMarginRight = 25;
  65. _dotBadgeSideLength = 10;
  66. self.clipsToBounds = YES;
  67. }
  68. - (void)setFrame:(CGRect)frame {
  69. [super setFrame:frame];
  70. [self updateItemsFrame];
  71. [self updateFrameOfSelectedBgWithIndex:self.selectedItemIndex];
  72. [self updateSeperators];
  73. if (self.scrollView) {
  74. self.scrollView.frame = self.bounds;
  75. }
  76. }
  77. - (void)setItems:(NSArray *)items {
  78. // 将老的item从superview上删除
  79. [_items makeObjectsPerformSelector:@selector(removeFromSuperview)];
  80. _items = [items copy];
  81. // 初始化每一个item
  82. for (YPTabItem *item in self.items) {
  83. item.titleColor = self.itemTitleColor;
  84. item.titleSelectedColor = self.itemTitleSelectedColor;
  85. item.titleFont = self.itemTitleFont;
  86. [item setContentHorizontalCenterWithVerticalOffset:5 spacing:5];
  87. item.badgeTitleFont = self.badgeTitleFont;
  88. item.badgeTitleColor = self.badgeTitleColor;
  89. item.badgeBackgroundColor = self.badgeBackgroundColor;
  90. item.badgeBackgroundImage = self.badgeBackgroundImage;
  91. [item setNumberBadgeMarginTop:self.numberBadgeMarginTop
  92. centerMarginRight:self.numberBadgeCenterMarginRight
  93. titleHorizonalSpace:self.numberBadgeTitleHorizonalSpace
  94. titleVerticalSpace:self.numberBadgeTitleVerticalSpace];
  95. [item setDotBadgeMarginTop:self.dotBadgeMarginTop
  96. centerMarginRight:self.dotBadgeCenterMarginRight
  97. sideLength:self.dotBadgeSideLength];
  98. [item addTarget:self action:@selector(tabItemClicked:) forControlEvents:UIControlEventTouchUpInside];
  99. }
  100. // 更新每个item的位置
  101. [self updateItemsFrame];
  102. // 更新item的大小缩放
  103. [self updateItemsScaleIfNeeded];
  104. }
  105. - (void)setTitles:(NSArray *)titles {
  106. NSMutableArray *items = [NSMutableArray array];
  107. for (NSString *title in titles) {
  108. YPTabItem *item = [[YPTabItem alloc] init];
  109. item.title = title;
  110. [items addObject:item];
  111. }
  112. self.items = items;
  113. }
  114. - (void)setleftAndRightSpacing:(CGFloat)leftAndRightSpacing {
  115. _leftAndRightSpacing = leftAndRightSpacing;
  116. [self updateItemsFrame];
  117. }
  118. - (void)updateItemsFrame {
  119. if (self.items.count == 0) {
  120. return;
  121. }
  122. // 将item从superview上删除
  123. [self.items makeObjectsPerformSelector:@selector(removeFromSuperview)];
  124. // 将item的选中背景从superview上删除
  125. [self.itemSelectedBgImageView removeFromSuperview];
  126. if (self.scrollView) {
  127. // 支持滚动
  128. [self.scrollView addSubview:self.itemSelectedBgImageView];
  129. CGFloat x = self.leftAndRightSpacing;
  130. for (int i = 0; i < self.items.count; i++) {
  131. YPTabItem *item = self.items[i];
  132. CGFloat width = 0;
  133. // item的宽度为一个固定值
  134. if (self.itemWidth > 0) {
  135. width = self.itemWidth;
  136. }
  137. // item的宽度为根据字体大小和spacing进行适配
  138. if (self.itemFitTextWidth) {
  139. CGSize size = [item.title boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)
  140. options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
  141. attributes:@{NSFontAttributeName : self.itemTitleFont}
  142. context:nil].size;
  143. width = ceilf(size.width) + self.itemFitTextWidthSpacing;
  144. }
  145. item.frame = CGRectMake(x, 0, width, self.frame.size.height);
  146. item.index = i;
  147. x += width;
  148. [self.scrollView addSubview:item];
  149. }
  150. self.scrollView.contentSize = CGSizeMake(x + self.leftAndRightSpacing, self.scrollView.frame.size.height);
  151. } else {
  152. // 不支持滚动
  153. [self addSubview:self.itemSelectedBgImageView];
  154. CGFloat x = self.leftAndRightSpacing;
  155. CGFloat itemWidth = (self.frame.size.width - self.leftAndRightSpacing * 2) / self.items.count;
  156. for (int i = 0; i < self.items.count; i++) {
  157. YPTabItem *item = self.items[i];
  158. item.frame = CGRectMake(x, JX_SCREEN_HEIGHT>=812?-8:0, itemWidth, self.frame.size.height);
  159. item.index = i;
  160. x += itemWidth;
  161. [self addSubview:item];
  162. }
  163. }
  164. }
  165. - (void)setSelectedItemIndex:(NSInteger)selectedItemIndex {
  166. if (self.items.count == 0 || selectedItemIndex < 0 || selectedItemIndex >= self.items.count) {
  167. return;
  168. }
  169. if (_selectedItemIndex >= 0) {
  170. YPTabItem *oldSelectedItem = self.items[_selectedItemIndex];
  171. oldSelectedItem.selected = NO;
  172. if (self.itemFontChangeFollowContentScroll) {
  173. // 如果支持字体平滑渐变切换,则设置item的scale
  174. oldSelectedItem.transform = CGAffineTransformMakeScale(self.itemTitleUnselectedFontScale,
  175. self.itemTitleUnselectedFontScale);
  176. } else {
  177. // 如果支持字体平滑渐变切换,则直接设置字体
  178. oldSelectedItem.titleFont = self.itemTitleFont;
  179. }
  180. }
  181. YPTabItem *newSelectedItem = self.items[selectedItemIndex];
  182. newSelectedItem.selected = YES;
  183. if (self.itemFontChangeFollowContentScroll) {
  184. // 如果支持字体平滑渐变切换,则设置item的scale
  185. newSelectedItem.transform = CGAffineTransformMakeScale(1, 1);
  186. } else {
  187. // 如果支持字体平滑渐变切换,则直接设置字体
  188. if (self.itemTitleSelectedFont) {
  189. newSelectedItem.titleFont = self.itemTitleSelectedFont;
  190. }
  191. }
  192. // NSLog(@"itemSelectedBgScrollFollowContent-->%d", self.itemSelectedBgScrollFollowContent);
  193. if (self.itemSelectedBgScrollFollowContent) {
  194. // item的选中背景位置会跟随contentView的拖动进行变化
  195. if (_selectedItemIndex < 0) {
  196. // 仅在首次显示的时候更新它的位置,之后会根据contentView的拖动进行移动
  197. [self updateFrameOfSelectedBgWithIndex:selectedItemIndex];
  198. }
  199. } else {
  200. // item的选中背景位置不会跟随contentView的拖动进行变化
  201. if (self.itemSelectedBgSwitchAnimated && _selectedItemIndex >= 0) {
  202. [UIView animateWithDuration:0.25f animations:^{
  203. [self updateFrameOfSelectedBgWithIndex:selectedItemIndex];
  204. }];
  205. } else {
  206. [self updateFrameOfSelectedBgWithIndex:selectedItemIndex];
  207. }
  208. }
  209. if (self.delegate && [self.delegate respondsToSelector:@selector(yp_tabBar:didSelectedItemAtIndex:)]) {
  210. [self.delegate yp_tabBar:self didSelectedItemAtIndex:selectedItemIndex];
  211. }
  212. _selectedItemIndex = selectedItemIndex;
  213. // 如果tabbar支持滚动,将选中的item放到tabbar的中央
  214. [self setSelectedItemCenter];
  215. }
  216. - (void)updateFrameOfSelectedBgWithIndex:(NSInteger)index {
  217. if (index < 0) {
  218. return;
  219. }
  220. YPTabItem *item = self.items[index];
  221. CGFloat width = item.frameWithOutTransform.size.width - self.itemSelectedBgInsets.left - self.itemSelectedBgInsets.right;
  222. CGFloat height = item.frameWithOutTransform.size.height - self.itemSelectedBgInsets.top - self.itemSelectedBgInsets.bottom;
  223. self.itemSelectedBgImageView.frame = CGRectMake(item.frameWithOutTransform.origin.x + self.itemSelectedBgInsets.left,
  224. item.frameWithOutTransform.origin.y + self.itemSelectedBgInsets.top,
  225. width,
  226. height);
  227. }
  228. - (void)setScrollEnabledAndItemWidth:(CGFloat)width {
  229. if (!self.scrollView) {
  230. self.scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
  231. self.scrollView.showsHorizontalScrollIndicator = NO;
  232. self.scrollView.showsVerticalScrollIndicator = NO;
  233. [self addSubview:self.scrollView];
  234. }
  235. self.itemWidth = width;
  236. self.itemFitTextWidth = NO;
  237. self.itemFitTextWidthSpacing = 0;
  238. [self updateItemsFrame];
  239. }
  240. - (void)setScrollEnabledAndItemFitTextWidthWithSpacing:(CGFloat)spacing {
  241. if (!self.scrollView) {
  242. self.scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
  243. self.scrollView.showsHorizontalScrollIndicator = NO;
  244. self.scrollView.showsVerticalScrollIndicator = NO;
  245. [self addSubview:self.scrollView];
  246. }
  247. self.itemFitTextWidth = YES;
  248. self.itemFitTextWidthSpacing = spacing;
  249. self.itemWidth = 0;
  250. [self updateItemsFrame];
  251. }
  252. - (void)setSelectedItemCenter {
  253. if (!self.scrollView) {
  254. return;
  255. }
  256. // 修改偏移量
  257. CGFloat offsetX = self.selectedItem.center.x - self.scrollView.frame.size.width * 0.5f;
  258. // 处理最小滚动偏移量
  259. if (offsetX < 0) {
  260. offsetX = 0;
  261. }
  262. // 处理最大滚动偏移量
  263. CGFloat maxOffsetX = self.scrollView.contentSize.width - self.scrollView.frame.size.width;
  264. if (offsetX > maxOffsetX) {
  265. offsetX = maxOffsetX;
  266. }
  267. [self.scrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
  268. }
  269. /**
  270. * 获取未选中字体与选中字体大小的比例
  271. */
  272. - (CGFloat)itemTitleUnselectedFontScale {
  273. if (_itemTitleSelectedFont) {
  274. return self.itemTitleFont.pointSize / _itemTitleSelectedFont.pointSize;
  275. }
  276. return 1.0f;
  277. }
  278. - (void)tabItemClicked:(YPTabItem *)item {
  279. if (self.selectedItemIndex == item.index) {
  280. return;
  281. }
  282. BOOL will = YES;
  283. if (self.delegate && [self.delegate respondsToSelector:@selector(yp_tabBar:willSelectItemAtIndex:)]) {
  284. will = [self.delegate yp_tabBar:self willSelectItemAtIndex:item.index];
  285. }
  286. if (will) {
  287. self.selectedItemIndex = item.index;
  288. }
  289. }
  290. - (YPTabItem *)selectedItem {
  291. if (self.selectedItemIndex < 0) {
  292. return nil;
  293. }
  294. return self.items[self.selectedItemIndex];
  295. }
  296. #pragma mark - ItemSelectedBg
  297. - (void)setItemSelectedBgColor:(UIColor *)itemSelectedBgColor {
  298. _itemSelectedBgColor = itemSelectedBgColor;
  299. self.itemSelectedBgImageView.backgroundColor = itemSelectedBgColor;
  300. }
  301. - (void)setItemSelectedBgImage:(UIImage *)itemSelectedBgImage {
  302. _itemSelectedBgImage = itemSelectedBgImage;
  303. self.itemSelectedBgImageView.image = itemSelectedBgImage;
  304. }
  305. - (void)setItemSelectedBgCornerRadius:(CGFloat)itemSelectedBgCornerRadius {
  306. _itemSelectedBgCornerRadius = itemSelectedBgCornerRadius;
  307. self.itemSelectedBgImageView.clipsToBounds = YES;
  308. self.itemSelectedBgImageView.layer.cornerRadius = itemSelectedBgCornerRadius;
  309. }
  310. - (void)setItemSelectedBgInsets:(UIEdgeInsets)insets
  311. tapSwitchAnimated:(BOOL)animated{
  312. self.itemSelectedBgInsets = insets;
  313. self.itemSelectedBgSwitchAnimated = animated;
  314. }
  315. - (void)setItemSelectedBgInsets:(UIEdgeInsets)itemSelectedBgInsets {
  316. _itemSelectedBgInsets = itemSelectedBgInsets;
  317. if (self.items.count > 0 && self.selectedItemIndex >= 0) {
  318. [self updateFrameOfSelectedBgWithIndex:self.selectedItemIndex];
  319. }
  320. }
  321. #pragma mark - ItemTitle
  322. - (void)setItemTitleColor:(UIColor *)itemTitleColor {
  323. _itemTitleColor = itemTitleColor;
  324. [self.items makeObjectsPerformSelector:@selector(setTitleColor:) withObject:itemTitleColor];
  325. }
  326. - (void)setItemTitleSelectedColor:(UIColor *)itemTitleSelectedColor {
  327. _itemTitleSelectedColor = itemTitleSelectedColor;
  328. [self.items makeObjectsPerformSelector:@selector(setTitleSelectedColor:) withObject:itemTitleSelectedColor];
  329. }
  330. - (void)setItemTitleFont:(UIFont *)itemTitleFont {
  331. _itemTitleFont = itemTitleFont;
  332. if (self.itemFontChangeFollowContentScroll) {
  333. // item字体支持平滑切换,更新每个item的scale
  334. [self updateItemsScaleIfNeeded];
  335. } else {
  336. // item字体不支持平滑切换,更新item的字体
  337. if (self.itemTitleSelectedFont) {
  338. // 设置了选中字体,则只更新未选中的item
  339. for (YPTabItem *item in self.items) {
  340. if (!item.selected) {
  341. [item setTitleFont:itemTitleFont];
  342. }
  343. }
  344. } else {
  345. // 未设置选中字体,更新所有item
  346. [self.items makeObjectsPerformSelector:@selector(setTitleFont:) withObject:itemTitleFont];
  347. }
  348. }
  349. if (self.itemFitTextWidth) {
  350. // 如果item的宽度是匹配文字的,更新item的位置
  351. [self updateItemsFrame];
  352. }
  353. }
  354. - (void)setItemTitleSelectedFont:(UIFont *)itemTitleSelectedFont {
  355. _itemTitleSelectedFont = itemTitleSelectedFont;
  356. self.selectedItem.titleFont = itemTitleSelectedFont;
  357. [self updateItemsScaleIfNeeded];
  358. }
  359. - (void)setItemFontChangeFollowContentScroll:(BOOL)itemFontChangeFollowContentScroll {
  360. _itemFontChangeFollowContentScroll = itemFontChangeFollowContentScroll;
  361. [self updateItemsScaleIfNeeded];
  362. }
  363. - (void)updateItemsScaleIfNeeded {
  364. if (self.itemTitleSelectedFont &&
  365. self.itemFontChangeFollowContentScroll &&
  366. self.itemTitleSelectedFont.pointSize != self.itemTitleFont.pointSize) {
  367. [self.items makeObjectsPerformSelector:@selector(setTitleFont:) withObject:self.itemTitleSelectedFont];
  368. for (YPTabItem *item in self.items) {
  369. if (!item.selected) {
  370. item.transform = CGAffineTransformMakeScale(self.itemTitleUnselectedFontScale,
  371. self.itemTitleUnselectedFontScale);
  372. }
  373. }
  374. }
  375. }
  376. #pragma mark - ItemContent
  377. - (void)setItemContentHorizontalCenter:(BOOL)itemContentHorizontalCenter {
  378. _itemContentHorizontalCenter = itemContentHorizontalCenter;
  379. if (itemContentHorizontalCenter) {
  380. [self setItemContentHorizontalCenterWithVerticalOffset:5 spacing:5];
  381. } else {
  382. self.itemContentHorizontalCenterVerticalOffset = 0;
  383. self.itemContentHorizontalCenterSpacing = 0;
  384. [self.items makeObjectsPerformSelector:@selector(setContentHorizontalCenter:) withObject:@(NO)];
  385. }
  386. }
  387. - (void)setItemContentHorizontalCenterWithVerticalOffset:(CGFloat)verticalOffset
  388. spacing:(CGFloat)spacing {
  389. _itemContentHorizontalCenter = YES;
  390. self.itemContentHorizontalCenterVerticalOffset = verticalOffset;
  391. self.itemContentHorizontalCenterSpacing = spacing;
  392. for (YPTabItem *item in self.items) {
  393. [item setContentHorizontalCenterWithVerticalOffset:verticalOffset spacing:spacing];
  394. }
  395. }
  396. #pragma mark - Badge
  397. - (void)setBadgeBackgroundColor:(UIColor *)badgeBackgroundColor {
  398. _badgeBackgroundColor = badgeBackgroundColor;
  399. [self.items makeObjectsPerformSelector:@selector(setBadgeBackgroundColor:) withObject:badgeBackgroundColor];
  400. }
  401. - (void)setBadgeBackgroundImage:(UIImage *)badgeBackgroundImage {
  402. _badgeBackgroundImage = badgeBackgroundImage;
  403. [self.items makeObjectsPerformSelector:@selector(setBadgeBackgroundImage:) withObject:badgeBackgroundImage];
  404. }
  405. - (void)setBadgeTitleColor:(UIColor *)badgeTitleColor {
  406. _badgeTitleColor = badgeTitleColor;
  407. [self.items makeObjectsPerformSelector:@selector(setBadgeTitleColor:) withObject:badgeTitleColor];
  408. }
  409. - (void)setBadgeTitleFont:(UIFont *)badgeTitleFont {
  410. _badgeTitleFont = badgeTitleFont;
  411. [self.items makeObjectsPerformSelector:@selector(setBadgeTitleFont:) withObject:badgeTitleFont];
  412. }
  413. - (void)setNumberBadgeMarginTop:(CGFloat)marginTop
  414. centerMarginRight:(CGFloat)centerMarginRight
  415. titleHorizonalSpace:(CGFloat)titleHorizonalSpace
  416. titleVerticalSpace:(CGFloat)titleVerticalSpace {
  417. for (YPTabItem *item in self.items) {
  418. [item setNumberBadgeMarginTop:marginTop
  419. centerMarginRight:centerMarginRight
  420. titleHorizonalSpace:titleHorizonalSpace
  421. titleVerticalSpace:titleVerticalSpace];
  422. }
  423. }
  424. - (void)setDotBadgeMarginTop:(CGFloat)marginTop
  425. centerMarginRight:(CGFloat)centerMarginRight
  426. sideLength:(CGFloat)sideLength {
  427. for (YPTabItem *item in self.items) {
  428. [item setDotBadgeMarginTop:marginTop
  429. centerMarginRight:centerMarginRight
  430. sideLength:sideLength];
  431. }
  432. }
  433. #pragma mark - UIScrollViewDelegate
  434. - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
  435. NSInteger page = scrollView.contentOffset.x / scrollView.frame.size.width;
  436. NSLog(@"scrollViewDidEndDecelerating");
  437. self.selectedItemIndex = page;
  438. }
  439. - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
  440. CGFloat offsetX = scrollView.contentOffset.x;
  441. CGFloat scrollViewWidth = scrollView.frame.size.width;
  442. if (offsetX < 0) {
  443. return;
  444. }
  445. if (offsetX > scrollView.contentSize.width - scrollViewWidth) {
  446. return;
  447. }
  448. NSInteger leftIndex = offsetX / scrollViewWidth;
  449. NSInteger rightIndex = leftIndex + 1;
  450. YPTabItem *leftItem = self.items[leftIndex];
  451. YPTabItem *rightItem;
  452. if (rightIndex < self.items.count) {
  453. rightItem = self.items[rightIndex];
  454. }
  455. // 计算右边按钮偏移量
  456. CGFloat rightScale = offsetX / scrollViewWidth;
  457. // 只想要 0~1
  458. rightScale = rightScale - leftIndex;
  459. CGFloat leftScale = 1 - rightScale;
  460. if (scrollView.isDragging || scrollView.isDecelerating) {
  461. if (self.itemFontChangeFollowContentScroll && self.itemTitleUnselectedFontScale != 1.0f) {
  462. CGFloat diff = self.itemTitleUnselectedFontScale - 1;
  463. leftItem.transform = CGAffineTransformMakeScale(rightScale * diff + 1, rightScale * diff + 1);
  464. rightItem.transform = CGAffineTransformMakeScale(leftScale * diff + 1, leftScale * diff + 1);
  465. }
  466. if (self.itemColorChangeFollowContentScroll) {
  467. static CGFloat normalRed, normalGreen, normalBlue;
  468. static CGFloat selectedRed, selectedGreen, selectedBlue;
  469. [self.itemTitleColor getRed:&normalRed green:&normalGreen blue:&normalBlue alpha:nil];
  470. [self.itemTitleSelectedColor getRed:&selectedRed green:&selectedGreen blue:&selectedBlue alpha:nil];
  471. // 获取选中和未选中状态的颜色差值
  472. CGFloat redDiff = selectedRed - normalRed;
  473. CGFloat greenDiff = selectedGreen - normalGreen;
  474. CGFloat blueDiff = selectedBlue - normalBlue;
  475. // 根据颜色值的差和偏移量,设置tabItem的标题颜色
  476. leftItem.titleLabel.textColor = [UIColor colorWithRed:leftScale * redDiff + normalRed
  477. green:leftScale * greenDiff + normalGreen
  478. blue:leftScale * blueDiff + normalBlue
  479. alpha:1];
  480. rightItem.titleLabel.textColor = [UIColor colorWithRed:rightScale * redDiff + normalRed
  481. green:rightScale * greenDiff + normalGreen
  482. blue:rightScale * blueDiff + normalBlue
  483. alpha:1];
  484. }
  485. }
  486. if (self.itemSelectedBgScrollFollowContent) {
  487. CGRect frame = self.itemSelectedBgImageView.frame;
  488. CGFloat xDiff = rightItem.frameWithOutTransform.origin.x - leftItem.frameWithOutTransform.origin.x;
  489. frame.origin.x = rightScale * xDiff + leftItem.frameWithOutTransform.origin.x + self.itemSelectedBgInsets.left;
  490. CGFloat widthDiff = rightItem.frameWithOutTransform.size.width - leftItem.frameWithOutTransform.size.width;
  491. if (widthDiff != 0) {
  492. CGFloat leftSelectedBgWidth = leftItem.frameWithOutTransform.size.width - self.itemSelectedBgInsets.left - self.itemSelectedBgInsets.right;
  493. frame.size.width = rightScale * widthDiff + leftSelectedBgWidth;
  494. }
  495. self.itemSelectedBgImageView.frame = frame;
  496. }
  497. }
  498. #pragma mark - Separator
  499. - (void)setItemSeparatorColor:(UIColor *)itemSeparatorColor
  500. width:(CGFloat)width
  501. marginTop:(CGFloat)marginTop
  502. marginBottom:(CGFloat)marginBottom {
  503. self.itemSeparatorColor = itemSeparatorColor;
  504. self.itemSeparatorWidth = width;
  505. self.itemSeparatorMarginTop = marginTop;
  506. self.itemSeparatorMarginBottom = marginBottom;
  507. [self updateSeperators];
  508. }
  509. - (void)setItemSeparatorColor:(UIColor *)itemSeparatorColor
  510. marginTop:(CGFloat)marginTop
  511. marginBottom:(CGFloat)marginBottom {
  512. UIScreen *mainScreen = [UIScreen mainScreen];
  513. CGFloat onePixel;
  514. if ([mainScreen respondsToSelector:@selector(nativeScale)]) {
  515. onePixel = 1.0f / mainScreen.nativeScale;
  516. } else {
  517. onePixel = 1.0f / mainScreen.scale;
  518. }
  519. [self setItemSeparatorColor:itemSeparatorColor
  520. width:onePixel
  521. marginTop:marginTop
  522. marginBottom:marginBottom];
  523. }
  524. - (void)updateSeperators {
  525. if (self.itemSeparatorColor) {
  526. if (!self.separatorLayers) {
  527. self.separatorLayers = [[NSMutableArray alloc] init];
  528. }
  529. [self.separatorLayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
  530. [self.separatorLayers removeAllObjects];
  531. [self.items enumerateObjectsUsingBlock:^(YPTabItem * _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop) {
  532. if (idx > 0) {
  533. CALayer *layer = [[CALayer alloc] init];
  534. layer.backgroundColor = self.itemSeparatorColor.CGColor;
  535. layer.frame = CGRectMake(item.frame.origin.x - self.itemSeparatorWidth / 2,
  536. self.itemSeparatorMarginTop,
  537. self.itemSeparatorWidth,
  538. self.bounds.size.height - self.itemSeparatorMarginTop - self.itemSeparatorMarginBottom);
  539. [self.layer addSublayer:layer];
  540. [self.separatorLayers addObject:layer];
  541. }
  542. }];
  543. } else {
  544. [self.separatorLayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
  545. [self.separatorLayers removeAllObjects];
  546. self.separatorLayers = nil;
  547. }
  548. }
  549. @end