SGAdvertScrollView.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. //
  2. // SGAdvertScrollView.m
  3. // SGAdvertScrollViewExample
  4. //
  5. // Created by kingsic on 17/3/8.
  6. // Copyright © 2017年 kingsic. All rights reserved.
  7. //
  8. #import "SGAdvertScrollView.h"
  9. #import "UIImageView+WebCache.h"
  10. static NSInteger const advertScrollViewTitleFont = 13;
  11. #pragma mark - - - SGAdvertScrollViewStyleNormal 样式下的 cell
  12. @interface SGAdvertScrollViewNormalCell : UICollectionViewCell
  13. @property (nonatomic, strong) UIImageView *signImageView;
  14. @property (nonatomic, strong) UILabel *titleLabel;
  15. @end
  16. @implementation SGAdvertScrollViewNormalCell
  17. - (instancetype)initWithFrame:(CGRect)frame {
  18. if (self = [super initWithFrame:frame]) {
  19. self.backgroundColor = [UIColor clearColor];
  20. [self.contentView addSubview:self.signImageView];
  21. [self.contentView addSubview:self.titleLabel];
  22. }
  23. return self;
  24. }
  25. - (void)layoutSubviews {
  26. [super layoutSubviews];
  27. CGFloat spacing = 5;
  28. CGFloat signImageViewW = self.signImageView.image.size.width;
  29. CGFloat signImageViewH = self.signImageView.image.size.height;
  30. CGFloat signImageViewX = 0;
  31. CGFloat signImageViewY = 0;
  32. self.signImageView.frame = CGRectMake(signImageViewX, signImageViewY, signImageViewW, signImageViewH);
  33. CGFloat labelX = 0;
  34. if (self.signImageView.image == nil) {
  35. labelX = 0;
  36. } else {
  37. labelX = CGRectGetMaxX(self.signImageView.frame) + 0.5 * spacing;
  38. }
  39. CGFloat labelY = 0;
  40. CGFloat labelW = self.frame.size.width - labelX;
  41. CGFloat labelH = self.frame.size.height;
  42. self.titleLabel.frame = CGRectMake(labelX, labelY, labelW, labelH);
  43. CGPoint topPoint = self.signImageView.center;
  44. topPoint.y = _titleLabel.center.y;
  45. _signImageView.center = topPoint;
  46. }
  47. - (UIImageView *)signImageView {
  48. if (!_signImageView) {
  49. _signImageView = [[UIImageView alloc] init];
  50. }
  51. return _signImageView;
  52. }
  53. - (UILabel *)titleLabel {
  54. if (!_titleLabel) {
  55. _titleLabel = [[UILabel alloc] init];
  56. _titleLabel.textColor = [UIColor blackColor];
  57. _titleLabel.font = [UIFont systemFontOfSize:advertScrollViewTitleFont];
  58. }
  59. return _titleLabel;
  60. }
  61. @end
  62. #pragma mark - - - SGAdvertScrollViewStyleMore 样式下的 cell
  63. @interface SGAdvertScrollViewMoreCell : UICollectionViewCell
  64. @property (nonatomic, strong) UIImageView *topSignImageView;
  65. @property (nonatomic, strong) UILabel *topLabel;
  66. @property (nonatomic, strong) UIImageView *bottomSignImageView;
  67. @property (nonatomic, strong) UILabel *bottomLabel;
  68. @end
  69. @implementation SGAdvertScrollViewMoreCell
  70. - (instancetype)initWithFrame:(CGRect)frame {
  71. if (self = [super initWithFrame:frame]) {
  72. self.backgroundColor = [UIColor clearColor];
  73. [self.contentView addSubview:self.topSignImageView];
  74. [self.contentView addSubview:self.topLabel];
  75. [self.contentView addSubview:self.bottomSignImageView];
  76. [self.contentView addSubview:self.bottomLabel];
  77. }
  78. return self;
  79. }
  80. - (void)layoutSubviews {
  81. [super layoutSubviews];
  82. CGFloat spacing = 5;
  83. CGFloat topSignImageViewW = self.topSignImageView.image.size.width;
  84. CGFloat topSignImageViewH = self.topSignImageView.image.size.height;
  85. CGFloat topSignImageViewX = 0;
  86. CGFloat topSignImageViewY = spacing;
  87. self.topSignImageView.frame = CGRectMake(topSignImageViewX, topSignImageViewY, topSignImageViewW, topSignImageViewH);
  88. CGFloat topLabelX = 0;
  89. if (self.topSignImageView.image == nil) {
  90. topLabelX = 0;
  91. } else {
  92. topLabelX = CGRectGetMaxX(self.topSignImageView.frame) + 0.5 * spacing;
  93. }
  94. CGFloat topLabelY = topSignImageViewY;
  95. CGFloat topLabelW = self.frame.size.width - topLabelX;
  96. CGFloat topLabelH = 0.5 * (self.frame.size.height - 2 * topLabelY);
  97. self.topLabel.frame = CGRectMake(topLabelX, topLabelY, topLabelW, topLabelH);
  98. CGPoint topPoint = self.topSignImageView.center;
  99. topPoint.y = _topLabel.center.y;
  100. _topSignImageView.center = topPoint;
  101. CGFloat bottomSignImageViewW = self.bottomSignImageView.image.size.width;
  102. CGFloat bottomSignImageViewH = self.bottomSignImageView.image.size.height;
  103. CGFloat bottomSignImageViewX = 0;
  104. CGFloat bottomSignImageViewY = CGRectGetMaxY(self.topLabel.frame);
  105. self.bottomSignImageView.frame = CGRectMake(bottomSignImageViewX, bottomSignImageViewY, bottomSignImageViewW, bottomSignImageViewH);
  106. CGFloat bottomLabelX = 0;
  107. if (self.bottomSignImageView.image == nil) {
  108. bottomLabelX = 0;
  109. } else {
  110. bottomLabelX = CGRectGetMaxX(self.bottomSignImageView.frame) + 0.5 * spacing;
  111. }
  112. CGFloat bottomLabelY = CGRectGetMaxY(self.topLabel.frame);
  113. CGFloat bottomLabelW = self.frame.size.width - bottomLabelX;
  114. CGFloat bottomLabelH = topLabelH;
  115. self.bottomLabel.frame = CGRectMake(bottomLabelX, bottomLabelY, bottomLabelW, bottomLabelH);
  116. CGPoint bottomPoint = self.bottomSignImageView.center;
  117. bottomPoint.y = _bottomLabel.center.y;
  118. _bottomSignImageView.center = bottomPoint;
  119. }
  120. - (UIImageView *)topSignImageView {
  121. if (!_topSignImageView) {
  122. _topSignImageView = [[UIImageView alloc] init];
  123. }
  124. return _topSignImageView;
  125. }
  126. - (UILabel *)topLabel {
  127. if (!_topLabel) {
  128. _topLabel = [[UILabel alloc] init];
  129. _topLabel.textColor = [UIColor blackColor];
  130. _topLabel.font = [UIFont systemFontOfSize:advertScrollViewTitleFont];
  131. }
  132. return _topLabel;
  133. }
  134. - (UIImageView *)bottomSignImageView {
  135. if (!_bottomSignImageView) {
  136. _bottomSignImageView = [[UIImageView alloc] init];
  137. }
  138. return _bottomSignImageView;
  139. }
  140. - (UILabel *)bottomLabel {
  141. if (!_bottomLabel) {
  142. _bottomLabel = [[UILabel alloc] init];
  143. _bottomLabel.textColor = [UIColor blackColor];
  144. _bottomLabel.font = [UIFont systemFontOfSize:advertScrollViewTitleFont];
  145. }
  146. return _bottomLabel;
  147. }
  148. @end
  149. #pragma mark - - - SGAdvertScrollView
  150. @interface SGAdvertScrollView () <UICollectionViewDelegate, UICollectionViewDataSource>
  151. @property (nonatomic, strong) UICollectionViewFlowLayout *flowLayout;
  152. @property (nonatomic, strong) UICollectionView *collectionView;
  153. @property (nonatomic, strong) NSTimer *timer;
  154. @property (nonatomic, strong) NSArray *titleArr;
  155. @property (nonatomic, strong) NSArray *imageArr;
  156. @property (nonatomic, strong) NSArray *bottomImageArr;
  157. @property (nonatomic, strong) NSArray *bottomTitleArr;
  158. @end
  159. @implementation SGAdvertScrollView
  160. static NSInteger const advertScrollViewMaxSections = 100;
  161. static NSString *const advertScrollViewNormalCell = @"advertScrollViewNormalCell";
  162. static NSString *const advertScrollViewMoreCell = @"advertScrollViewMoreCell";
  163. - (void)awakeFromNib {
  164. [super awakeFromNib];
  165. [self initialization];
  166. [self setupSubviews];
  167. }
  168. - (instancetype)initWithFrame:(CGRect)frame {
  169. if (self = [super initWithFrame:frame]) {
  170. self.backgroundColor = [UIColor whiteColor];
  171. [self initialization];
  172. [self setupSubviews];
  173. }
  174. return self;
  175. }
  176. - (void)willMoveToSuperview:(UIView *)newSuperview {
  177. if (!newSuperview) {
  178. [self removeTimer];
  179. }
  180. }
  181. - (void)dealloc {
  182. _collectionView.delegate = nil;
  183. _collectionView.dataSource = nil;
  184. }
  185. - (void)initialization {
  186. _scrollTimeInterval = 3.0;
  187. [self addTimer];
  188. _advertScrollViewStyle = SGAdvertScrollViewStyleNormal;
  189. }
  190. - (void)setupSubviews {
  191. UIView *tempView = [[UIView alloc] initWithFrame:CGRectZero];
  192. [self addSubview:tempView];
  193. [self addSubview:self.collectionView];
  194. }
  195. - (UICollectionView *)collectionView {
  196. if (!_collectionView) {
  197. _flowLayout = [[UICollectionViewFlowLayout alloc] init];
  198. _flowLayout.minimumLineSpacing = 0;
  199. _collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:_flowLayout];
  200. _collectionView.delegate = self;
  201. _collectionView.dataSource = self;
  202. _collectionView.scrollsToTop = NO;
  203. _collectionView.scrollEnabled = NO;
  204. _collectionView.pagingEnabled = YES;
  205. _collectionView.showsVerticalScrollIndicator = NO;
  206. _collectionView.backgroundColor = [UIColor clearColor];
  207. [_collectionView registerClass:[SGAdvertScrollViewNormalCell class] forCellWithReuseIdentifier:advertScrollViewNormalCell];
  208. }
  209. return _collectionView;
  210. }
  211. - (void)layoutSubviews {
  212. [super layoutSubviews];
  213. _flowLayout.itemSize = CGSizeMake(self.frame.size.width, self.frame.size.height);
  214. _collectionView.frame = self.bounds;
  215. if (self.titleArr.count > 1) {
  216. [self defaultSelectedScetion];
  217. }
  218. }
  219. - (void)defaultSelectedScetion {
  220. [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0.5 * advertScrollViewMaxSections] atScrollPosition:UICollectionViewScrollPositionBottom animated:NO];
  221. }
  222. #pragma mark - - - UICollectionView 的 dataSource、delegate方法
  223. - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
  224. return advertScrollViewMaxSections;
  225. }
  226. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  227. return self.titleArr.count;
  228. }
  229. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  230. if (self.advertScrollViewStyle == SGAdvertScrollViewStyleMore) {
  231. SGAdvertScrollViewMoreCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:advertScrollViewMoreCell forIndexPath:indexPath];
  232. NSInteger topImagesCount = self.imageArr.count;
  233. if (topImagesCount > 0) {
  234. NSString *topImagePath = self.imageArr[indexPath.item];
  235. if (topImagePath == nil || [topImagePath isEqualToString:@""]) { // 解决 iOS 11 无图片,控制台打印问题
  236. if ([topImagePath hasPrefix:@"http"]) {
  237. [cell.topSignImageView sd_setImageWithURL:[NSURL URLWithString:@"www.kingsic22.com"]];
  238. } else {
  239. cell.topSignImageView.image = [UIImage imageNamed:@"kingsic"];
  240. }
  241. } else {
  242. if ([topImagePath hasPrefix:@"http"]) {
  243. [cell.topSignImageView sd_setImageWithURL:[NSURL URLWithString:topImagePath]];
  244. } else {
  245. cell.topSignImageView.image = [UIImage imageNamed:topImagePath];
  246. }
  247. }
  248. }
  249. cell.topLabel.text = self.titleArr[indexPath.item];
  250. NSInteger bottomImagesCount = self.bottomImageArr.count;
  251. if (bottomImagesCount > 0) {
  252. NSString *bottomImagePath = self.bottomImageArr[indexPath.item];
  253. if (bottomImagePath == nil || [bottomImagePath isEqualToString:@""]) { // 解决 iOS 11 无图片,控制台打印问题
  254. if ([bottomImagePath hasPrefix:@"http"]) {
  255. [cell.bottomSignImageView sd_setImageWithURL:[NSURL URLWithString:@"www.kingsic22.com"]];
  256. } else {
  257. cell.bottomSignImageView.image = [UIImage imageNamed:@"kingsic"];
  258. }
  259. } else {
  260. if ([bottomImagePath hasPrefix:@"http"]) {
  261. [cell.bottomSignImageView sd_setImageWithURL:[NSURL URLWithString:bottomImagePath]];
  262. } else {
  263. cell.bottomSignImageView.image = [UIImage imageNamed:bottomImagePath];
  264. }
  265. }
  266. }
  267. cell.bottomLabel.text = self.bottomTitleArr[indexPath.item];
  268. if (self.titleFont) {
  269. cell.topLabel.font = self.titleFont;
  270. cell.bottomLabel.font = self.titleFont;
  271. }
  272. if (self.topTitleColor) {
  273. cell.topLabel.textColor = self.topTitleColor;
  274. }
  275. if (self.bottomTitleColor) {
  276. cell.bottomLabel.textColor = self.bottomTitleColor;
  277. }
  278. return cell;
  279. } else {
  280. SGAdvertScrollViewNormalCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:advertScrollViewNormalCell forIndexPath:indexPath];
  281. NSInteger imagesCount = self.imageArr.count;
  282. if (imagesCount > 0) {
  283. NSString *imagePath = self.imageArr[indexPath.item];
  284. if (imagePath == nil || [imagePath isEqualToString:@""]) { // 解决 iOS 11 无图片,控制台打印问题
  285. if ([imagePath hasPrefix:@"http"]) {
  286. [cell.signImageView sd_setImageWithURL:[NSURL URLWithString:@"www.kingsic22.com"]];
  287. } else {
  288. cell.signImageView.image = [UIImage imageNamed:@"kingsic"];
  289. }
  290. } else {
  291. if ([imagePath hasPrefix:@"http"]) {
  292. [cell.signImageView sd_setImageWithURL:[NSURL URLWithString:imagePath]];
  293. } else {
  294. cell.signImageView.image = [UIImage imageNamed:imagePath];
  295. }
  296. }
  297. }
  298. cell.titleLabel.text = self.titleArr[indexPath.item];
  299. if (self.textAlignment) {
  300. cell.titleLabel.textAlignment = self.textAlignment;
  301. }
  302. if (self.titleFont) {
  303. cell.titleLabel.font = self.titleFont;
  304. }
  305. if (self.titleColor) {
  306. cell.titleLabel.textColor = self.titleColor;
  307. }
  308. return cell;
  309. }
  310. }
  311. - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  312. if (self.delegate && [self.delegate respondsToSelector:@selector(advertScrollView:didSelectedItemAtIndex:)]) {
  313. [self.delegate advertScrollView:self didSelectedItemAtIndex:indexPath.item];
  314. }
  315. }
  316. #pragma mark - - - NSTimer
  317. - (void)addTimer {
  318. [self removeTimer];
  319. self.timer = [NSTimer timerWithTimeInterval:self.scrollTimeInterval target:self selector:@selector(beginUpdateUI) userInfo:nil repeats:YES];
  320. [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
  321. }
  322. - (void)removeTimer {
  323. [_timer invalidate];
  324. _timer = nil;
  325. }
  326. - (void)beginUpdateUI {
  327. if (self.titleArr.count == 0) return;
  328. // 1、当前正在展示的位置
  329. NSIndexPath *currentIndexPath = [[self.collectionView indexPathsForVisibleItems] lastObject];
  330. // 马上显示回最中间那组的数据
  331. NSIndexPath *resetCurrentIndexPath = [NSIndexPath indexPathForItem:currentIndexPath.item inSection:0.5 * advertScrollViewMaxSections];
  332. [self.collectionView scrollToItemAtIndexPath:resetCurrentIndexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:NO];
  333. // 2、计算出下一个需要展示的位置
  334. NSInteger nextItem = resetCurrentIndexPath.item + 1;
  335. NSInteger nextSection = resetCurrentIndexPath.section;
  336. if (nextItem == self.titleArr.count) {
  337. nextItem = 0;
  338. nextSection++;
  339. }
  340. NSIndexPath *nextIndexPath = [NSIndexPath indexPathForItem:nextItem inSection:nextSection];
  341. // 3、通过动画滚动到下一个位置
  342. [self.collectionView scrollToItemAtIndexPath:nextIndexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:YES];
  343. }
  344. #pragma mark - - - setting
  345. - (void)setAdvertScrollViewStyle:(SGAdvertScrollViewStyle)advertScrollViewStyle {
  346. _advertScrollViewStyle = advertScrollViewStyle;
  347. if (advertScrollViewStyle == SGAdvertScrollViewStyleMore) {
  348. _advertScrollViewStyle = SGAdvertScrollViewStyleMore;
  349. [_collectionView registerClass:[SGAdvertScrollViewMoreCell class] forCellWithReuseIdentifier:advertScrollViewMoreCell];
  350. }
  351. }
  352. - (void)setSignImages:(NSArray *)signImages {
  353. _signImages = signImages;
  354. if (signImages) {
  355. self.imageArr = [NSArray arrayWithArray:signImages];
  356. }
  357. }
  358. - (void)setTitles:(NSArray *)titles {
  359. _titles = titles;
  360. if (titles.count > 1) {
  361. [self addTimer];
  362. } else {
  363. [self removeTimer];
  364. }
  365. self.titleArr = [NSArray arrayWithArray:titles];
  366. [self.collectionView reloadData];
  367. }
  368. - (void)setTitleFont:(UIFont *)titleFont {
  369. _titleFont = titleFont;
  370. }
  371. - (void)setTextAlignment:(NSTextAlignment)textAlignment {
  372. _textAlignment = textAlignment;
  373. }
  374. - (void)setTopSignImages:(NSArray *)topSignImages {
  375. _topSignImages = topSignImages;
  376. if (topSignImages) {
  377. self.imageArr = [NSArray arrayWithArray:topSignImages];
  378. }
  379. }
  380. - (void)setTopTitles:(NSArray *)topTitles {
  381. _topTitles = topTitles;
  382. if (topTitles.count > 1) {
  383. [self addTimer];
  384. } else {
  385. [self removeTimer];
  386. }
  387. self.titleArr = [NSArray arrayWithArray:topTitles];
  388. [self.collectionView reloadData];
  389. }
  390. - (void)setBottomSignImages:(NSArray *)bottomSignImages {
  391. _bottomSignImages = bottomSignImages;
  392. if (bottomSignImages) {
  393. self.bottomImageArr = [NSArray arrayWithArray:bottomSignImages];
  394. }
  395. }
  396. - (void)setBottomTitles:(NSArray *)bottomTitles {
  397. _bottomTitles = bottomTitles;
  398. if (bottomTitles) {
  399. self.bottomTitleArr = [NSArray arrayWithArray:bottomTitles];
  400. }
  401. }
  402. - (void)setScrollTimeInterval:(CFTimeInterval)scrollTimeInterval {
  403. _scrollTimeInterval = scrollTimeInterval;
  404. if (scrollTimeInterval) {
  405. [self addTimer];
  406. }
  407. }
  408. @end