iOS无限轮播器框架(UICollectionView实现,添加了UIPageControl)

一、控制器里只需要写下边的代码

#import "ViewController.h"
#import "JWCycleCollectionView.h"
#import "JWPageControl.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建轮播视图
    JWCycleCollectionView *cycleView = [[JWCycleCollectionView alloc] initWithUrlString:@"http://c.m.163.com/nc/ad/headline/0-4.html"];

    cycleView.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 200);

    [self.view addSubview:cycleView];

    // 创建pageControl
    JWPageControl *pageControl = [[JWPageControl alloc] initWithFrame:CGRectMake(cycleView.frame.size.width - 100, cycleView.frame.size.height - 42, 100, 50)];

    [self.view addSubview:pageControl];

    cycleView.pageControl = pageControl;
}

二、加载网络请求的工具类和数据模型

1.工具类

定义一个供外界调用的方法,传入URLString,网络加载到数据后用自定义的block实现回调。

#import "AFHTTPSessionManager.h"

typedef void(^finishBlock)(id result);
@interface WJWNetWorkTool : AFHTTPSessionManager

// 获取单例的方法
+ (instancetype)sharedWJWNetWorkTool;

// 供所有模型调用的方法,模型传进来URLString和回调,当从网络上回来结果之后,~~传给模型
- (void)objectWithURLString:(NSString *)URLString andFinishedBlock:(finishBlock)finishblock;
@end
#import "WJWNetWorkTool.h"

@implementation WJWNetWorkTool

#if DEBUG
static NSString *BaseURLString = @"http://c.m.163.com/";
#else
static NSString *BaseURLString = @"http://xxxxxxxxx/";
#endif


+ (instancetype)sharedWJWNetWorkTool{
    static dispatch_once_t onceToken;
    static WJWNetWorkTool *_instance = nil;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] initWithBaseURL:[NSURL URLWithString:BaseURLString]];

         // 该默认响应方式支持的类型
        _instance.responseSerializer.acceptableContentTypes = [_instance.responseSerializer.acceptableContentTypes setByAddingObject:@"text/html"];

    });


    return _instance;
}

- (void)objectWithURLString:(NSString *)URLString andFinishedBlock:(finishBlock)finishblock{

    // AFN去发送网络请求
    [self GET:URLString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // 通过block传递给模型
        if (finishblock) {
            // NSLog(@"%@",responseObject);

            finishblock(responseObject);
        }

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"error:%@",[error localizedDescription]);
    }];
}
@end

2.数据模型

定义一个供外界调用的方法,传入urlString,调用网络工具类加载数据,加载到数据后在回调的finishblock中将加载到的数据进行字典转模型。此外,定义了completeBlock供回调,将模型数组传递到调用block的位置。

#import <Foundation/Foundation.h>

typedef void(^completeBlock)(NSArray *cyclePictures);
@interface JWCycle : NSObject
/**
 *  标题
 */
@property (nonatomic,copy) NSString *title;
/**
 *  图片地址
 */
@property (nonatomic,copy) NSString *imgsrc;

/**
 *  根据网址加载网络数据
 *
 *  @param urlString     网址
 *  @param completeBlcok 回调的block
 */
+ (void)cylcesWithURLsting:(NSString *)urlString completeBLock:(completeBlock)completeBlcok;
@end
#import "JWCycle.h"
#import "WJWNetWorkTool.h"
@implementation JWCycle
+ (instancetype)cycleWithDict:(NSDictionary *)dict{

    id obj = [[self alloc] init];
    [obj setValuesForKeysWithDictionary:dict];
    return obj;
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key{}

+ (void)cylcesWithURLsting:(NSString *)urlString completeBLock:(completeBlock)completeBlcok{
    [[WJWNetWorkTool sharedWJWNetWorkTool] objectWithURLString:urlString andFinishedBlock:^(id result) {
        NSDictionary *dict = (NSDictionary *)result;
        // NSLog(@"%@",dict);
        NSArray *dictArr = dict[@"headline_ad"];

        NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:dictArr.count];
        [dictArr enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            JWCycle *cycle = [JWCycle cycleWithDict:obj];
            [arrM addObject:cycle];
        }];

        // NSLog(@"%@",arrM);
        if (completeBlcok) {
            completeBlcok(arrM.copy);
        }
    }];
}

二、自定义UICollectionView、UICollectionViewFlowlayout和UICollectionViewCell

1.UICollectionView

定义一个供外界调用地方法,传入URLString,加载图片和title等;另外定义一个pageControl属性,与控制器创建的pageControl进行关联。

#import <UIKit/UIKit.h>
#import "JWPageControl.h"
@interface JWCycleCollectionView : UICollectionView
// 传入加载图片的网址,加载到的数据应包含每张图片的网址以
- (instancetype)initWithUrlString:(NSString *)urlString;
// 分页控制器
@property (nonatomic,weak) JWPageControl *pageControl;
@end
#import "JWCycleCollectionView.h"
#import "JWCycle.h"
#import "JWCycleCollectionViewCell.h"
#import "JWCycleCollectionViewLayout.h"

#define KSectionCount 100
#define KScreenWidth  [UIScreen mainScreen].bounds.size.width
@interface JWCycleCollectionView ()<UICollectionViewDataSource,UICollectionViewDelegate>

// 存储轮播数据模型的数组
@property (nonatomic,strong) NSArray <JWCycle *>*cycles;

// 流布局
@property (weak, nonatomic)  UICollectionViewFlowLayout *flowLayout;

// 定时器
@property (nonatomic,strong) NSTimer *timer;
@end

@implementation JWCycleCollectionView

static NSString * const reuseIdentifier = @"Cell";


- (instancetype)initWithUrlString:(NSString *)urlString{
    self = [super initWithFrame:CGRectZero collectionViewLayout:[[JWCycleCollectionViewLayout alloc] init]];
    if (self) {
        self.dataSource = self;
        self.delegate = self;

        [self registerClass:[JWCycleCollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];

        [self loadDataWithUrlString:urlString];

    }
    return self;
}

- (void)loadDataWithUrlString:(NSString *)urlString{
    __weak typeof(self) weakSelf = self;
    [JWCycle cylcesWithURLsting:urlString completeBLock:^(NSArray *cyclePictures) {
        // NSLog(@"加载到数据了");
        weakSelf.cycles = cyclePictures;

        [weakSelf reloadData];

        // 默认选中中间那一组
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:KSectionCount / 2];
        [weakSelf scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];

        [self timer];

        self.pageControl.cycles = cyclePictures;

    }];
}


#pragma mark <UICollectionViewDataSource>

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
    return KSectionCount;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

    return self.cycles.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    JWCycleCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

    JWCycle *cycle = self.cycles[indexPath.item];

    cell.cycle = cycle;
    return cell;
}

#pragma mark - 定时器
- (NSTimer *)timer{
    if (!_timer) {
        _timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
        // 添加到主运行循环
        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
    }
    return _timer;
}

- (void)nextPage{
    NSIndexPath *indexPath = [[self indexPathsForVisibleItems] lastObject];

    // 中间那组的索引
    NSIndexPath *middleIndexPath = [NSIndexPath indexPathForItem:indexPath.item inSection:(KSectionCount / 2)];
    [self scrollToItemAtIndexPath:middleIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];

    if (middleIndexPath.item != self.cycles.count - 1){
        middleIndexPath = [NSIndexPath indexPathForItem:(indexPath.item +1) inSection:middleIndexPath.section];
    } else{
        middleIndexPath = [NSIndexPath indexPathForItem:0 inSection:middleIndexPath.section+1];
    }

    [self scrollToItemAtIndexPath:middleIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];

}

#pragma mark <UIScrollViewDelegate>
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{

    [self.timer invalidate];
    self.timer = nil;

}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    if (decelerate == NO) { // 没有降速的过程,直接在此方法中去添加定时器
        [self timer];
    }

}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{

    [self timer];


}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    // 确定当前页数及组数
    NSInteger currentPage = self.contentOffset.x / KScreenWidth;
    NSInteger currentPageIndex = currentPage % self.cycles.count;

    self.pageControl.currentPage = currentPageIndex;
}
@end

2.UICollectionViewFlowlayout

在自定义的UICollectionView初始化的时候,将自定义的UICollectionViewflowlayout设置给UICollectionView。

#import "JWCycleCollectionViewLayout.h"

@implementation JWCycleCollectionViewLayout

- (void)prepareLayout{
    [super prepareLayout];
    // 直接利用 collectionView 的属性设置布局
    self.itemSize = self.collectionView.bounds.size;
    self.minimumInteritemSpacing = 0;
    self.minimumLineSpacing = 0;
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;

    self.collectionView.bounces = NO;
    self.collectionView.pagingEnabled = YES;
    self.collectionView.showsHorizontalScrollIndicator = NO;
    self.collectionView.showsVerticalScrollIndicator = NO;
}
@end

3.UICollectionViewCell

重写传入的数据模型的set方法,给cell里的imageView和titileLabel赋值。

#import <UIKit/UIKit.h>
@class JWCycle;
@interface JWCycleCollectionViewCell : UICollectionViewCell
// 轮播数据模型
@property (nonatomic,strong) JWCycle *cycle;
@end
#import "JWCycleCollectionViewCell.h"
#import "Masonry.h"
#import "UIImageView+WebCache.h"
#import "JWCycle.h"



@implementation JWCycleCollectionViewCell{
    UIImageView *_iconView;
    UILabel *_titleLabel;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        //NSLog(@"%@", NSStringFromCGRect(frame));
        _iconView = [[UIImageView alloc] initWithFrame:self.bounds];
        [self.contentView addSubview:_iconView];

        _titleLabel = [[UILabel alloc] init];
        _titleLabel.textColor = [UIColor whiteColor];
        _titleLabel.font = [UIFont systemFontOfSize:15];
        [self.contentView addSubview:_titleLabel];
        [_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.contentView).offset(12);
            make.bottom.equalTo(self.contentView).offset(-10);
        }];
    }
    return self;
}

- (void)setCycle:(JWCycle *)cycle{
    _cycle = cycle;

    [_iconView sd_setImageWithURL:[NSURL URLWithString:cycle.imgsrc]];
    _titleLabel.text = cycle.title;
}

@end

三、UIPageControl

UIPageControl不能直接添加到UICollectionView上,只能添加到控制器的View上。拿到模型数组,并且重写其set方法设置一共显示多少个圆点(多少也)

#import <UIKit/UIKit.h>

@interface JWPageControl : UIPageControl

@property (nonatomic,strong) NSArray *cycles;
@end
#import "JWPageControl.h"

@implementation JWPageControl

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

        // 设置非选中页的圆点颜色
        self.pageIndicatorTintColor = [UIColor redColor];
        // 设置选中页的圆点颜色
        self.currentPageIndicatorTintColor = [UIColor blueColor];

        // 禁止默认的点击功能
        self.enabled = NO;

    }
    return self;
}

- (void)setCycles:(NSArray *)cycles{
    _cycles = cycles;
    self.numberOfPages = cycles.count; // 一共显示多少个圆点(多少页)
}
@end
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 `UICollectionView` 或 `UIPageViewController` 来实现 iOS 图片轮。 使用 `UICollectionView` 实现的方法如下: 1. 在您的视图控制中,创建一个 `UICollectionView` 实例,并将其作为子视图添加到您的视图控制的视图中。 2. 使用自定义布局实现循环滚动。可以参考以下代码: ``` class LoopCollectionViewFlowLayout: UICollectionViewFlowLayout { override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { guard let collectionView = collectionView else { return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) } let collectionViewSize = collectionView.bounds.size let proposedContentOffsetCenterX = proposedContentOffset.x + collectionViewSize.width * 0.5 let proposedRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionViewSize.width, height: collectionViewSize.height) guard let layoutAttributes = layoutAttributesForElements(in: proposedRect) else { return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) } let centerX = proposedContentOffsetCenterX let offset = CGPoint(x: proposedContentOffset.x + nearestTargetOffset(for: layoutAttributes, with: centerX), y: proposedContentOffset.y) return offset } private func nearestTargetOffset(for layoutAttributes: [UICollectionViewLayoutAttributes], with centerX: CGFloat) -> CGFloat { let targetAttributes = layoutAttributes.sorted { abs($0.center.x - centerX) < abs($1.center.x - centerX) } let nearestAttribute = targetAttributes.first return nearestAttribute?.center.x ?? 0 - centerX } } ``` 3. 创建自定义 `UICollectionViewCell` 类,并在其中添加一个 `UIImageView` 用于显示图片。 4. 实现 `UICollectionViewDataSource` 协议中的方法,用于设置图片数据源和自定义的 `UICollectionViewCell`。 5. 实现定时

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值