1 #import <UIKit/UIKit.h> 2 3 typedef void(^Click)(NSInteger index); 4 5 typedef void(^Sliding)(NSInteger index); 6 7 typedef NS_ENUM(NSInteger, SLRoateViewStyle) { 8 SLRoateViewStyleAutomaticCarousel, // 没有自动轮播没有手动轮播 9 SLRoateViewStyleAllowCarousel, // 没有自动轮播可以手动轮播 10 SLRoateViewStyleDefault // 自动轮播手动轮播都有 11 }; 12 13 @interface SLRoateView : UIScrollView 14 15 // 是否支持点击 只需判断block 是否为空 为空则不添加手势 16 //@property(nonatomic, assign)BOOL SupportInteraction; 17 18 // pageControl 可设置 添加pageControl需在外面添加 19 @property(nonatomic, strong)UIPageControl *pageControl; 20 21 // 创建 frame 显示在屏幕什么位置 style以什么形式运作 array可装URL 可装data 这个自己在pageView里实现的 block 是点击传值 22 + (SLRoateView *)roateViewWithFrame:(CGRect)frame style:(SLRoateViewStyle)style array:(NSArray *)array click:(Click)click; 23 24 //- (instancetype)initWithFrame:(CGRect)frame style:(SLRoateViewStyle)style array:(NSArray *)array click:(Click)click; 25 26 - (void)registerClass:(nullable Class)pageClass; 27 28 @end
1 #import "SLRoateView.h" 2 #import <objc/objc-runtime.h> 3 #import "SLRoatePage.h" 4 5 @interface SLRoateView ()<UIScrollViewDelegate> 6 { 7 SLRoatePage *leftView; 8 SLRoatePage *centerView; 9 SLRoatePage *rightView; 10 } 11 12 @property(nonatomic, strong)NSArray *array; 13 @property(nonatomic, copy)Click click; 14 @property(nonatomic, assign)CGFloat KRoateWidth; 15 @property(nonatomic, assign)CGFloat KRoateHeight; 16 @property(nonatomic, assign)NSInteger index; 17 @property(nonatomic, strong)NSTimer *timer; 18 @property(nonatomic, copy)Sliding sliding; 19 @property(nonatomic, assign)NSInteger style; 20 // 记录开始拖拽的时候的offset 21 @property(nonatomic, assign)NSInteger offsetX; 22 23 24 @end 25 26 @implementation SLRoateView 27 28 +(SLRoateView *)roateViewWithFrame:(CGRect)frame style:(SLRoateViewStyle)style array:(NSArray *)array click:(Click)click 29 { 30 return [[SLRoateView alloc]initWithFrame:frame style:style array:array click:click]; 31 } 32 33 - (instancetype)initWithFrame:(CGRect)frame style:(SLRoateViewStyle)style array:(NSArray *)array click:(Click)click 34 { 35 self = [super initWithFrame:frame]; 36 if (self) 37 { 38 self.KRoateWidth = frame.size.width; 39 self.KRoateHeight = frame.size.height; 40 self.array = array; 41 self.click = click; 42 // scrollVeiw 设置 43 self.contentSize = CGSizeMake(_KRoateWidth * 3, 0); 44 self.pagingEnabled = YES; 45 self.alwaysBounceVertical = NO; 46 self.showsVerticalScrollIndicator = NO; 47 self.alwaysBounceHorizontal = YES; 48 self.showsHorizontalScrollIndicator = NO; 49 self.delegate = self; 50 51 [self addPageControl]; 52 // 设置不同模式下的功能 53 [self operationModeWithStyle:style]; 54 55 // 如果block不为空 则添加手势 56 if (click != nil) 57 { 58 [self addGestureRecognizer]; 59 } 60 61 } 62 return self; 63 } 64 65 #pragma mark 判断当前view在那种模式下运行 66 - (void)operationModeWithStyle:(SLRoateViewStyle)style 67 { 68 _style = style; 69 if (style == SLRoateViewStyleDefault) 70 { 71 // 可手动、可自动轮播 72 self.contentOffset = CGPointMake(_KRoateWidth, 0); 73 [self addTimer]; 74 // [self addPageControl]; 75 } 76 else if (style == SLRoateViewStyleAllowCarousel) 77 { 78 // 可手动轮播 79 self.contentOffset = CGPointMake(_KRoateWidth, 0); 80 } 81 else if (style == SLRoateViewStyleAutomaticCarousel) 82 { 83 // 不可轮播 84 self.contentOffset = CGPointMake(0, 0); 85 } 86 [self addPageControl]; 87 } 88 89 #pragma mark 添加计时器 90 - (void)addTimer 91 { 92 // 在子线程中创建一个计时器 是图片实现轮播 93 dispatch_async(dispatch_get_global_queue(0, 0), ^{ 94 _timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(rotaView) userInfo:nil repeats:YES]; 95 [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; 96 97 [[NSRunLoop currentRunLoop] run]; 98 99 }); 100 } 101 102 - (void)rotaView 103 { 104 [self setContentOffset:CGPointMake(_KRoateWidth * 2, 0) animated:YES]; 105 NSLog(@"%ld", _index); 106 // 设置分页 由于动画是从中间移动到第三张 所以pageControl要显示的不是中间图片而是第三张图片 107 _pageControl.currentPage = (_index + 1) % _array.count; 108 if (self.contentOffset.x/_KRoateWidth == 2) 109 { 110 [self reloadData]; 111 // scrollView 回到中间 112 [self setContentOffset:CGPointMake(_KRoateWidth, 0) animated:NO]; 113 } 114 } 115 116 #pragma mark 添加点击事件 117 - (void)addGestureRecognizer 118 { 119 [self addGestureRecognizer:[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapGestureRecognizer)]]; 120 } 121 122 - (void)tapGestureRecognizer 123 { 124 if (_click) 125 { 126 // 用当前的 127 self.click(_pageControl.currentPage); 128 } 129 130 } 131 132 #pragma mark 注册一个pageVeiw放在scroll上 133 - (void)registerClass:(Class)pageClass 134 { 135 objc_registerClassPair(pageClass); 136 leftView = [[pageClass alloc] initWithFrame:CGRectMake(0, 0, _KRoateWidth, _KRoateHeight)]; 137 [self addSubview:leftView]; 138 139 centerView = [[pageClass alloc] initWithFrame:CGRectMake(_KRoateWidth, 0, _KRoateWidth, _KRoateHeight)]; 140 [self addSubview:centerView]; 141 142 rightView = [[pageClass alloc] initWithFrame:CGRectMake(_KRoateWidth * 2, 0, _KRoateWidth, _KRoateHeight)]; 143 [self addSubview:rightView]; 144 145 [self setDefautData]; 146 } 147 148 #pragma mark 设置默认显示page 149 - (void)setDefautData 150 { 151 NSInteger leftIndex, index, rightIndex; 152 if (_style == SLRoateViewStyleAutomaticCarousel) 153 { 154 leftIndex = 0; 155 index = 1; 156 rightIndex = 2; 157 } 158 else 159 { 160 leftIndex = _array.count - 1; 161 index = 0; 162 rightIndex = 1; 163 } 164 [leftView performSelector:@selector(loadDataWith:) withObject:_array[leftIndex]]; 165 [centerView performSelector:@selector(loadDataWith:) withObject:_array[index]]; 166 [rightView performSelector:@selector(loadDataWith:) withObject:_array[rightIndex]]; 167 _index = 0; 168 _pageControl.currentPage = _index; 169 } 170 171 #pragma mark 添加分页控件 172 - (void)addPageControl 173 { 174 // 根据页数放回UIPageControl合适的大小 返回(0,0)不知道为啥 ----先要创建出来再给frame 175 _pageControl = [[UIPageControl alloc]init]; 176 CGSize size = [_pageControl sizeForNumberOfPages:_array.count]; 177 _pageControl.frame = CGRectMake(0, 0, size.width, size.height); 178 _pageControl.center = CGPointMake(_KRoateWidth / 2, _KRoateHeight - size.height/2); 179 _pageControl.numberOfPages = _array.count; 180 [self.window addSubview:_pageControl]; 181 } 182 183 #pragma mark 重新加载图片 184 - (void)reloadData 185 { 186 NSInteger leftIndex, rightIndex; 187 CGPoint offset = self.contentOffset; 188 if (offset.x > _KRoateWidth) 189 { 190 _index = (_index + 1) % _array.count; 191 }else if (offset.x < _KRoateWidth) 192 { 193 _index = (_index + _array.count - 1) % _array.count; 194 } 195 [centerView performSelector:@selector(loadDataWith:) withObject:_array[_index]]; 196 197 leftIndex = (_index + _array.count - 1) % _array.count; 198 rightIndex = (_index + 1) % _array.count; 199 [leftView performSelector:@selector(loadDataWith:) withObject:_array[leftIndex]]; 200 [rightView performSelector:@selector(loadDataWith:) withObject:_array[rightIndex]]; 201 } 202 203 #pragma mark 不循环滚动 204 - (void)rollingOnce 205 { 206 NSInteger leftIndex, rightIndex; 207 CGPoint offset = self.contentOffset; 208 if (offset.x == _offsetX) 209 { 210 return; 211 } 212 if (offset.x > _offsetX) 213 { 214 _index = _index + 1; 215 if (_index >= _array.count - 1) 216 { 217 _index = _array.count - 1; 218 return; 219 } 220 }else if (offset.x < _offsetX) 221 { 222 _index = _index - 1; 223 if (_index <= 0) 224 { 225 _index = 0; 226 return; 227 } 228 } 229 leftIndex = _index - 1; 230 rightIndex = _index + 1; 231 [centerView performSelector:@selector(loadDataWith:) withObject:_array[_index]]; 232 233 [leftView performSelector:@selector(loadDataWith:) withObject:_array[leftIndex]]; 234 [rightView performSelector:@selector(loadDataWith:) withObject:_array[rightIndex]]; 235 236 } 237 238 #pragma mark 滚动停止事件 239 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 240 { 241 // 5秒后启动计时器 242 [_timer performSelector:@selector(setFireDate:) withObject:[NSDate distantPast] afterDelay:5]; 243 if (_style != SLRoateViewStyleAutomaticCarousel) 244 { 245 [self reloadData]; 246 // scrollView 回到中间 247 [self setContentOffset:CGPointMake(_KRoateWidth, 0) animated:NO]; 248 } 249 else 250 { 251 [self rollingOnce]; 252 if (_index < _array.count - 1 && _index > 0) 253 { 254 [self setContentOffset:CGPointMake(_KRoateWidth, 0) animated:NO]; 255 } 256 } 257 // 设置分页 258 _pageControl.currentPage = _index; 259 // 添加一个block 传出去index; 260 if (_sliding) 261 { 262 self.sliding(_pageControl.currentPage); 263 } 264 } 265 266 267 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 268 { 269 _offsetX = scrollView.contentOffset.x; 270 if (scrollView.isDragging) 271 { 272 // 取消timer之前的执行请求 273 [NSObject cancelPreviousPerformRequestsWithTarget:_timer]; 274 // 关闭定时器 275 [_timer setFireDate:[NSDate distantFuture]]; 276 277 } 278 } 279 280 281 282 @end
1 #import <UIKit/UIKit.h> 2 3 // 本类用于添加需要盛放在scrollView上的View ,view需在本类的子类创建添加,并且实现代理方法 4 @protocol SLRoateViewPageDataSource <NSObject> 5 // 用于实现数据铺放 6 @required 7 - (void)loadDataWith:(id)data; 8 9 @end 10 11 @interface SLRoatePage : UIView 12 13 @property(nonatomic, weak)id<SLRoateViewPageDataSource> dataSource; 14 15 - (instancetype)initWithFrame:(CGRect)frame; 16 17 @end
#import "SLRoatePage.h" @implementation SLRoatePage -(instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { } return self; } @end
// 运行实例
#import "ViewController.h"
#import "SLRoateView.h"
#import "MyPage.h"
#define Choose @"http://api.liwushuo.com/v2/channels/100/items"
#define Girifriend @"http://api.liwushuo.com/v2/channels/10/items?gender=1&generation=1&limit=20&offset=0"
#define Parents @"http://api.liwushuo.com/v2/channels/6/items?gender=1&generation=1&limit=20&offset=0"
#define GayFriend @"http://api.liwushuo.com/v2/channels/26/items?gender=1&generation=1&limit=20&offset=0"
#define Lesbian @"http://api.liwushuo.com/v2/channels/5/items?gender=1&generation=1&limit=20&offset=0"
#define Fellow @"http://api.liwushuo.com/v2/channels/17/items?gender=1&generation=1&limit=20&offset=0"
#define Heart @"http://api.liwushuo.com/v2/channels/24/items?gender=1&generation=1&limit=20&offset=0"
#define Birthday @"http://api.liwushuo.com/v2/channels/30/items?gender=1&generation=1&limit=20&offset=0"
#define Marry @"http://api.liwushuo.com/v2/channels/33/items?gender=1&generation=1&limit=20&offset=0"
#define Anniversary @"http://api.liwushuo.com/v2/channels/31/items?gender=1&generation=1&limit=20&offset=0"
#define Housewarming @"http://api.liwushuo.com/v2/channels/35/items?gender=1&generation=1&limit=20&offset=0"
#define Thanks @"http://api.liwushuo.com/v2/channels/36/items?gender=1&generation=1&limit=20&offset=0"
#define Knowledge @"http://api.liwushuo.com/v2/channels/120/items?gender=1&generation=1&limit=20&offset=0"
@interface ViewController ()
//@property(nonatomic, strong)UIImageView *imgView;
@property (nonatomic, strong)NSArray *urlArray;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// NSArray *array = @[[UIImage imageNamed:@"1"], [UIImage imageNamed:@"2"], [UIImage imageNamed:@"3"], [UIImage imageNamed:@"4"], [UIImage imageNamed:@"5"]];
_urlArray = @[Choose, Girifriend, Parents, GayFriend, Lesbian, Fellow, Heart, Birthday, Marry, Anniversary, Housewarming, Thanks, Knowledge];
SLRoateView *roateView = [SLRoateView roateViewWithFrame:[[UIScreen mainScreen]bounds] style:(SLRoateViewStyleAutomaticCarousel) array:_urlArray click:nil];
[roateView registerClass:[MyPage class]];
// [roateView registerClass:[UIImageView class]];
//
// _imgView = [[UIImageView alloc]pageWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame))];
// _imgView.dataSource = self;
[self.view addSubview:roateView];
[self.view addSubview:roateView.pageControl];
}
#import "MyPage.h"
#import "RequestManager.h"
#import "GiftModel.h"
#import "GiftTableViewCell.h"
#define KHeight [UIScreen mainScreen].bounds.size.height
@interface MyPage ()<SLRoateViewPageDataSource, UITableViewDelegate, UITableViewDataSource>
@property(nonatomic, strong)UITableView *tableView;
@property(nonatomic, strong)NSArray *array;
@end
@implementation MyPage
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// _imgView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame))];
// self.dataSource = self;
// [self addSubview:_imgView];
_tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame)) style:(UITableViewStyleGrouped)];
_tableView.delegate = self;
_tableView.dataSource = self;
[_tableView registerNib:[UINib nibWithNibName:@"GiftTableViewCell" bundle:nil] forCellReuseIdentifier:@"giftCell"];
[self addSubview:_tableView];
}
return self;
}
- (void)loadDataWith:(id)data
{
// 现在data为 url
NSString *url = (NSString *)data;
[RequestManager requestWithUrl:url requestType:requestTypeGet parDic:nil finish:^(NSData *data) {
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
_array = [GiftModel giftModelConfigureWithDic:dic andIdex:index];
dispatch_async(dispatch_get_main_queue(), ^{
[_tableView reloadData];
});
} error:^(NSError *error) {
NSLog(@"请求错误");
}];
}
#pragma mark --- 返回分区行数 --
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _array.count;
}
#pragma mark --- 返回cell --
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
GiftTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"giftCell" forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.model = _array[indexPath.row];
return cell;
}
#pragma mark --- 返回行高 --
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return KHeight / 4;
}
#pragma mark --- cell点击方法 ---
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// GiftModel *model = _array[indexPath.row];
// GiftWebViewController *webVc = [[GiftWebViewController alloc]init];
// webVc.url = model.url;
// [self.navigationController pushViewController:webVc animated:YES];
}
1.现在的数据形式是每次都需要请求数据 而且一条数据会请求多次 2. 还有一种方法可以直接传Model数组,这样的话就会导致不管用户有没有看完界面,数据都请求下来了,还有最关键的是请求需要时间N条数据一起请求,很耗时间,我的demo传入的是一个数组,要的是一个完整的数据,这样用户的体验会很差 3.可以不传数组用代理方法需要用到数组数据的时候才传进去。 最简单的就是第一种情况下请求一次存储一次,下次需要直接从本地取