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:@"保存成功!"];    }}

关于保存的问题,将图片保存到相册中时,需要调用一个方法,系统需要这个方法接受三个参数,所以方法我们不能乱写,可以按照官方的建议写!

0 0