一 功能图
二 讲解思路
1 回顾上一篇内容
2 创建加载图片类(同时创建xib)
3 点击图片查看大图
4 点击查看大图(查看长图)
5 model出展示图片的控制器
6 保存图片
7 封装根据网络状态展示不同的图片
三 回顾上一篇内容
1 上一篇内容讲到对整个cell的分析,通过创建一个类(XIB)来管理cell的顶部和尾部总共九个控件.然后创建三个不同的类(xib),各自负责自己的中间部分,然后根据服务器返回的帖子类型,拼接上对应的cell,展示在用户眼前.
四 处理图片
1 处理原因: 由于从服务器中返回的图片的类型有两种:小图和长图,相对于其他部分,图片的处理相对来说比较麻烦.所以这里我先将展示图片的功能处理下.
2 创建加载图片类
3 处理图片的xib
—-> 3.1 注意一 : 占位文字”百思不得姐”字样的放置位置,放在UIImageView的下面,有利于在图片还没有从服务器中加载的时候,能显示”百思不得姐”字样,给用户比较好的体验(由于美工没有提供占位视图,只提供了一段文字,注意设置文字的样式为:下图)
—-> 3.2 注意二 : 注意”点击查看大图”按钮中的图片和文字中间的距离.我们是通过让图片向左移动5厘米并且让文字想右移动5厘米来达到中间的间隙,并且能让图片和文字总体处于中间位置.(设置地方)
—> 图一 :
—> 图二 :
4 图片类中需要用到的属性(通过拖线的方式拿到xib中需要的属性)
/**
* 背景图片
*/
@property (weak, nonatomic) IBOutlet UIImageView *pictureBackImageView;
/**
* 点击查看大图
*/
@property (weak, nonatomic) IBOutlet UIButton *seeBigPictureImageView;
/**
* 动图
*/
@property (weak, nonatomic) IBOutlet UIImageView *gifImageView;
5 定义模型属性(用于重写模型属性的set方法)
/**
* 导入模型
*/
@property (nonatomic, strong) XFJItem *topicesPicture;
6 模型的set方法
—-> 6.1 开启上下文(如果图片为长图)
—-> 6.2 绘图(如果图片为长图)
—-> 6.3 关闭上下文 (如果图片为长图)
总体代码:
#pragma mark - 模型属性的set方法
- (void)setTopicesPicture:(XFJItem *)topicesPicture
{
_topicesPicture = topicesPicture;
[self.pictureBackImageView XFJ_originalImageURL:topicesPicture.image1 thumbnailImageURL:topicesPicture.image0 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
//判断如果图片下载失败就返回
if (image == nil) return ;
//如果不是长图就返回
if (!topicesPicture.isBigPicture) return;
//长图来到下面
CGFloat pictureW = topicesPicture.middleFrame.size.width;
CGFloat pictureH = topicesPicture.middleFrame.size.height;
//开启上下文
UIGraphicsBeginImageContext(CGSizeMake(pictureW, pictureH));
/*
上下文的宽度 上下文的高度
------------ = ---------------
服务器返回图片的宽度 服务器返回图片的高度
*/
//绘图
[image drawInRect:CGRectMake(0, 0, pictureW, pictureW * topicesPicture.height / topicesPicture.width)];
//获得图片
self.pictureBackImageView.image = UIGraphicsGetImageFromCurrentImageContext();
//图形上下文
UIGraphicsEndImageContext();
}];
//如果是短图就隐藏点击查看大图按钮
self.seeBigPictureImageView.hidden = !topicesPicture.isBigPicture;
//如果不是动图就隐藏动图图标
self.gifImageView.hidden = !topicesPicture.is_gif;
}
五 处理点击图片和查看大图业务逻辑
1 点击查看大图(通过拖线的方式我们进行对按钮的监听)
- (IBAction)seeBigPictureClick
{
[self seeBigPicture];
}
2 调用的方法
#pragma mark - 实现轻按事件
- (void)seeBigPicture
{
//创建控制器
XFJSeeBigPicture *seePicture = [[XFJSeeBigPicture alloc] init];
//如果不写这一句的话,会出现NaN的情况
seePicture.topicesItem = self.topicesPicture;
//model出该控制器
[self.window.rootViewController presentViewController:seePicture animated:YES completion:nil];
}
3 由于当用户不管点击图片还是点击查看大图都会使得图片上展示出来,所以,我们给图片添加一个点按手势,其中点按要实现的方法恰好是查看大图的方法.
#pragma mark - 加载xib的时候回来到这个方法
- (void)awakeFromNib
{
//允许图片接收事件
self.pictureBackImageView.userInteractionEnabled = YES;
//创建请按手势
UITapGestureRecognizer *gest = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(seeBigPicture)];
//给图片添加手势
[self.pictureBackImageView addGestureRecognizer:gest];
}
六 展示图片的控制器(处理)
1 通过点击图片或者查看图片的按钮,可以看得出控制器是直接model出来的.
2 通过整体的图片在该控制器中的展示,我们不难看出,当图片为长图的时候用户需要往上滑动才能查看下面的图片,所以在dodel出来的控制器中层次结构为: UIScrollView–>UIImageView–>返回和保存按钮.
3 展示的xib效果图
4 需要用到的属性
/**
* 保存按钮
*/
@property (weak, nonatomic) IBOutlet UIButton *saveButton;
@property (nonatomic, weak) UIImageView *imageView;
5 通过直接拖线的方式,处理返回按钮(将model出来的控制器dissmiss)
- (IBAction)backClick
{
[self dismissViewControllerAnimated:YES completion:nil];
}
6 添加UIScrollView
#pragma mark - 添加scrollerView
- (void)setUpContentView
{
//创建UIScrollView
UIScrollView *scrollView = [[UIScrollView alloc] init];
//设置尺寸
scrollView.frame = CGRectMake(0, 0, XFJ_screenW, XFJ_screenH);
//添加手势
[scrollView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(backClick)]];
//设置颜色
scrollView.backgroundColor = [UIColor blackColor];
//添加插入到view中
[self.view insertSubview:scrollView atIndex:0];
//调用方法
[self setUpcontentImageView:scrollView];
}
—-> 6.1 注意 :创建的UIScrollView一定要选择插入到model出来的控制器中,否则会出错.不能直接添加.
7 添加UIScrollView上的UIImageView
—-> 7.1 计算图片的高度
—-> 7.2 给图片添加一个缩放功能
总体的代码:
#pragma mark - 在contentView中添加UIImageView
- (void)setUpcontentImageView:(UIScrollView *)scrollView
{
UIImageView *imageView = [[UIImageView alloc] init];
//添加图片
[imageView sd_setImageWithURL:[NSURL URLWithString:self.topicesItem.image1] placeholderImage:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
//如果下载的图片为空
if (image == nil) return ;
self.saveButton.enabled = YES;
}];
//设置尺寸
imageView.XFJ_X = 0;
imageView.XFJ_Width = scrollView.XFJ_Width;
[scrollView addSubview:imageView];
//赋值
self.imageView = imageView;
//图片的高度
imageView.XFJ_Height = imageView.XFJ_Width * self.topicesItem.height / self.topicesItem.width;
//判断
if (imageView.XFJ_Height >= XFJ_screenH) {
imageView.XFJ_Y = 0;
scrollView.contentSize = CGSizeMake(0, imageView.XFJ_Height);
}else{
imageView.XFJ_centerY = scrollView.XFJ_Height * 0.5;
}
CGFloat maxScale = self.topicesItem.width / self.imageView.XFJ_Width;
//判断
if (maxScale >= 1.0) {
scrollView.maximumZoomScale = maxScale;
scrollView.delegate = self;
}
}
8 代理方法处理缩放图片
#pragma mark - 代理方法
//return a view that will be scaled. if delegate returns nil, nothing happens
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
9 保存图片
—-> 9.1 点击保存按钮,保存图片
- (IBAction)savePicture
{
UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image: didFinishSavingWithError: contextInfo:), nil);
}
—-> 9.2 提示用户是否保存成功
#pragma mark - 是否保存成功
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
if (error) {
[SVProgressHUD showErrorWithStatus:@"保存失败"];
}else{
[SVProgressHUD showSuccessWithStatus:@"保存成功"];
}
}
—-> 9.3 注意 :UIImageWriteToSavedPhotosAlbum对该方法,苹果官方文档中有说明,@selector中调用的方法,必须是(下面)方法,否则就会报错.
// - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
七 建立联系
1 怎么样将各部分负责的UIView插入到自定义的cell中呢?
—-> 解答:通过下面的判断(self.topicesPicture.topicesPicture = topices;)主要作用
//通过贴模型中定义的属性帖子的类型
switch (self.topices.type) {
case XFJTopicTypeWord://段子
//将声音;图片;视频图片都隐藏
self.topicesPicture.hidden = YES;
self.topicesVideo.hidden = YES;
self.topicesVoice.hidden = YES;
break;
case XFJTopicTypePicture://图片
//图片出现;声音;视频隐藏
self.topicesVideo.hidden = YES;
self.topicesVoice.hidden = YES;
self.topicesPicture.topicesPicture = topices;
self.topicesPicture.hidden = NO;
break;
case XFJTopicTypeVideo://视频
//视频出现;声音和图片隐藏
self.topicesPicture.hidden = YES;
self.topicesVoice.hidden = YES;
self.topicesVideo.topicesVideo = topices;
self.topicesVideo.hidden = NO;
break;
case XFJTopicTypeVoice://声音
//声音出现;图片和视频隐藏
self.topicesPicture.hidden =YES;
self.topicesVoice.topicesVoice = topices;
self.topicesVoice.hidden = NO;
self.topicesVideo.hidden = YES;
break;
default:
break;
}
2 通过(self.topicesPicture.topicesPicture = topices;)需要加载对应的xib
#pragma mark - 图片xib懒加载
- (XFJTopicesPictureView *)topicesPicture
{
if (_topicesPicture == nil) {
//创建xib
XFJTopicesPictureView *picture = [XFJTopicesPictureView XFJ_middleXib];
//添加到tableView中的contentView中
[self.contentView addSubview:picture];
//赋值
_topicesPicture = picture;
}
return _topicesPicture;
}
3 调用下面的方法来加载对应的xib(self:谁调用就代表加载谁的xib)
#pragma mark - 实现快速创建xib的方法
+ (instancetype)XFJ_middleXib
{
return [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil].firstObject;
}
八 根据用户网络状态来下载不同规格的图片大小(封装)
1 思路:见下面伪代码
/*
if (缓存中有原图) {
self.imageView.image = 原图;
} else {
if (Wifi环境) {
下载显示原图
} else if (手机自带网络) {
if (用户设置3G\4G环境下仍然下载原图) {
下载显示原图
} else {
下载显示小图
}
} else {
if (缓存中有小图) {
self.imageView.image = 小图;
} else {
self.imageView.image = 占位图片;
}
}
}*/
2 封装
—-> 2.1 .h文件
/**
* 设置下载的图片类型(原图或缩略图)
*
* @param originalImageURL 原图的URL
* @param thumbnailImageURL 缩略图的URL
* @param placeholderImage 占位视图
* @param completedBlock 设置完图片回调
*/
- (void)XFJ_originalImageURL:(NSString *)originalImageURL thumbnailImageURL:(NSString *)thumbnailImageURL placeholderImage:(UIImage *)placeholderImage completed:(SDWebImageCompletionBlock)completedBlock;
/**
* 设置下载的图片类型(原图或缩略图)
*
* @param originalImageURL 原图的URL
* @param thumbnailImageURL 缩略图的URL
*/
- (void)XFJ_originalImageURL:(NSString *)originalImageURL thumbnailImageURL:(NSString *)thumbnailImageURL;
/**
* 设置下载的图片类型(原图或缩略图)
*
* @param originalImageURL 原图的URL
* @param thumbnailImageURL 缩略图的URL
* @param placeholderImage 占位视图
*/
- (void)XFJ_originalImageURL:(NSString *)originalImageURL thumbnailImageURL:(NSString *)thumbnailImageURL placeholderImage:(UIImage *)placeholderImage;
/**
* 设置下载的图片类型(原图或缩略图)
*
* @param originalImageURL 原图的URL
* @param thumbnailImageURL 缩略图的URL
* @param completedBlock 设置完图片回调
*/
- (void)XFJ_originalImageURL:(NSString *)originalImageURL thumbnailImageURL:(NSString *)thumbnailImageURL completed:(SDWebImageCompletionBlock)completedBlock;
—-> 2.2 .m文件(需要导入的框架AFN)
#pragma mark - 不需要传占位视图和完成需要做的事
- (void)XFJ_originalImageURL:(NSString *)originalImageURL thumbnailImageURL:(NSString *)thumbnailImageURL
{
[self XFJ_originalImageURL:originalImageURL thumbnailImageURL:thumbnailImageURL placeholderImage:nil completed:nil];
}
#pragma mark - 需要传入占位视图
- (void)XFJ_originalImageURL:(NSString *)originalImageURL thumbnailImageURL:(NSString *)thumbnailImageURL placeholderImage:(UIImage *)placeholderImage
{
[self XFJ_originalImageURL:originalImageURL thumbnailImageURL:thumbnailImageURL placeholderImage:placeholderImage completed:nil];
}
#pragma mark - 需要设置完图片回调
- (void)XFJ_originalImageURL:(NSString *)originalImageURL thumbnailImageURL:(NSString *)thumbnailImageURL completed:(SDWebImageCompletionBlock)completedBlock
{
[self XFJ_originalImageURL:originalImageURL thumbnailImageURL:thumbnailImageURL placeholderImage:nil completed:completedBlock];
}
#pragma mark - 需要设置占位视图和完成回调
- (void)XFJ_originalImageURL:(NSString *)originalImageURL thumbnailImageURL:(NSString *)thumbnailImageURL placeholderImage:(UIImage *)placeholderImage completed:(SDWebImageCompletionBlock)completedBlock
{
//先去缓存池中或者沙盒中寻找原图
UIImage *originalImageView = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:originalImageURL];
//判断如果有原图的话
if (originalImageView) {
//设置图片(有原图)
[self sd_setImageWithURL:[NSURL URLWithString:originalImageURL] placeholderImage:placeholderImage completed:completedBlock];
}else{
// 内存或者沙盒中没有原图-->下载
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
//判断网络情况
if (manager.isReachableViaWiFi) {//如果是wifi
[self sd_setImageWithURL:[NSURL URLWithString:originalImageURL] placeholderImage:placeholderImage completed:completedBlock];
}else if(manager.isReachableViaWWAN){//如果是3G或4G的话就看用户选择
//从沙盒中读取用户对是否下载原图的配置
BOOL alwaysDownloadOriginalImage = [[NSUserDefaults standardUserDefaults] boolForKey:@"alwaysDownloadOriginalImage"];
//如果是下载原图就直接下载
if (alwaysDownloadOriginalImage) {
[self sd_setImageWithURL:[NSURL URLWithString:originalImageURL] placeholderImage:placeholderImage completed:completedBlock];
}else{
//否则就下载小图
[self sd_setImageWithURL:[NSURL URLWithString:thumbnailImageURL] placeholderImage:placeholderImage completed:completedBlock];
}
}else{
//没有网络,读取缓存\沙盒中小图
UIImage *thumbnailImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:thumbnailImageURL];
//如果有缓存\沙盒中有小图
if (thumbnailImage) {
[self sd_setImageWithURL:[NSURL URLWithString:thumbnailImageURL] placeholderImage:placeholderImage completed:completedBlock];
}else{
[self sd_setImageWithURL:nil placeholderImage:placeholderImage completed:completedBlock];
}
}
}
}
九 总结
1 该部分着重的讲解了对图片处理和对用户网络状态显示多大规格的图片进行处理.代码内部的业务逻辑相对来说比较难(需要考虑到多方面的因素),但总的来说还是可以解决的,可能里面有一些还没有想到,后期想到会完善的.
2 后面我会继续完善百思不得姐,希望带给大家更多的不一样的想法,最后大家如果觉得我写的博客还满意的话,麻烦大家多多建议,多多关注我的官方博客,谢谢!!!!
时间: 2024-12-28 08:11:13