Demo address (cocopods support)

Blog portal

Why repeat the wheel?

Because most banners are seamless scrolling, with card scaling effect and no PageControl, and PageControl style does not support customization, so according to their own project needs and UI needs, built a wheel, hope to share it can be helpful to everyone, if it is useful to click a star

The principle of analysis

UICollectionView infinite rotation, there are many online demo is the use of array copy 100 copies, even 1000 copies, using cell reuse mechanism, to achieve"Infinite rotation"This kind of plan is too simple and crude, of course it is very practical. I did it in a different wayCopy the code
  • The principle of infinite rotation

    • Seamless rotation chart

      Principle is very simple, such as have an array @ [@ “1,” @ “2,” @ “3”], seamless shuffling is a copy of the first element in the array into the tail element, end element along with a copy of the first element, namely @ [@ “3,” @ “1”, “@” 2, “@” 3, “@” 1 “); So just assignment, the current position of the array subscript is 1, which is @ “1”, scroll to the left, when the scroll to subscript 4 @ “1”, namely let its collectionView. ContentOffset. No animation back to subscript 1 x @ (interface without awareness) on “1”; Similarly, scroll to the right, scroll to 0 at sign “3”, go back to 3 at sign “3”;

    • Have clearance and amplification effect by the above figure, just because the amplification effect, can see around the edge of two cell show, so become @ [@ “2,” @ “3,” @ “1”, “@” 2, “@” 3, “@” 1, “@” 2 “); If I scroll to the left, subscript 5 which is at sign “1” becomes subscript 2 which is at sign “1”; If I scroll to the right, subscript 1 which is at sign 3 becomes subscript 4 which is at sign 3

      Then the rest is the offset calculation, paste core code

      
      #pragma mark UIScrollViewDelegate
      - (void)scrollViewDidScroll:(UIScrollView *)scrollView
      {
      [self scrollViewBorderJudge];
      }
      - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
      {
      if ([self scrollViewBorderJudge]) {
         [self handCellSeleceLocation];
      }
      }
      - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
      {
      if (self.autoScroll) {
         [self invalidateTimer];
      }
      }
      - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
      {
      if(! Activity) {// Don't decelerateif([self scrollViewBorderJudge]) { [self handCellSeleceLocation]; }}if(self.autoScroll) { [self createTimer]; }}Pragma marks boundaries and cell position handling_datAIMgs. count > 0 - (BOOL)scrollViewBorderJudge {if (_dataImgs.count > 0) {
         if(_collectionView. ContentOffset. X < = 1 - BannerOffsetleft BannerOffsetWidth *) {/ / on the left side of the border (positive) the second - > the third from bottom _collectionView.contentOffset = CGPointMake(BannerOffsetWidth*(_dataImgs.count-3)-BannerOffsetleft, 0); _selectedIndex = _dataImgs.count-5; _pageControl.currentPage = _selectedIndex;return NO;
         } else if(_collectionView. ContentOffset. X > = BannerOffsetWidth * (_dataImgs. Count - 2) - BannerOffsetleft) {/ / right boundary (the last but one) - > positive third _collectionView.contentOffset = CGPointMake(BannerOffsetWidth*2-BannerOffsetleft, 0); _selectedIndex = 0; _pageControl.currentPage = _selectedIndex;return NO;
         }
         return YES;
      }
      returnNO; } // Scroll to stop making sure cell is in the middle - (void)handCellSeleceLocation {CGFloat OffsetIndex = (_collectionView.contentOffset.x+_line+_showLine)/BannerOffsetWidth; NSInteger index = (NSInteger)((_collectionView.contentOffset.x+_line+_showLine)/BannerOffsetWidth);if ((NSInteger)(OffsetIndex*100)%100 <= 50) {
            [_collectionView setContentOffset: CGPointMake (0.0) index - BannerOffsetleft BannerOffsetWidth * and animated: YES]; _selectedIndex = index-2; }else {
         [_collectionView setContentOffset: CGPointMake (BannerOffsetWidth * (index + 1) - BannerOffsetleft, 0.0) animated: YES]; _selectedIndex = index-1; } _pageControl.currentPage = _selectedIndex; }Copy the code
  • Cell card magnification effect

    Inheritance UICollectionViewFlowLayout, rewrite layoutAttributesForElementsInRect: method, according to the offset calculation, 3 d rotation animation;

    / / allows you to update the position, and you don't write this if a loop inside card is more and more small, the last cycle ends start next cycle, such as cell replacement size - (BOOL) shouldInvalidateLayoutForBoundsChange: (CGRect) oldBounds {returnYES; } - (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect { NSArray* array = [super layoutAttributesForElementsInRect:rect]; CGRect visibleRect; visibleRect.origin = self.collectionView.contentOffset; visibleRect.size = self.collectionView.bounds.size; [array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UICollectionViewLayoutAttributes* attributes = (UICollectionViewLayoutAttributes *)obj;  CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;  CGFloat normalizedDistance = ABS(distance/BannerOffsetWidth); CGFloat zoom = 1 - ZoomFactor*normalizedDistance; Attributes. Transform3D = CATransform3DMakeScale(1.0, zoom, 1.0); attributes.return array;
      }
    
    Copy the code
    • Custom pageControl

    Inherit UIPageControl, rewrite layoutSubviews method, calculate the distance between dots, dot size, cut corners; You can also make custom images if you like

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    self.userInteractionEnabled = NO;
    
    CGFloat allW = (self.subviews.count - 1)*(PageW+PageLine)+CurrentW;
    CGFloat originX = self.frame.size.width/2-allW/2;
    for (int i = 0; i < self.subviews.count; i++) {
        UIView *view = self.subviews[i];
        if(I == self.currentPage) {// currentPage view.frame = CGRectMake(originX+ I *(PageW+PageLine), view.frame.origin. CurrentH); }else if (i > self.currentPage) {
                view.frame = CGRectMake(originX+ i * (PageW+PageLine)+(CurrentW-PageW), view.frame.origin.y, PageW, PageH);
        } else{ view.frame = CGRectMake(originX+ i * (PageW+PageLine), view.frame.origin.y, PageW, PageH); } view.layer.cornerRadius = 1; view.layer.masksToBounds = YES; }}Copy the code

conclusion

  • If it is useful, I hope you can give me a thumbs-up and go.
  • There are bugs or other problems, also hope to issue or send email