iOS 封裝跑馬燈和輪播效果

代碼地址以下:
http://www.demodashi.com/demo/14075.htmlhtml

功能概述和預覽

iOS UICollectionView實現跑馬燈和輪播效果.gif

功能描述:WSL_RollView 是基於UICollectionView實現的支持水平和垂直兩個方向上的的分頁和漸進循環輪播效果,能夠設置時間間隔、漸進速率、是否循環、分頁寬度和間隔,還支持高度自定義分頁視圖的控件。ide

1、實現方法

1.一、 首先用UICollectionView和計時器實現一個基本的水平滾動效果,以下圖,這個太簡單就不在此詳述。

iOS UICollectionView

1.二、對比上面的效果圖,咱們還須要解決分頁的寬度和循環滾動的問題。

  • 自定義分頁寬度:默認的分頁寬度是UICollectionView的寬度,因此當分頁寬度的不等於UICollectionView的寬度或分頁間隔不等於0時會出現錯誤,這時就須要咱們經過自定義UICollectionViewFlowLayout來實現效果。
/** 返回值決定了collectionView中止滾動時的偏移量 手指鬆開後執行
 * proposedContentOffset:本來狀況下,collectionView中止滾動時最終的偏移量
 * velocity 滾動速率,經過這個參數能夠了解滾動的方向
 */
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{
    
    if (_scrollStyle == WSLRollViewScrollStylePage) {
        CGSize size = self.collectionView.frame.size;
        // 計算可見區域的面積
        CGRect rect = CGRectMake(proposedContentOffset.x, proposedContentOffset.y, size.width, size.height);
        NSArray *array = [super layoutAttributesForElementsInRect:rect];
        // 標記 cell 的中點與 UICollectionView 中點最小的間距
        CGFloat minDetal = MAXFLOAT;
        
        if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal){
            // 計算 CollectionView 中點值
            CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;
            for (UICollectionViewLayoutAttributes *attrs in array){
                if (ABS(minDetal) > ABS(centerX - attrs.center.x)){
                    minDetal = attrs.center.x - centerX;
                }
            }
            return CGPointMake(proposedContentOffset.x + minDetal, proposedContentOffset.y);
        }else{
            // 計算 CollectionView 中點值
            CGFloat centerY = proposedContentOffset.y + self.collectionView.frame.size.height * 0.5;
            for (UICollectionViewLayoutAttributes *attrs in array){
                if (ABS(minDetal) > ABS(centerY - attrs.center.y)){
                    minDetal = attrs.center.y - centerY;
                }
            }
            return CGPointMake(proposedContentOffset.x, proposedContentOffset.y + minDetal);
        }
    }
    return proposedContentOffset;
}
  • 循環滾動:思想固然仍是3 >4 >0 >1 >2 >3 >4 >0 >1,關鍵就在於怎麼肯定彌補兩端輪播首尾相連須要增長的cell,前邊尾首相連須要UICollectionView可見範圍內的數據源後邊的元素cell,後邊首尾相連須要UICollectionView可見範圍內的數據源前邊的元素cell
//獲取首尾相連循環滾動時須要用到的元素,並重組數據源
- (void)resetDataSourceForLoop{
    if(_loopEnabled == NO){
        return;
    }
    if(_scrollDirection == UICollectionViewScrollDirectionHorizontal && _collectionView.contentSize.width >= self.frame.size.width){
        //用於右側鏈接元素數量
        _addRightCount = [_collectionView  indexPathForItemAtPoint:CGPointMake(self.frame.size.width - 1, 0)].row + 1 ;
        if (_scrollStyle == WSLRollViewScrollStylePage){
            //若是是分頁,還須要用於左側鏈接元素數量
            _addLeftCount = _sourceArray.count - [_collectionView  indexPathForItemAtPoint:CGPointMake(_collectionView.contentSize.width - self.frame.size.width + 1, 0)].row;
        }
    }else if(_scrollDirection == UICollectionViewScrollDirectionVertical && _collectionView.contentSize.height >= self.frame.size.height){
        //用於右側鏈接元素數量
        _addRightCount = [_collectionView  indexPathForItemAtPoint:CGPointMake(0, self.frame.size.height - 1)].row + 1 ;
        if (_scrollStyle == WSLRollViewScrollStylePage){
            //用於左側鏈接元素數量
            _addLeftCount = _sourceArray.count - [_collectionView  indexPathForItemAtPoint:CGPointMake(0, _collectionView.contentSize.height - self.frame.size.height + 1)].row;
        }
    }
    NSArray * rightSubArray = [_sourceArray subarrayWithRange:NSMakeRange(0, _addRightCount)];
    //增長右側鏈接元素
    [_dataSource addObjectsFromArray:rightSubArray];
    
    if (_scrollStyle == WSLRollViewScrollStylePage){
        NSArray * leftSubArray = [_sourceArray subarrayWithRange:NSMakeRange(_sourceArray.count - _addLeftCount, _addLeftCount)];
        //增長左側鏈接元素
        [_dataSource insertObjects:leftSubArray atIndexes: [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,_addLeftCount)]];
    }
}

2、WSL_RollView用法

請看WSLRollView.h文件中的註釋,屬性和用法很明朗,詳情和效果能夠看代碼。oop

//
//  WSLRollView.h
//  WSL_RollView
//
//  Created by 王雙龍 on 2018/9/8.
//  Copyright © 2018年 https://www.jianshu.com/u/e15d1f644bea. All rights reserved.
//

#import <UIKit/UIKit.h>

/**
 默認cell樣式 WSLItemID
 */
@interface WSLRollViewCell : UICollectionViewCell
@end

@class WSLRollView;

//代理協議
@protocol WSLRollViewDelegate <NSObject>
@optional
/**
 返回itemSize 默認值是CGSizeMake(self.frame.size.width, self.frame.size.height);
 */
- (CGSize)rollView:(WSLRollView *)rollView sizeForItemAtIndex:(NSInteger)index;
/**
 item的間隔 默認值0
 */
- (CGFloat)spaceOfItemInRollView:(WSLRollView *)rollView;
/**
 內邊距 上 左 下 右 默認值UIEdgeInsetsMake(0, 0, 0, 0)
 */
- (UIEdgeInsets)paddingOfRollView:(WSLRollView *)rollView;
/**
 點擊事件
 */
- (void)rollView:(WSLRollView *)rollView didSelectItemAtIndex:(NSInteger)index;
/**
 自定義item樣式
 */
- (WSLRollViewCell *)rollView:(WSLRollView *)rollView cellForItemAtIndex:(NSInteger )index;
@end

/**
 滾動樣式
 */
typedef NS_ENUM(NSInteger, WSLRollViewScrollStyle) {
    WSLRollViewScrollStylePage = 0, /** 分頁 必須等寬或高*/
    WSLRollViewScrollStyleStep   /** 漸進 能夠不等寬或高*/
};

@interface WSLRollView : UIView

/**
 原始數據源
 */
@property (nonatomic, strong) NSMutableArray * sourceArray;

/**
 是否循環輪播 默認YES
 */
@property (nonatomic, assign) BOOL loopEnabled;

/**
 輪播方向 默認是 UICollectionViewScrollDirectionHorizontal 水平
 */
@property (nonatomic, assign) UICollectionViewScrollDirection scrollDirection;

/**
 輪播樣式 默認是 WSLRollViewScrollStylePage 分頁
 */
@property (nonatomic, assign) WSLRollViewScrollStyle scrollStyle;

/**
 漸進輪播速率 單位是Point/s,以座標系單位爲準 默認60/s 若是爲0 表示禁止計時器
 */
@property (nonatomic, assign) CGFloat speed;
/**
 分頁輪播間隔時長 單位是s  默認3s 若是爲0 表示禁止計時器
 */
@property (nonatomic, assign) CGFloat interval;

/**
 item的間隔 默認值0
 */
@property (nonatomic, assign) CGFloat spaceOfItem;

/**
 內邊距 上 左 下 右 默認值UIEdgeInsetsMake(0, 0, 0, 0)
 */
@property (nonatomic, assign) UIEdgeInsets padding;

/** delegate*/
@property (nonatomic, weak) id<WSLRollViewDelegate> delegate;

/**
  初始化方法 direction 滾動方向
 */
- (instancetype)initWithFrame:(CGRect)frame scrollDirection:(UICollectionViewScrollDirection)direction;

/**
 註冊item樣式 用法和UICollectionView類似
 */
- (void)registerClass:(nullable Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
/**
 註冊item樣式 用法和UICollectionView類似
 */
- (void)registerNib:(nullable UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
/**
 用於初始化和獲取WSLRollViewCell,自定義cell樣式 用法和UICollectionView類似
 */
- (WSLRollViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index;
/**
 刷新數據源
 */
- (void)reloadData;
/**
 暫停自動輪播
 */
- (void)pause;
/**
 繼續自動輪播
 */
- (void)play;
/**
 釋放計時器 必須執行,防止內存暴漲
 */
- (void)close;
@end

3、項目結構

以上就是我實現這個效果的過程;若是小夥伴們有其餘的實現方法,歡迎再此留言交流😊😊😀😀🤗🤗ui

😁😁iOS 封裝跑馬燈和輪播效果atom

代碼地址以下:
http://www.demodashi.com/demo/14075.htmlspa

注:本文著做權歸做者,由demo大師代發,拒絕轉載,轉載須要做者受權代理

相關文章
相關標籤/搜索