添加图片库、封装

This commit is contained in:
2025-10-29 20:57:45 +08:00
parent e8c88a6148
commit 8ce1d95c8c
9 changed files with 530 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
//
// KBWebImageManager.h
// keyBoard
//
// SDWebImage 的二次封装:全局配置、预取、缓存管理
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface KBWebImageManager : NSObject
/// 预取一组图片
+ (void)prefetchURLs:(NSArray<id> *)urlList
progress:(void(^_Nullable)(NSUInteger finished, NSUInteger total))progress
completed:(void(^_Nullable)(NSUInteger finished, NSUInteger skipped))completed;
/// 异步计算磁盘缓存大小(字节)
+ (void)calculateDiskSize:(void(^)(NSUInteger bytes))completion;
/// 清理内存+磁盘缓存
+ (void)clearAllCache:(void(^_Nullable)(void))completion;
/// 设置全局 HTTP Header如鉴权 Token
+ (void)setHTTPHeaderValue:(nullable NSString *)value forKey:(NSString *)field;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,51 @@
//
// KBWebImageManager.m
// keyBoard
//
#import "KBWebImageManager.h"
#import <SDWebImage/SDWebImage.h>
static inline NSURL *_KBURL(id url) {
if (!url) return nil;
if ([url isKindOfClass:NSURL.class]) return url;
if ([url isKindOfClass:NSString.class]) return [NSURL URLWithString:(NSString *)url];
return nil;
}
@implementation KBWebImageManager
+ (void)prefetchURLs:(NSArray<id> *)urlList
progress:(void(^)(NSUInteger finished, NSUInteger total))progress
completed:(void(^)(NSUInteger finished, NSUInteger skipped))completed {
NSMutableArray<NSURL *> *urls = [NSMutableArray arrayWithCapacity:urlList.count];
for (id u in urlList) { NSURL *nu = _KBURL(u); if (nu) [urls addObject:nu]; }
[[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:urls progress:^(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls) {
if (progress) progress(noOfFinishedUrls, noOfTotalUrls);
} completed:^(NSUInteger finishedCount, NSUInteger skippedCount) {
if (completed) completed(finishedCount, skippedCount);
}];
}
+ (void)calculateDiskSize:(void(^)(NSUInteger bytes))completion {
[[SDImageCache sharedImageCache] calculateSizeWithCompletionBlock:^(NSUInteger fileCount, NSUInteger totalSize) {
if (completion) completion(totalSize);
}];
}
+ (void)clearAllCache:(void(^)(void))completion {
SDImageCache *cache = SDImageCache.sharedImageCache;
[cache clearMemory];
[cache clearDiskOnCompletion:^{ if (completion) completion(); }];
}
+ (void)setHTTPHeaderValue:(NSString *)value forKey:(NSString *)field {
if (value.length == 0) {
[[SDWebImageDownloader sharedDownloader] setValue:nil forHTTPHeaderField:field];
} else {
[[SDWebImageDownloader sharedDownloader] setValue:value forHTTPHeaderField:field];
}
}
@end

View File

@@ -0,0 +1,49 @@
//
// UIImageView+KBWebImage.h
// keyBoard
//
// 在 SDWebImage 基础上的便捷封装:
// - 统一默认 options失败重试、后台续传、降采样等
// - 支持按视图大小缩略解码,减少内存占用
// - 常用形状:普通、圆角、头像圆形
// - 支持占位图、渐隐动画、取消下载
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIImageView (KBWebImage)
/// 简单加载(默认 options自动渐隐
- (void)kb_setImageURL:(nullable id)url placeholder:(nullable UIImage *)placeholder;
/// 自定义 options
- (void)kb_setImageURL:(nullable id)url
placeholder:(nullable UIImage *)placeholder
options:(NSUInteger)options;
/// 按视图大小缩略解码(推荐:内存友好)。若视图尚未布局,可传入 `targetSize` 期望像素尺寸×scale
- (void)kb_setImageURL:(nullable id)url
placeholder:(nullable UIImage *)placeholder
thumbnailToFit:(BOOL)thumbnailToFit
targetSize:(CGSize)targetPixelSize;
/// 圆角图(在解码阶段裁圆角,避免离屏开销)
- (void)kb_setImageURL:(nullable id)url
placeholder:(nullable UIImage *)placeholder
cornerRadius:(CGFloat)radius
corners:(UIRectCorner)corners
borderWidth:(CGFloat)borderWidth
borderColor:(nullable UIColor *)borderColor;
/// 头像:自动按最短边裁成圆形(若视图尚未布局,会使用当前 bounds 估算)
- (void)kb_setAvatarURL:(nullable id)url placeholder:(nullable UIImage *)placeholder;
/// 取消当前图的下载
- (void)kb_cancelImageLoad;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,142 @@
//
// UIImageView+KBWebImage.m
// keyBoard
//
#import "UIImageView+KBWebImage.h"
#import <SDWebImage/SDWebImage.h>
//
static inline SDWebImageOptions KBWebImageDefaultOptions(void) {
return SDWebImageRetryFailed |
SDWebImageContinueInBackground |
SDWebImageHighPriority |
SDWebImageScaleDownLargeImages |
SDWebImageProgressiveLoad; //
}
static inline NSURL *_KBURL(id url) {
if (!url) return nil;
if ([url isKindOfClass:NSURL.class]) return url;
if ([url isKindOfClass:NSString.class]) return [NSURL URLWithString:(NSString *)url];
return nil;
}
@implementation UIImageView (KBWebImage)
- (void)kb_setImageURL:(id)url placeholder:(UIImage *)placeholder {
[self kb_setImageURL:url placeholder:placeholder options:KBWebImageDefaultOptions()];
}
- (void)kb_setImageURL:(id)url placeholder:(UIImage *)placeholder options:(NSUInteger)options {
NSURL *u = _KBURL(url);
//
__weak typeof(self) weakSelf = self;
[self sd_setImageWithURL:u
placeholderImage:placeholder
options:options
progress:nil
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if (!error && image && cacheType == SDImageCacheTypeNone) {
//
weakSelf.alpha = 0.0;
[UIView animateWithDuration:0.25 animations:^{ weakSelf.alpha = 1.0; }];
}
}];
}
- (void)kb_setImageURL:(id)url
placeholder:(UIImage *)placeholder
thumbnailToFit:(BOOL)thumbnailToFit
targetSize:(CGSize)targetPixelSize {
NSURL *u = _KBURL(url);
SDWebImageOptions options = KBWebImageDefaultOptions();
NSMutableDictionary<SDWebImageContextOption, id> *context = [NSMutableDictionary dictionary];
if (thumbnailToFit) {
CGFloat scale = UIScreen.mainScreen.scale;
CGSize size = self.bounds.size;
if (CGSizeEqualToSize(size, CGSizeZero) && !CGSizeEqualToSize(targetPixelSize, CGSizeZero)) {
size = CGSizeMake(targetPixelSize.width/scale, targetPixelSize.height/scale);
}
if (!CGSizeEqualToSize(size, CGSizeZero)) {
CGSize pixelSize = CGSizeMake(size.width * scale, size.height * scale);
context[SDWebImageContextImageThumbnailPixelSize] = @(pixelSize);
}
}
__weak typeof(self) weakSelf = self;
[self sd_setImageWithURL:u
placeholderImage:placeholder
options:options
context:context
progress:nil
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if (!error && image && cacheType == SDImageCacheTypeNone) {
weakSelf.alpha = 0.0;
[UIView animateWithDuration:0.25 animations:^{ weakSelf.alpha = 1.0; }];
}
}];
}
- (void)kb_setImageURL:(id)url
placeholder:(UIImage *)placeholder
cornerRadius:(CGFloat)radius
corners:(UIRectCorner)corners
borderWidth:(CGFloat)borderWidth
borderColor:(UIColor *)borderColor {
NSURL *u = _KBURL(url);
SDWebImageOptions options = KBWebImageDefaultOptions();
// +
CGFloat scale = UIScreen.mainScreen.scale;
CGSize size = self.bounds.size;
NSMutableArray<id<SDImageTransformer>> *trans = [NSMutableArray array];
if (!CGSizeEqualToSize(size, CGSizeZero)) {
//
CGSize pixel = CGSizeMake(size.width * scale, size.height * scale);
[trans addObject:[SDImageResizingTransformer transformerWithSize:pixel scaleMode:SDImageScaleModeAspectFill]];
}
[trans addObject:[SDImageRoundCornerTransformer transformerWithRadius:radius
corners:(SDRectCorner)corners
borderWidth:borderWidth
borderColor:borderColor]];
SDImagePipelineTransformer *pipeline = [SDImagePipelineTransformer transformerWithTransformers:trans];
NSDictionary *context = @{ SDWebImageContextImageTransformer : pipeline };
__weak typeof(self) weakSelf = self;
[self sd_setImageWithURL:u
placeholderImage:placeholder
options:options
context:context
progress:nil
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if (!error && image && cacheType == SDImageCacheTypeNone) {
weakSelf.alpha = 0.0;
[UIView animateWithDuration:0.25 animations:^{ weakSelf.alpha = 1.0; }];
}
}];
}
- (void)kb_setAvatarURL:(id)url placeholder:(UIImage *)placeholder {
//
CGSize sz = self.bounds.size;
CGFloat r = MIN(sz.width, sz.height) * 0.5;
if (r <= 0) {
// 使
r = MIN(placeholder.size.width, placeholder.size.height) * 0.5;
}
[self kb_setImageURL:url
placeholder:placeholder
cornerRadius:r
corners:UIRectCornerAllCorners
borderWidth:0
borderColor:nil];
}
- (void)kb_cancelImageLoad {
[self sd_cancelCurrentImageLoad];
}
@end