TYTabPagerController.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. #import "TYTabPagerController.h"
  2. #import "TYTabTitleViewCell.h"
  3. #import <QMUIKit/QMUIKit.h>
  4. @interface TYTabPagerController ()<UICollectionViewDelegateFlowLayout, UICollectionViewDataSource>
  5. {
  6. struct {
  7. unsigned int titleForIndex :1;
  8. }_tabDataSourceFlags;
  9. struct {
  10. unsigned int configreReusableCell :1;
  11. unsigned int didSelectAtIndexPath :1;
  12. unsigned int didScrollToTabPageIndex :1;
  13. unsigned int transitionFromeCellAnimated :1;
  14. unsigned int transitionFromeCellProgress :1;
  15. }_tabDelegateFlags;
  16. }
  17. // views
  18. //@property (nonatomic, weak) UIView *pagerBarView;
  19. @property (nonatomic, weak) UICollectionView *collectionViewBar;
  20. @property (nonatomic, weak) UIView *progressView;
  21. @property (nonatomic ,assign) Class cellClass;
  22. @property (nonatomic ,assign) BOOL cellContainXib;
  23. @property (nonatomic ,strong) NSString *cellId;
  24. @end
  25. //#define kCollectionViewBarHieght 50 + 44
  26. //tabbar高度
  27. #define kUnderLineViewHeight 1
  28. #define _pageBarWidth (kScreenW - 10 * 2)
  29. @implementation TYTabPagerController
  30. - (instancetype)initWithCoder:(NSCoder *)aDecoder
  31. {
  32. if (self = [super initWithCoder:aDecoder]) {
  33. [self configireTabPropertys];
  34. }
  35. return self;
  36. }
  37. - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
  38. {
  39. if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
  40. [self configireTabPropertys];
  41. }
  42. return self;
  43. }
  44. - (void)configireTabPropertys
  45. {
  46. _kCollectionViewBarHieght = 50 + 44;
  47. _animateDuration = 0.1;
  48. _barStyle = TYPagerBarStyleNoneView;
  49. _normalTextFont = [UIFont systemFontOfSize:16];
  50. _selectedTextFont = [UIFont boldSystemFontOfSize:20];
  51. _cellSpacing = 0;
  52. _cellEdging = 0;
  53. _progressHeight = kUnderLineViewHeight;
  54. _progressEdging = 0;
  55. _progressWidth = 0;
  56. self.changeIndexWhenScrollProgress = 1.0;
  57. self.contentTopEdging = _kCollectionViewBarHieght;
  58. }
  59. #pragma mark - life cycle
  60. - (void)viewDidLoad {
  61. [super viewDidLoad];
  62. // Do any additional setup after loading the view.
  63. // add pager bar
  64. [self addPagerBarView];
  65. // add title views
  66. [self addCollectionViewBar];
  67. // add progress view
  68. [self addUnderLineView];
  69. }
  70. - (void)addPagerBarView
  71. {
  72. //首页顶部背景颜色
  73. _bgTopImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"mg_hm_topBgImgView"]];
  74. _bgTopImgView.frame = CGRectMake(0, 0, kScreenW, _kCollectionViewBarHieght);
  75. [self.view addSubview:_bgTopImgView];
  76. _pagerBarView = [[UIView alloc]initWithFrame:CGRectMake(0,0,CGRectGetWidth(self.view.frame), self.kCollectionViewBarHieght)];
  77. [self.view addSubview:_pagerBarView];
  78. }
  79. //在这里添加控件
  80. - (void)addCollectionViewBar
  81. {
  82. UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];
  83. layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  84. UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(20,0, CGRectGetWidth(self.view.frame), _pagerBarView.height) collectionViewLayout:layout];
  85. collectionView.showsHorizontalScrollIndicator = NO;
  86. collectionView.showsVerticalScrollIndicator = NO;
  87. collectionView.delegate = self;
  88. collectionView.backgroundColor = kYellowColor;
  89. collectionView.dataSource = self;
  90. [_pagerBarView addSubview:collectionView];
  91. //tabbar title
  92. _collectionViewBar = collectionView;
  93. if (_cellContainXib) {
  94. UINib *nib = [UINib nibWithNibName:_cellId bundle:nil];
  95. [collectionView registerNib:nib forCellWithReuseIdentifier:_cellId];
  96. }else {
  97. [collectionView registerClass:_cellClass forCellWithReuseIdentifier:_cellId];
  98. }
  99. }
  100. // layout tab view
  101. - (void)layoutTabPagerView
  102. {
  103. ((UICollectionViewFlowLayout *)_collectionViewBar.collectionViewLayout).minimumLineSpacing = 0;
  104. // CGFloat collectionViewEaging = _barStyle != TYPagerBarStyleCoverView ? _collectionLayoutEdging : (_collectionLayoutEdging > 0 ? _collectionLayoutEdging : -_progressEdging+_cellSpacing);
  105. ((UICollectionViewFlowLayout *)self.collectionViewBar.collectionViewLayout).sectionInset = UIEdgeInsetsMake(5,0,0,0);
  106. //tabbar 位置
  107. // if(isIPhoneX())
  108. // {
  109. // _pagerBarView.frame = CGRectMake(0,self.collectionLayoutEdging ,CGRectGetWidth(self.view.frame),_kCollectionViewBarHieght);
  110. // }
  111. // else
  112. // {
  113. _pagerBarView.frame = CGRectMake(0,MG_TOP_MARGIN,CGRectGetWidth(self.view.frame),_kCollectionViewBarHieght);
  114. // }
  115. CGFloat collectionbar_w =0;
  116. for (int i =0; i<[self.dataSource numberOfControllersInPagerController]; i++)
  117. {
  118. NSString *title = [self.dataSource pagerController:self titleForIndex:i];
  119. CGFloat width = [self boundingSizeWithString:title font:_selectedTextFont constrainedToSize:CGSizeMake(300, 100)].width+_cellEdging*1.5;
  120. if (width > _pageBarWidth/7)
  121. {
  122. collectionbar_w +=width;
  123. }else
  124. collectionbar_w +=_pageBarWidth/7;
  125. }
  126. if (collectionbar_w > _pageBarWidth)
  127. {
  128. collectionbar_w =_pageBarWidth;
  129. }
  130. // _collectionViewBar.frame = CGRectMake(10,0,collectionbar_w,_kCollectionViewBarHieght);
  131. // _collectionViewBar.y += 10;
  132. // int x = CGRectGetMinXHorizontallyCenterInParentRect(self.view.frame,_collectionViewBar.frame);
  133. // _collectionViewBar.x = x;
  134. self.pagerBarView.frame = CGRectMake(0, isIPhoneX() ? 30 : 10, kScreenW - self.collectionLayoutEdging , kRealValue(44));
  135. self.collectionViewBar.frame = self.pagerBarView.bounds;
  136. }
  137. //添加下划线
  138. - (void)addUnderLineView
  139. {
  140. UIView *underLineView = [[UIView alloc]init];
  141. underLineView.hidden = (_barStyle == TYPagerBarStyleNoneView);
  142. underLineView.layer.cornerRadius = 2;
  143. if (_barStyle != TYPagerBarStyleCoverView) {
  144. [_collectionViewBar addSubview:underLineView];
  145. }else{
  146. underLineView.layer.zPosition = -1;
  147. [_collectionViewBar insertSubview:underLineView atIndex:0];
  148. }
  149. _progressView = underLineView;
  150. }
  151. #pragma mark - setter
  152. - (void)setBarStyle:(TYPagerBarStyle)barStyle
  153. {
  154. _barStyle = barStyle;
  155. _progressView.hidden = (_barStyle == TYPagerBarStyleNoneView);
  156. }
  157. - (void)setDelegate:(id<TYTabPagerControllerDelegate>)delegate
  158. {
  159. [super setDelegate:delegate];
  160. _tabDelegateFlags.configreReusableCell = [self.delegate respondsToSelector:@selector(pagerController:configreCell:forItemTitle:atIndexPath:)];
  161. _tabDelegateFlags.didSelectAtIndexPath = [self.delegate respondsToSelector:@selector(pagerController:didSelectAtIndexPath:)];
  162. _tabDelegateFlags.didScrollToTabPageIndex = [self.delegate respondsToSelector:@selector(pagerController:didScrollToTabPageIndex:)];
  163. _tabDelegateFlags.transitionFromeCellAnimated = [self.delegate respondsToSelector:@selector(pagerController:transitionFromeCell:toCell:animated:)];
  164. _tabDelegateFlags.transitionFromeCellProgress = [self.delegate respondsToSelector:@selector(pagerController:transitionFromeCell:toCell:progress:)];
  165. }
  166. - (void)setDataSource:(id<TYPagerControllerDataSource>)dataSource
  167. {
  168. [super setDataSource:dataSource];
  169. _tabDataSourceFlags.titleForIndex = [self.dataSource respondsToSelector:@selector(pagerController:titleForIndex:)];
  170. NSAssert(_tabDataSourceFlags.titleForIndex, @"TYPagerControllerDataSource pagerController:titleForIndex: not impletement!");
  171. }
  172. #pragma mark - public
  173. - (void)reloadData
  174. {
  175. [_collectionViewBar reloadData];
  176. [super reloadData];
  177. }
  178. // update tab subviews frame
  179. - (void)updateContentView
  180. {
  181. [super updateContentView];
  182. [self layoutTabPagerView];
  183. [self setUnderLineFrameWithIndex:1 animated:NO];
  184. [self tabScrollToIndex:1 animated:NO];
  185. }
  186. - (void)registerCellClass:(Class)cellClass isContainXib:(BOOL)isContainXib
  187. {
  188. _cellClass = cellClass;
  189. _cellId = NSStringFromClass(cellClass);
  190. _cellContainXib = isContainXib;
  191. }
  192. - (CGRect)cellFrameWithIndex:(NSInteger)index
  193. {
  194. if (index >= self.countOfControllers) {
  195. return CGRectZero;
  196. }
  197. UICollectionViewLayoutAttributes * cellAttrs = [_collectionViewBar layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]];
  198. return cellAttrs.frame;
  199. }
  200. - (UICollectionViewCell *)cellForIndex:(NSInteger)index
  201. {
  202. if (index >= self.countOfControllers) {
  203. return nil;
  204. }
  205. return [_collectionViewBar cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]];
  206. }
  207. - (void)tabScrollToIndex:(NSInteger)index animated:(BOOL)animated
  208. {
  209. if (_tabDelegateFlags.didScrollToTabPageIndex) {
  210. [self.delegate pagerController:self didScrollToTabPageIndex:index];
  211. }
  212. if (index < self.countOfControllers) {
  213. [_collectionViewBar scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:animated];
  214. }
  215. }
  216. #pragma mark - private
  217. // set up progress view frame
  218. //设置下划线
  219. - (void)setUnderLineFrameWithIndex:(NSInteger)index animated:(BOOL)animated
  220. {
  221. if (_progressView.isHidden || self.countOfControllers == 0) {
  222. return;
  223. }
  224. CGRect cellFrame = [self cellFrameWithIndex:index];
  225. CGFloat progressEdging = _progressWidth > 0 ? (cellFrame.size.width - _progressWidth)/2 : _progressEdging;
  226. CGFloat progressX = cellFrame.origin.x+progressEdging;
  227. CGFloat progressY = _barStyle == TYPagerBarStyleCoverView ? (cellFrame.size.height - _progressHeight)/2:(cellFrame.size.height - _progressHeight);
  228. progressY += 3;
  229. CGFloat width = cellFrame.size.width-2*progressEdging;
  230. if (animated) {
  231. [UIView animateWithDuration:_animateDuration animations:^{
  232. _progressView.frame = CGRectMake(progressX + 13, progressY+3, width - 26, _progressHeight);
  233. }];
  234. }else {
  235. _progressView.frame = CGRectMake(progressX + 13, progressY+3, width - 26, _progressHeight);
  236. }
  237. }
  238. - (void)setUnderLineFrameWithfromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress
  239. {
  240. if (_progressView.isHidden || self.countOfControllers == 0) {
  241. return;
  242. }
  243. CGRect fromCellFrame = [self cellFrameWithIndex:fromIndex];
  244. CGRect toCellFrame = [self cellFrameWithIndex:toIndex];
  245. CGFloat progressFromEdging = _progressWidth > 0 ? (fromCellFrame.size.width - _progressWidth)/2 : _progressEdging;
  246. CGFloat progressToEdging = _progressWidth > 0 ? (toCellFrame.size.width - _progressWidth)/2 : _progressEdging;
  247. CGFloat progressY = _barStyle == TYPagerBarStyleCoverView ? (toCellFrame.size.height - _progressHeight)/2 + 3:(toCellFrame.size.height - _progressHeight) + 3;
  248. progressY += 3;
  249. CGFloat progressX, width;
  250. if (_barStyle == TYPagerBarStyleProgressBounceView) {
  251. if (fromCellFrame.origin.x < toCellFrame.origin.x) {
  252. if (progress <= 0.5) {
  253. progressX = fromCellFrame.origin.x + progressFromEdging ;
  254. width = (toCellFrame.size.width-progressToEdging+progressFromEdging+_cellSpacing)*2*progress + fromCellFrame.size.width-2*progressFromEdging ;
  255. }else {
  256. progressX = fromCellFrame.origin.x + progressFromEdging + (fromCellFrame.size.width-progressFromEdging+progressToEdging+_cellSpacing)*(progress-0.5)*2 ;
  257. width = CGRectGetMaxX(toCellFrame)-progressToEdging - progressX ;
  258. }
  259. }else {
  260. if (progress <= 0.5) {
  261. progressX = fromCellFrame.origin.x + progressFromEdging - (toCellFrame.size.width-progressToEdging+progressFromEdging+_cellSpacing)*2*progress;
  262. width = CGRectGetMaxX(fromCellFrame) - progressFromEdging - progressX ;
  263. }else {
  264. progressX = toCellFrame.origin.x + progressToEdging ;
  265. width = (fromCellFrame.size.width-progressFromEdging+progressToEdging + _cellSpacing)*(1-progress)*2 + toCellFrame.size.width - 2*progressToEdging ;
  266. }
  267. }
  268. }else {
  269. progressX = (toCellFrame.origin.x+progressToEdging-(fromCellFrame.origin.x+progressFromEdging))*progress+fromCellFrame.origin.x+progressFromEdging ;
  270. width = (toCellFrame.size.width-2*progressToEdging)*progress + (fromCellFrame.size.width-2*progressFromEdging)*(1-progress) ;
  271. }
  272. _progressView.frame = CGRectMake(progressX + 13,progressY+3, width - 26, _progressHeight);//下划线宽度
  273. }
  274. #pragma mark - override transition
  275. - (void)transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated
  276. {
  277. UICollectionViewCell *fromCell = [self cellForIndex:fromIndex];
  278. UICollectionViewCell *toCell = [self cellForIndex:toIndex];
  279. if (![self isProgressScrollEnabel]) {
  280. // if isn't progressing
  281. if (_tabDelegateFlags.transitionFromeCellAnimated) {
  282. [self.delegate pagerController:self transitionFromeCell:fromCell toCell:toCell animated:animated];
  283. }
  284. [self setUnderLineFrameWithIndex:toIndex animated:fromCell && animated ? animated: NO];
  285. }
  286. [self tabScrollToIndex:toIndex animated:toCell ? YES : fromCell && animated ? animated: NO];
  287. }
  288. - (void)transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress
  289. {
  290. UICollectionViewCell *fromCell = (TYTabTitleViewCell *)[self cellForIndex:fromIndex];
  291. UICollectionViewCell *toCell = (TYTabTitleViewCell *)[self cellForIndex:toIndex];
  292. if (_tabDelegateFlags.transitionFromeCellProgress) {
  293. [self.delegate pagerController:self transitionFromeCell:fromCell toCell:toCell progress:progress];
  294. }
  295. [self setUnderLineFrameWithfromIndex:fromIndex toIndex:toIndex progress:progress];
  296. }
  297. #pragma mark - UICollectionViewDataSource
  298. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
  299. {
  300. return [self.dataSource numberOfControllersInPagerController];
  301. }
  302. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  303. {
  304. UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:_cellId forIndexPath:indexPath];
  305. if (_tabDataSourceFlags.titleForIndex) {
  306. NSString *title = [self.dataSource pagerController:self titleForIndex:indexPath.item];
  307. if (_tabDelegateFlags.configreReusableCell) {
  308. [self.delegate pagerController:self configreCell:cell forItemTitle:title atIndexPath:indexPath];
  309. }
  310. if (_tabDelegateFlags.transitionFromeCellAnimated) {
  311. [self.delegate pagerController:self transitionFromeCell:(indexPath.item == self.curIndex ? nil : cell) toCell:(indexPath.item == self.curIndex ? cell : nil) animated:NO];
  312. }
  313. }
  314. return cell;
  315. }
  316. #pragma mark - UICollectionViewDelegateFlowLayout
  317. - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
  318. {
  319. [self moveToControllerAtIndex:indexPath.item animated:YES];
  320. if (_tabDelegateFlags.didSelectAtIndexPath) {
  321. [self.delegate pagerController:self didSelectAtIndexPath:indexPath];
  322. }
  323. }
  324. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
  325. {
  326. // if(false)
  327. // {
  328. // return CGSizeMake(_pageBarWidth/3,CGRectGetHeight(_collectionViewBar.frame) - 10);
  329. // }
  330. NSString *title = [self.dataSource pagerController:self titleForIndex:indexPath.item];
  331. CGFloat width = [self boundingSizeWithString:title font:_selectedTextFont constrainedToSize:CGSizeMake(300, 100)].width+_cellEdging*1.5;
  332. if (width > _pageBarWidth/7)
  333. {
  334. return CGSizeMake(width,CGRectGetHeight(_collectionViewBar.frame) - 10);
  335. }
  336. return CGSizeMake(_pageBarWidth/7,CGRectGetHeight(_collectionViewBar.frame) - 10);
  337. }
  338. // text size
  339. - (CGSize)boundingSizeWithString:(NSString *)string font:(UIFont *)font constrainedToSize:(CGSize)size
  340. {
  341. CGSize textSize = CGSizeZero;
  342. #if (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0)
  343. if (![string respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
  344. // below ios7
  345. textSize = [string sizeWithFont:font
  346. constrainedToSize:size
  347. lineBreakMode:NSLineBreakByWordWrapping];
  348. }
  349. else
  350. #endif
  351. {
  352. //iOS 7
  353. CGRect frame = [string boundingRectWithSize:size options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{ NSFontAttributeName:font } context:nil];
  354. textSize = CGSizeMake(frame.size.width, frame.size.height + 1);
  355. }
  356. return textSize;
  357. }
  358. @end