適用於圖片數量固定、無需複雜交互的場景(如詳情頁圖集)。
- (void)setupImageScrollViewWithImages:(NSArray *)images {
// 1. 配置 ScrollView
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.scrollView.showsVerticalScrollIndicator = NO;
self.scrollView.delegate = self;
[self.view addSubview:self.scrollView];
// 2. 批量添加 UIImageView
CGFloat yOffset = 0;
const CGFloat padding = 8.0f;
const CGFloat imageWidth = self.view.bounds.size.width - 2 * padding;
for (UIImage *image in images) {
// 等比縮放計算高度
CGFloat aspectRatio = image.size.height / image.size.width;
CGFloat imageHeight = imageWidth * aspectRatio;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:
CGRectMake(padding, yOffset + padding, imageWidth, imageHeight)];
imageView.image = image;
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = YES;
[self.scrollView addSubview:imageView];
yOffset += imageHeight + padding;
}
// 3. 設置 contentSize 啟用滾動
self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, yOffset + padding);
}
scrollViewDidEndDecelerating 中重置偏移量@interface BannerScrollView : UIScrollView
@property (nonatomic, strong) NSArray *images;
@property (nonatomic, strong) NSTimer *autoScrollTimer;
@property (nonatomic, assign) NSInteger currentPage;
@end
@implementation BannerScrollView
- (void)configureWithImages:(NSArray *)images {
self.images = images;
self.pagingEnabled = YES;
self.showsHorizontalScrollIndicator = NO;
self.delegate = self;
// 擴展數據源:尾部加首圖,首部加尾圖
NSMutableArray *extended = [images mutableCopy];
[extended insertObject:images.lastObject atIndex:0];
[extended addObject:images.firstObject];
CGFloat width = self.bounds.size.width;
for (NSInteger i = 0; i < extended.count; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(i * width, 0, width, self.bounds.size.height)];
iv.image = extended[i];
iv.contentMode = UIViewContentModeScaleAspectFill;
iv.clipsToBounds = YES;
[self addSubview:iv];
}
self.contentSize = CGSizeMake(extended.count * width, self.bounds.size.height);
self.contentOffset = CGPointMake(width, 0); // 初始顯示真實第一張
self.currentPage = 0;
[self startAutoScroll];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSInteger page = (NSInteger)(scrollView.contentOffset.x / scrollView.bounds.size.width);
NSInteger realCount = self.images.count;
// 邊界校正實現無限循環
if (page == 0) {
scrollView.contentOffset = CGPointMake(realCount * scrollView.bounds.size.width, 0);
self.currentPage = realCount - 1;
} else if (page == realCount + 1) {
scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
self.currentPage = 0;
} else {
self.currentPage = page - 1;
}
[self updatePageControl];
}
- (void)startAutoScroll {
[self stopAutoScroll];
self.autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:3.0
target:self selector:@selector(autoScroll) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.autoScrollTimer forMode:NSRunLoopCommonModes];
}
- (void)autoScroll {
CGPoint next = CGPointMake(self.contentOffset.x + self.bounds.size.width, 0);
[self setContentOffset:next animated:YES];
}
@end
| 優化點 | 方案 | 收益 |
|---|---|---|
| 圖片解碼 | 後台線程 ImageIO 漸進式解碼 | 主線程不阻塞 |
| 內存佔用 | SDWebImage/Kingfisher 磁盤+內存雙級緩存 | 避免重複下載解碼 |
| 佈局計算 | 預計算 frame 避免 AutoLayout 開銷 | 滾動 60fps 保障 |
| 大圖處理 | CATiledLayer 分塊渲染 / UIImageView+Zoom | 支持縮放查看原圖 |
FSPagerView、SDCycleScrollView、CHIPageControl