对于图片的无限滚动播放想必大家应该可以找到很多轮子或者自己也能写出一个,那么为什么我还要在这里写呢,其实也没啥可以指出的要点,只是个人每天想写点东西罢了,低调路过。
实现无限滚动的思路我个人认为主要有两种,一种是采用UICollectionView给定一定数量的Item,然后当用户不断的滚动的时候有足够空间展示图片,当用户停止滚动了就马上返回之前的中点,这样相当于有重置了Item的下标,造成无限滚动的效果。
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
NSInteger index = scrollView.contentOffset.x / scrollView.frame.size.width;
// 设置的Item个数 加上 需要展示的图片数 等于距离中心点偏离的个数
NSInteger item = (ItemCount / 2) + (index % 5);
// 回滚到初始的中点位置
[((UICollectionView *)scrollView) scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:item inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}
另外一种是利用UIScrollView来实现,在ScrollView添加内容视图控件,有人用两个,也有人用三个。这种方法核心就是判断用户滚动的方向,然后迅速的把移除屏幕的视图摆放到准备显示的那边屏幕。本人这个项目是采用添加三个内容视图,另外本项目自带了SDWebImage,实现自动加载网络的图片,如果你的项目有这个三方的话,可以自行删除,GitHub,网络原因还在上传,如果看到代码,请自行忽略。
其核心代码如下:
#pragma mark - <UIScrollViewDelegate>
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// 找出显示在最中间的imageView
UIImageView *middleImageView = nil;
// x值和偏移量x的最小差值
CGFloat minDelta = MAXFLOAT;
for (NSInteger i = 0; i < LXImageViewCount; i++) {
UIImageView *imageView = self.scrollView.subviews[i];
// x值和偏移量x差值最小的imageView,就是显示在最中间的imageView
CGFloat currentDelta = 0;
if (self.scrollDirection == LXCyclicScrollDirectionHorizontal) {
currentDelta = ABS(imageView.frame.origin.x - self.scrollView.contentOffset.x);
} else {
currentDelta = ABS(imageView.frame.origin.y - self.scrollView.contentOffset.y);
}
if (currentDelta < minDelta) {
minDelta = currentDelta;
middleImageView = imageView;
}
}
self.pageControl.currentPage = middleImageView.tag;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
// 更新图片内容和scrollView的偏移量
[self updateContentAndOffset];
}
/**
* 更新图片内容和scrollView的偏移量
*/
- (void)updateContentAndOffset
{
// 1.更新imageView上面的图片内容
for (NSInteger i = 0; i < LXImageViewCount; i++) { // i是用来获取imageView的
UIImageView *imageView = self.scrollView.subviews[i];
// 根据当前页码求出imageIndex
NSInteger imageIndex = 0;
if (i == 0) { // 左边
imageIndex = self.pageControl.currentPage - 1;
if (imageIndex == -1) { // 显示最后面一张
imageIndex = self.images.count - 1;
}
} else if (i == 1) { // 中间
imageIndex = self.pageControl.currentPage;
} else if (i == 2) { // 右边
imageIndex = self.pageControl.currentPage + 1;
if (imageIndex == self.images.count) { // 显示最前面一张
imageIndex = 0;
}
}
imageView.tag = imageIndex;
// 图片数据 考虑到无论传递什么参数都能加载到图片
id obj = self.images[imageIndex];
if ([obj isKindOfClass:[UIImage class]]) { // UIImage对象
imageView.image = obj;
} else if ([obj isKindOfClass:[NSString class]]) { // 本地图片名
imageView.image = [UIImage imageNamed:obj];
} else if ([obj isKindOfClass:[NSURL class]]) { // 远程图片URL
[imageView sd_setImageWithURL:obj placeholderImage:self.placeholder];
}
}
// 2.设置scrollView.contentOffset.x = 1倍宽度
if (self.scrollDirection == LXCyclicScrollDirectionHorizontal) {
self.scrollView.contentOffset = CGPointMake(self.scrollView.frame.size.width, 0);
} else {
self.scrollView.contentOffset = CGPointMake(0, self.scrollView.frame.size.height);
}
}
再来看看头文件,我提供了一下这些参数可以调整滚动器
@class LXCyclicScrollView;
@protocol LXCyclicScrollViewDelegate <NSObject>
@optional
- (void)cyclicScrollView:(LXCyclicScrollView *)cisylicScrollView didClickImageAtIndex:(NSInteger)index;
@end
typedef NS_ENUM(NSInteger, LXCyclicScrollDirection) {
/** 左右滑动 */
LXCyclicScrollDirectionHorizontal = 0,
/** 上下滑动 */
LXCyclicScrollDirectionVertical
};
@interface LXCyclicScrollView : UIView
/** 图片数据(里面可以存放UIImage对象、NSString对象【本地图片名】、NSURL对象【远程图片的URL】) */
@property (nonatomic, strong) NSArray *images;
/** 占位图片 */
@property (nonatomic, strong) UIImage *placeholder;
/** 每张图片之间的时间间隔 */
@property (nonatomic, assign) NSTimeInterval interval;
/** 可以修改页码控制器的颜色等 */
@property (nonatomic, weak, readonly) UIPageControl *pageControl;
/** 图片滚动的方向 */
@property (nonatomic, assign) LXCyclicScrollDirection scrollDirection;
/** 代理 */
@property (nonatomic, weak) id<LXCyclicScrollViewDelegate> delegate;
@end