上节课我们完成了只让微博显示了文字内容的功能,但是没有显示微博配图,今天我们就要完成首页的最后一个内容,也就是给微博添加图片。
本节内容
- 计算配图控件的frame
- 设置原创微博和转发微博的配图
- 配图控件内部设置
- 设置配图浏览器功能
- 显示gif图片
本节资料
15.1 计算配图控件的frame
玩过微博的都知道,一条微博,要么是原创微博有配图,要么是转发微博有配图,两者只能有一个有配图。所以我们现在就开始新建一个配图类YGPhotosView.(不要忘了在头文件中添加一个pic_urls数组属性,用来传递数据)。
然后我们先把子控件加到原创微博和转发微博上。代码与添加其他控件都是类似的:
// 配图
YGPhotosView *photosView = [[YGPhotosView alloc] init];
[self addSubview:photosView];
_photosView = photosView;
我们继续往上走,把配图的frame在视图模型YGStatusFrame内计算出来,别忘了在YGStatusFrame内添加两个属性,originalPhotosFrame和retweetPhotosFrame。当我们计算配图frame的时候,原点坐标比较容易得出来,就是size比较复杂,因为配图不一样,计算的size就不一样。我们首先要根据配图的个数算出有几行几列,这里我们专门把计算size的代码抽取出来,如下:
#pragma mark - 计算配图的尺寸
- (CGSize)photosSizeWithCount:(int)count
{
// 获取总列数
int cols = count == 4? 2 : 3;
// 获取总行数 = (总个数 - 1) / 总列数 + 1
int rols = (count - 1) / cols + 1;
CGFloat photoWH = 70;
CGFloat w = cols * photoWH + (cols - 1) * YGStatusCellMargin;
CGFloat h = rols * photoWH + (rols - 1) * YGStatusCellMargin;
return CGSizeMake(w, h);
}
然后我们就根据size计算出配图控件的frame,代码如下,因为添加了配图控件,所以原创微博的frame也就发生了变化,所以这里我们把更改后的原创微博frame也一并贴了过来:
CGFloat originH = CGRectGetMaxY(_originalTextFrame) + YGStatusCellMargin;
// 配图
if (_status.pic_urls.count) {
CGFloat photosX = YGStatusCellMargin;
CGFloat photosY = CGRectGetMaxY(_originalTextFrame) + YGStatusCellMargin;
CGSize photosSize = [self photosSizeWithCount:_status.pic_urls.count];
_originalPhotosFrame = (CGRect){{photosX,photosY},photosSize};
originH = CGRectGetMaxY(_originalPhotosFrame) + YGStatusCellMargin;
}
// 原创微博的frame
CGFloat originX = 0;
//设置间隙
CGFloat originY = 10;
CGFloat originW = YGScreenW;
_originalViewFrame = CGRectMake(originX, originY, originW, originH);
计算转发微博里的配图frame就跟上面的代码差不多了,请大家仿照代码做出更改。
15.2 设置原创微博和转发微博的配图
计算配图尺寸完毕后,我们就可以在原创微博和转发微博里给刚刚添加的配图控件设置尺寸啦。原创微博里代码如下:
// 配图
_photosView.frame = _statusFrame.originalPhotosFrame;
别忘了给配图子控件传递数据哦,没有数据展示个啥!代码如下:
// 配图
_photosView.pic_urls = status.pic_urls;
转发微博的设置跟以上代码类似,请大家自己copy然后更改吧。
15.3 配图控件内部设置
下面我们就开始在配图子控件内部添加一个个的图片视图,代码如下:
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
// 添加9个子控件
[self setUpAllChildView];
}
return self;
}
// 添加9个子控件
- (void)setUpAllChildView
{
for (int i = 0; i < 9; i++) {
UIImageView *imageV = [[UIImageView alloc] init];
[self addSubview:imageV];
}
}
然后我们重写控件的layOutSubviews,这些简单的算法应该难不到你们吧,代码如下:
// 计算尺寸
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat x = 0;
CGFloat y = 0;
CGFloat w = 70;
CGFloat h = 70;
CGFloat margin = 10;
int col = 0;
int rol = 0;
int cols = _pic_urls.count==4?2:3;
// 计算显示出来的imageView
for (int i = 0; i < _pic_urls.count; i++) {
col = i % cols;
rol = i / cols;
UIImageView *imageV = self.subviews[i];
x = col * (w + margin);
y = rol * (h + margin);
imageV.frame = CGRectMake(x, y, w, h);
}
当配图子控件的pic_urls数组一旦被赋值后,我们就在它的set方法里,给配图里的子控间按照顺序设置图片。没有图片的子控件要隐藏。代码如下:
- (void)setPic_urls:(NSArray *)pic_urls
{
// 4
_pic_urls = pic_urls;
int count = self.subviews.count;
for (int i = 0; i < count; i++) {
UIImageView *imageV = self.subviews[i];
if (i < _pic_urls.count) { // 显示
imageV.hidden = NO;
// 获取YGPhoto模型
YGPhoto *photo = _pic_urls[i];
// 赋值
[imageV sd_setImageWithURL:photo.thumbnail_pic placeholderImage:[UIImage imageNamed:@"timeline_image_placeholder"]];
}else{
imageV.hidden = YES;
}
}
}
15.4 设置配图浏览器功能
大家都知道实际微博的配图都是可以点击,并且浏览的,而且多个配图间可以滑动浏览。所以我们这部分就讲解如何给配图加上浏览功能。
首先,给每个图片增加点按手势,代码如下:
// 添加9个子控件
- (void)setUpAllChildView
{
for (int i = 0; i < 9; i++) {
UIImageView *imageV = [[UIImageView alloc] init];
imageV.tag = i;
//设置可交互
imageV.userInteractionEnabled = YES;
//设置图片显示的方式
imageV.contentMode = UIViewContentModeScaleAspectFill;
// 裁剪图片,超出控件的部分裁剪掉
imageV.clipsToBounds = YES;
// 添加点按手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
[imageV addGestureRecognizer:tap];
[self addSubview:imageV];
}
}
然后,我们这里需要使用MJ搭建的配图浏览器框架,框架可以在资料里面找到。这里框架的使用有一点需要注意,就是浏览器需要知道显示什么图片,这里我们需要把YGPhoto模型转换为浏览器可以识别的MJPhoto模型,才能给浏览器使用。代码如下:
#pragma mark - 点击图片的时候调用
- (void)tap:(UITapGestureRecognizer *)tap
{
UIImageView *tapView = tap.view;
// YGPhoto -> MJPhoto
int i = 0;
NSMutableArray *arrM = [NSMutableArray array];
for (YGPhoto *photo in _pic_urls) {
MJPhoto *p = [[MJPhoto alloc] init];
NSString *urlStr = photo.thumbnail_pic.absoluteString;
urlStr = [urlStr stringByReplacingOccurrencesOfString:@"thumbnail" withString:@"bmiddle"];
p.url = [NSURL URLWithString:urlStr];
p.index = i;
p.srcImageView = tapView;
[arrM addObject:p];
i++;
}
// 弹出图片浏览器
// 创建浏览器对象
MJPhotoBrowser *brower = [[MJPhotoBrowser alloc] init];
// MJPhoto
brower.photos = arrM;
brower.currentPhotoIndex = tapView.tag;
[brower show];
}
15.5显示gif图片
如果你现在运行项目的话,会发现基本没啥毛病了,是不是现在很得意呢?但是还有最后一个小小问题,把它解决了就算大功告成了。这个问题就是当图片是gif的时候,在缩略图右下方添加一个图片表明是gif。所以这就需要我们自定义单个图片视图了,为YGPhotoView,继承自UIImageView。
第一步就是给代码搬家啦,首先在.m文件内,重写initWithFrame方法.
第二步就是创建一个新的gifView,用来添加到图片上。
代码如下:
-(instancetype)initWithFrame:(CGRect)frame
{
if (self=[super initWithFrame:frame]) {
self.userInteractionEnabled = YES;
self.contentMode = UIViewContentModeScaleAspectFill;
self.clipsToBounds = YES;
UIImageView *gifView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"timeline_image_gif"]];
[self addSubview:gifView];
_gifView = gifView;
}
return self;
}
然后我们重写layOutSubviews,给gifView设置位置:
- (void)layoutSubviews
{
[super layoutSubviews];
self.gifView.x = self.width - self.gifView.width;
self.gifView.y = self.height - self.gifView.height;
}
然后我们需要判断图片是否为gif图,如果是就显示gifView,不是就隐藏。我们怎么知道YGPhotoView里面加载什么图片呢,所以就需要给它添加一个YGPhoto属性,用来传值。重写setPhoto方法:
- (void)setPhoto:(YGPhoto *)photo
{
_photo = photo;
// 赋值
[self sd_setImageWithURL:photo.thumbnail_pic placeholderImage:[UIImage imageNamed:@"timeline_image_placeholder"]];
// 判断下是否显示gif
NSString *urlStr = photo.thumbnail_pic.absoluteString;
if ([urlStr hasSuffix:@".gif"]) {
self.gifView.hidden = NO;
}else{
self.gifView.hidden = YES;
}
}
最后我们重新修改下YGPhotosView方法的代码,让其添加的是我们自定义的YGPhotoView控件。运行代码后可以看到gif图片可以正确显示啦。
到这里我们就把微博的核心内容给学完了,相信大家在这十几节博客中也学了不少东西。是不是也发现一开始看起来很大的项目,当我们一步一步去拆解的时候就不显得很难了吧。其实它们都是纸老虎,按照我们某工大校训来说,只要功夫到家,一切问题都可以解决。下面两节,我们将会讲述如何发送微博,现在赶紧撸代码去吧。