AutoLayout进阶之朋友圈界面实现

前面我已经写了4篇关于AutoLayout进阶的文章,但是讲的点都很散。我准备用这篇文章将前面所讲的知识串起来,运用到实际,然后将AutoLayout系列做一个总结。我们先来看看效果:

2016-07-18 10_43_37.gif

这是一个类似朋友圈的社交界面,也是我以前做过的项目的一部分,全部由基本的UITableView实现。为了避免暴露服务器接口,我去除了与服务器交互的部分以及一大部分业务逻辑,只剩下写死的数据和界面布局。当时为了完成项目任务,做这个界面大概花了5天的时间(demo外还有很多功能),为了实现功能和优化卡顿也费了不少心思,也帮助我对约束布局有了更深认识。话不多说,我们来看看怎么实现。

大图小图布局切换

看gif图我们可以看见,图片的布局有多样,准确的说最多显示9种,根据图片数量不同,布局也不同。网上有些人采用几个不同的cell来显示不同种类的图片,但我这为了节省代码量,我采用AutoLayout布局,并通过修改约束来实现不同个数的图片显示。

上半部分cell布局

这个是我上半部分cell的布局。中间的大方框就是我放图片的位置,我在这单独摆放了一个UIView,方便后续的界面布局。这个方框的宽度不会改变,唯一会变的应该是高度(虚线显示的约束),因此我将这个高度约束设置成变量,在cell的.m文件中,通过改变变量的值来动态调整UiView的高度,再把imageView填上去。

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bigPictureViewHeight;

- (void)createPicTureView:(NSArray *)picArray{
    [self.pictureView removeAllSubviews];
    [pictureArray removeAllObjects];
    picWidth = 0;
    picHeight = 0;
    int rowPicCount = 1;
    float bigPicViewWidth = screenWidth - space *2;

if ([picArray count]==0) {
    self.bigPictureViewHeight.constant = 0;
    return ;
}
else if ([picArray count] == 1) {
    picWidth = (screenWidth - space *2) ;
    picHeight = picWidth;
    self.bigPictureViewHeight.constant = bigPicViewWidth;
    rowPicCount =1;
}
else if ([picArray count] <=2){
    picWidth = (screenWidth - space *2 - 5)/2;
    picHeight = picWidth;
    self.bigPictureViewHeight.constant = picHeight;
    rowPicCount =2;
}
else if ([picArray count] <=4){
    picWidth = (screenWidth - space *2 - 5)/2;
    picHeight = picWidth;
    self.bigPictureViewHeight.constant = bigPicViewWidth;
    rowPicCount = 2;
}
else if ([picArray count] <=6){
    picWidth = (screenWidth - space *2 - 10)/3;
    picHeight = picWidth;
    self.bigPictureViewHeight.constant = picHeight *2 +5;
    rowPicCount = 3;
}
else if ([picArray count] <= 9){
    picWidth = (screenWidth - space *2 - 10)/3;
    picHeight = picWidth;
    self.bigPictureViewHeight.constant = bigPicViewWidth;
    rowPicCount = 3;
}
float x=0;
float y =0;
for (int i =0 ; i<[picArray count]; i++) {
    UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(x, y , picWidth, picHeight)];
    imageView.backgroundColor = [UIColor whiteColor];
    imageView.clipsToBounds = YES;
    imageView.contentMode  =UIViewContentModeScaleAspectFill;
    [imageView sd_getImageWithId:picArray[i] andSize:picWidth square:NO placeholderImage:[UIImage imageNamed:@"place_holder_album"]];
    [self.pictureView addSubview:imageView];
    [pictureArray addObject:imageView];
    //白色圆角边框
    UIImageView *cornerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(x, y , picWidth, picHeight)];
    cornerImageView.image = [UIImage stretchableImageNamed:@"white_corner"];
    [self.pictureView addSubview:cornerImageView];

    UIButton * button = [[UIButton alloc]initWithFrame:imageView.frame];
    button.tag = i;
    //点击图片展示
     [button addTarget:self action:@selector(showPic:) forControlEvents:UIControlEventTouchUpInside];
      [self.pictureView addSubview:button];
    if ((i+1)%rowPicCount == 0) {
        x= 0;
        y = y + 5 + picHeight;
    }
    else {
        x= x+picWidth +5;
    }
  }
}

这里其实有一点不足之处,如果每次显示cell都将控件remove再add一遍,其实是很耗性能的,如果有什么好的建议欢迎再评论区分享。

文字点击事件TTTAttributedLabel

文字点击事件获取一直都是这类界面的难点。我们都知道NSMutableAttributedString可以改变字体颜色,大小等,但是不支持响应事件。如果专门为了这个功能去封装UIViewtouch事件又太过麻烦。因此,我选择上网查找第三方控件,很幸运,TTTAttributedLabel刚好能满足我的需求。

TTTAttributedLabel的使用很简单,首先设置addLinkToAddress:withRange:方法,将响应的参数和范围传进去,然后设置delegate。在代理的attributedLabel:didSelectLinkWithAddress:会返回回调,在里面处理点击事件就可以了。TTTAttributedLabel还能像NSMutableAttributedString那样,通过setText:afterInheritingLabelAttributesAndConfiguringWithBlock:方法设置文字颜色,点击颜色等。关键代码如下:

    TTTAttributedLabel * textLabel = [[TTTAttributedLabel alloc] initWithFrame:CGRectMake(0, 0, 20, 0)];
    textLabel.extendsLinkTouchArea = NO;//网上说设置这个可以减少点击面积,从而使滑动更流畅
    textLabel.font = FontRealityNormal;
    NSString * userName1 = dataModel.username;
    NSString * userName2 = dataModel.targetusername;
    NSString * text = dataModel.text;
    NSRange firstRange = NSMakeRange(0, userName1.length);
    NSRange secondRange;
    NSRange thirdRange;
    NSString * result = [NSString stringWithFormat:@"%@",userName1];
    if (userName2.length > 0) {
        result = [NSString stringWithFormat:@"%@ 回复 %@",result,userName2];
        secondRange = NSMakeRange(userName1.length+4, userName2.length);
    }
    else {
        secondRange = NSMakeRange(userName1.length+4, 0);
    }
    result = [NSString stringWithFormat:@"%@ :%@",result,text];
    thirdRange = NSMakeRange(0, result.length);
    textLabel.lineSpacing = 5;
    textLabel.preferredMaxLayoutWidth = screenWidth - 68 -30 -6-6-10;
    if (self.type == TalkTypeNomal) {
         textLabel.numberOfLines = 5;
    }
    else {
         textLabel.numberOfLines = 0;
    }
    textLabel.linkAttributes = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kCTUnderlineStyleAttributeName];
    [textLabel setText:result afterInheritingLabelAttributesAndConfiguringWithBlock:^NSMutableAttributedString *(NSMutableAttributedString *mutableAttributedString) {
    
        UIFont *boldSystemFont = [UIFont systemFontOfSize:13];
        CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)boldSystemFont.fontName, boldSystemFont.pointSize, NULL);
        if (font) {
            //设置可点击文本的大小
            [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)font range:firstRange];
            [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)font range:secondRange];
            //设置可点击文本的颜色
            [mutableAttributedString addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)[[UIColor colorWithRed:62/255.0 green:81/255.0 blue:105/255.0 alpha:1] CGColor] range:firstRange];
            [mutableAttributedString addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)[[UIColor colorWithRed:62/255.0 green:81/255.0 blue:105/255.0 alpha:1] CGColor] range:secondRange];
      
            CFRelease(font);
        }
        return mutableAttributedString;
    }];
    textLabel.delegate = self;
    [textLabel addLinkToAddress:@{@"kind":@"comment",@"object":dataModel} withRange:thirdRange];
    [textLabel addLinkToAddress:@{@"kind":@"user",@"object":dataModel.userid} withRange:firstRange];
    [textLabel addLinkToAddress:@{@"kind":@"user",@"object":dataModel.targetuserid} withRange:secondRange];
    [self.commentView addSubview:textLabel];
    ///添加长按事件
    UILongPressGestureRecognizer * longPressGestureRecognizer =[[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressGesture:)];
    [textLabel addGestureRecognizer:longPressGestureRecognizer];
    [textLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(self.commentView).offset(3);
    make.left.equalTo(avatar.mas_right).offset(5);
    make.right.equalTo(self.commentView).offset(-10);
    make.bottom.equalTo(self.commentView).offset(-3);
}];

将评论添加到view上并布局我采用Masonry设置约束,代码如上最后一段。参考:Autolayout进阶之代码编写约束(一)

自动计算cell高度

朋友圈类型的界面,自动计算高度是少不了的。这里我采用的是自己的一套框架,用法比较简单,而且我以前也介绍过,这里就不再累述。参考:AutoLayout进阶之可变cell高度

主要代码:

- (CGFloat)getHeightWidthInfo:(id)info{
    [self setInfo:info];
    [self layoutSubviews];

    [self setNeedsUpdateConstraints];
    [self updateConstraintsIfNeeded];

    [self setNeedsLayout];
    [self layoutIfNeeded];
    CGFloat height = [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height ;
    return  height;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if((self.type == TalkTypeNomal || self.type == TalkTopic) && indexPath.row == 6){
        return 50;
    }

//先从缓存中查看数据,如果有数据就直接返回,如果没有再进行计算
    float height = [tableViewHeightCache getHeightWithNSIndexPath:indexPath].floatValue;
    if (height != 0) {
        return height;
    }
    if (indexPath.row == 0) {
    float height;

    MCTalkMainViewCell * cell = [tableView MCTalkMainViewCell];
    height = [cell getHeightWidthInfo:dataArray[indexPath.section]] ;
    [tableViewHeightCache setHeightWithNSIndexPatch:indexPath andValue:@(height)];
        return height;
    }
    else {
  
    float height;
    MCTalkCommentCell * cell = [tableView MCTalkCommentCell];
    cell.type = self.type;
    PZHListItemModel * listModel = dataArray[indexPath.section];
    TalkCommentModel * commentModel = listModel.commentPoList[indexPath.row -1];
    height = [(MCTalkCommentCell *)cell getHeightWidthInfo:@{@"listModel":listModel,@"commentModel":commentModel}];
    [tableViewHeightCache setHeightWithNSIndexPatch:indexPath andValue:@(height)];
    return height;
    }
return 0.1;
}

总结

类似朋友圈最大的问题就是滑动卡顿。如果仔细观察,微信的朋友圈也是有略微卡顿的。因此要尽可能优化代码。我曾经将评论都放在一个cell,结果评论一多就根本划不动,原因是每条评论都设置了多个autoLayout约束,在一个cell中的话,计算高度十分复杂、缓慢。后来我将评论分成多个cell,这样就减少了计算量。一定要记得要缓存高度,这样能极大的优化加载速度。还有富文本label的使用尽量少,因为富文本本身就很消耗性能。

Show Me The Code!

github: https://github.com/NBaby/PZHCircleOfFriendsDemo

我是翻滚的牛宝宝,欢迎大家评论交流~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一种新的协议。它实...
    香橙柚子阅读 23,687评论 8 183
  • wxg 我披着一层皮 身着一件光鲜艳丽的衣 我被人群高高抬起 认不清 自 己 迷茫 迷失 在 人群里 我、想...
    silencesky阅读 341评论 0 2
  • “哎呀,我的小宝贝哭了。” “没事妈,我冲好奶就过去。” “那你不早说,给我抱啊。” “妈,你别抱。他是故意大声哭...
    chen姐chen阅读 3,787评论 0 2
  • 你一定要清楚,自己想成为什么样的人。三十岁时,你想要的生活是什么样的?你眼下要做的事,应该是有助于你实现你的长期目...
    充满自信的我阅读 134评论 0 0