05-百思不得姐(第五天)
来源:互联网 发布:sql 数据库 培训 编辑:程序博客网 时间:2024/06/10 14:45
今天的任务就是完成图片、段子cell里面的内容!从结构来看,图片cell就是在段子cell的基础上完成的,所以我们先写好段子cell界面!
一、段子cell内容的显示
1> 其实段子这个界面很好做,因为是纯文字,我们只需要计算出文字在cell中的frame就可以的!因为中间的内容不确定,导致cell的高度也是不确定的,所以我们可以在tableView的代理方法heightForRowAtIndexPath中完成。但是在这个方法中计算cell内部控件的frame以及自身的高度代码是不应该直接暴露在控制器中的,明显可以屏蔽起来。所以我们可以利用模型,给模型添加一个辅助属性cellHeight(cell的高度),然后把模型的该属性返回出去。
DSTopic.h文件中:
/** * cell的高度 */@property (nonatomic, assign, readonly) CGFloat cellHeight;
控制器.m文件中:
#pragma mark - 代理方法- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ DSTopic *topic = self.topics[indexPath.row]; return topic.cellHeight;}
这个时候控制器代码就十分简介明了!
2> 接下来就重写cellHeight的get方法,在get方法里面完成内部子控件frame的计算!
- (CGFloat)cellHeight{ // 文字的宽度限制 CGFloat maxW = [UIScreen mainScreen].bounds.size.width - 4 * DSTopicCellMargin; // 文字的高度 CGFloat textH = [self.text sizeWithFont:[UIFont systemFontOfSize:15] maxW:maxW].height; _cellHeight = DSTopicCellTextY + textH + DSTopicCellMargin; if (self.type == DSBaseTypePicture) { // 图片 CGFloat pictureW = maxW; CGFloat pictureH = pictureW * self.height / self.width; if (pictureH >= DSTopicCellPictureMaxH) { // 图片过大 self.seeBigPicture = YES; pictureH = DSTopicCellPictureBreakH; } // 设置图片视图的frame _pictureViewFrame = CGRectMake(DSTopicCellMargin, DSTopicCellTextY + textH + DSTopicCellMargin, pictureW, pictureH); _cellHeight += pictureH + DSTopicCellMargin; } _cellHeight += DSTopicCellBottomH + DSTopicCellMargin; return _cellHeight;}
注意:
- 关于文字size的计算,我封装到NSString的一个分类里面去了!
/** - 计算文字的宽高(需要告诉宽度限制) */ - (CGSize)sizeWithFont:(UIFont *)font maxW:(CGFloat)maxW{ NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; attrs[NSFontAttributeName] = font; CGSize maxSize = CGSizeMake(maxW, MAXFLOAT); return [self boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin) attributes:attrs context:nil].size;}
其中的_pictureViewFrame,seeBigPicture等几个属性和常量是后面会用到的,待会儿会交代!
在这里面其实主要就是计算出文字的size,然后求出cell的高度
接着在自定义cell里面写上:
// 设置段子内容 self.contentLabel.text = topic.text;
该界面就完成了!
二、图片界面的显示
关于图片的显示其实和段子差不多,但是也有很多注意点!
1> 完成图片在cell中的显示
因为图片内容中有一些固定的内容,因此直接用XIB完成!该类就叫做DSPictureView
计算代码也是在cellHeight的get方法中!
讲解点:
- 首先应该判断出该cell的高度是应该显示段子还是显示图片
这里的图片高度是应该是一个比例值,取得图片的实际宽高,然后根据定的宽度计算出高度!
其中的几个固定的常量距离就直接定义在const文件中了!
/** 精华-顶部标签栏-高度 */UIKIT_EXTERN CGFloat const DSTitleViewH;/** 精华-顶部标签栏-Y值 */UIKIT_EXTERN CGFloat const DSTitleViewY;/** 精华-cell-间距 */UIKIT_EXTERN CGFloat const DSTopicCellMargin;/** 精华-cell-Text的Y值 */UIKIT_EXTERN CGFloat const DSTopicCellTextY;/** 精华-cell-底部工具条的高度 */UIKIT_EXTERN CGFloat const DSTopicCellBottomH;/** 精华-cell-帖子的最大高度 */UIKIT_EXTERN CGFloat const DSTopicCellPictureMaxH;/** 精华-cell-帖子超出最大高度后的高度 */UIKIT_EXTERN CGFloat const DSTopicCellPictureBreakH;
然后给DSPictureView传递模型,在设置模型的过程中设置imageView的图片,同时判断是否要显示GIF,底部放大按钮!不过判断就放到后面,我们先完成显示!
这个时候会发现,图片的显示还是不尽人意!其实这个时候是一个属性在作怪,那就是autoresizing!
因此在DSPictureView.m文件中,重写awakeFromNib方法,然后设置一项属性!
- (void)awakeFromNib{ // 当我们的某控件frame都设置好了,但是显示却不理想,多半是autoresizing的问题 self.autoresizingMask = UIViewAutoresizingNone;}
图片显示完毕后,就需要添加判断了!
首先是GIF的判断:
// 获取图片是否为gif NSString *imageExtension = topic.large_image.pathExtension; self.gifImageView.hidden = ![imageExtension.lowercaseString isEqualToString:@"gif"];
我们可以根据图片的路径后缀判断,因为经过服务器的处理,只要是GIF图片,后缀就是GIF!
在这里说一个知识点,那就是如何在不知道图片扩展名的情况下,知道图片的真实类型?
解答: 取出图片的第一个字节,就可以判断图片的真实类型
接下来就判断按钮:
// 判断图片是否需要点击大图 if (topic.isSeeBigPicture) { // 图片过大 self.seeBigButton.hidden = NO; self.imageView.contentMode = UIViewContentModeScaleAspectFill; }else { self.seeBigButton.hidden = YES; self.imageView.contentMode = UIViewContentModeScaleToFill; }
这里我给模型添加一个辅助属性(isSeeBigPicture),我们在cellHeight的get方法中,可以判断图片的高度是否超过一个固定值,如果超过了,就显示大图按钮!然后设置图片的显示属性(在这里其实有个问题:那就是这样加载后的图片会显示中间的部分,而不是最上面的部分,这个后面解决!)
三、显示中间的进度条
关于进度条,我用了一个三方框架,关于框架的使用就不详细介绍了!这里主要讲解下:如何减少第三方框架的污染!
其实关于这类框架,最好的办法就是自己写一个类继承自该框架,然后提供相应的方法或者重写相应的方法来实现同样的功能,把框架里面的代码包装在这个类中,等以后换其他框架的时候,只需要改这个一个地方就好了!而不是让框架侵染到项目的各个地方!
关于进度的问题,SD提供了对应的方法!
// 立即显示最新的进度值(防止网速慢而显示其他图片的下载进度) [self.progressView setProgress:topic.progress animated:NO]; [self.imageView sd_setImageWithURL:[NSURL URLWithString:topic.large_image] placeholderImage:nil options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) { self.progressView.hidden = NO; // 保存进度值 topic.progress = 1.0 * receivedSize / expectedSize; [self.progressView setProgress:topic.progress animated:NO]; } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { self.progressView.hidden = YES; }];
四、点击图片后显示大图
关于该界面,可以用一个控制器+XIB(DSShowPictureController)来显示,给imageView添加手势,同时点击大图按钮方法也是和手势方法一样!
/** * 显示大图 */- (IBAction)showPicture{ DSShowPictureController *showVc = [[DSShowPictureController alloc] init]; showVc.topic = self.topic; [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:showVc animated:YES completion:nil];}
因为DSPictureView是继承自UIView,所以不能直接弹出控制器,所以可以拿出根控制器来弹出!
XIB显示:
实现代码如下:
- (void)viewDidLoad { [super viewDidLoad]; // 0.获取屏幕尺寸 CGFloat screenW = [UIScreen mainScreen].bounds.size.width; CGFloat screenH = [UIScreen mainScreen].bounds.size.height; // 1.创建imageView UIImageView *imageView = [[UIImageView alloc] init]; imageView.userInteractionEnabled = YES; [imageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(back)]]; [self.scrollView addSubview:imageView]; self.imageView = imageView; // 2.设置图片尺寸 CGFloat pictureW = screenW; CGFloat pictureH = pictureW * self.topic.height / self.topic.width; if (pictureH > screenH) { // 需要滚动显示 imageView.frame = CGRectMake(0, 0, pictureW, pictureH); self.scrollView.contentSize = CGSizeMake(0, pictureH); }else { // 直接显示 imageView.size = CGSizeMake(pictureW, pictureH); imageView.center = CGPointMake(screenW * 0.5, screenH * 0.5); } // 3.显示图片 // 立即显示最新的进度值(防止网速慢而显示其他图片的下载进度) [self.progressView setProgress:self.topic.progress animated:NO]; [self.imageView sd_setImageWithURL:[NSURL URLWithString:self.topic.large_image] placeholderImage:nil options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) { self.progressView.hidden = NO; [self.progressView setProgress:self.topic.progress animated:NO]; } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { self.progressView.hidden = YES; }];}
/** * 返回 */- (IBAction)back { [self dismissViewControllerAnimated:YES completion:nil];}/** * 保存图片 */- (IBAction)savePicture { UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);}- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{ if (error) { [SVProgressHUD showErrorWithStatus:@"保存失败!"]; }else { [SVProgressHUD showSuccessWithStatus:@"保存成功!"]; }}
关于保存的问题,将图片保存到相册中时,需要调用一个方法,系统需要这个方法接受三个参数,所以方法我们不能乱写,可以按照官方的建议写!
- 05-百思不得姐(第五天)
- 01-百思不得姐(第一天)
- 08-百思不得姐(第八天)
- 03-百思不得姐(第三天)
- 07-百思不得姐(第七天)
- 09-百思不得姐(第九天)
- 《百思不得姐》
- 百思不得姐
- (第五天)了
- 第五天-2017-05-06
- 百思不得姐项目详细知识点(一)
- 百思不得姐项目详细知识点(二)
- 百思不得姐(4.5.6)最新版高仿
- Android 第五天(上午)
- Android 第五天 (下午)
- 第五天(5道)
- 移植第五天(文件系统)
- 第五天(Mysql+Php)
- 3. Longest Substring Without Repeating Characters
- 2015年蓝桥杯C/C++组B组第三题:三羊献瑞
- BIODIGITAL HUMAN(3D解剖)
- 防止头文件重复包含之pragma once与#ifndef
- javascript的方法可以分为三类:
- 05-百思不得姐(第五天)
- Codeforces E. Bear and Contribution(枚举维护)
- Fluent Nhibernate and Stored Procedures
- ACM_程序设计竞赛:穷举法:DFS(深度优先)
- 静态方法与非静态方法的区别
- Fluent Nhibernate and Stored Procedures
- POJ 3190(Stall Reservations 区间贪心)
- iOS判断字符串中包含数字和字母的几种情况
- Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解