AutoLayout進(jìn)階之朋友圈界面實(shí)現(xiàn)

前面我已經(jīng)寫(xiě)了4篇關(guān)于AutoLayout進(jìn)階的文章,但是講的點(diǎn)都很散。我準(zhǔn)備用這篇文章將前面所講的知識(shí)串起來(lái),運(yùn)用到實(shí)際,然后將AutoLayout系列做一個(gè)總結(jié)。我們先來(lái)看看效果:

2016-07-18 10_43_37.gif

這是一個(gè)類似朋友圈的社交界面,也是我以前做過(guò)的項(xiàng)目的一部分,全部由基本的UITableView實(shí)現(xiàn)。為了避免暴露服務(wù)器接口,我去除了與服務(wù)器交互的部分以及一大部分業(yè)務(wù)邏輯,只剩下寫(xiě)死的數(shù)據(jù)和界面布局。當(dāng)時(shí)為了完成項(xiàng)目任務(wù),做這個(gè)界面大概花了5天的時(shí)間(demo外還有很多功能),為了實(shí)現(xiàn)功能和優(yōu)化卡頓也費(fèi)了不少心思,也幫助我對(duì)約束布局有了更深認(rèn)識(shí)。話不多說(shuō),我們來(lái)看看怎么實(shí)現(xiàn)。

大圖小圖布局切換

看gif圖我們可以看見(jiàn),圖片的布局有多樣,準(zhǔn)確的說(shuō)最多顯示9種,根據(jù)圖片數(shù)量不同,布局也不同。網(wǎng)上有些人采用幾個(gè)不同的cell來(lái)顯示不同種類的圖片,但我這為了節(jié)省代碼量,我采用AutoLayout布局,并通過(guò)修改約束來(lái)實(shí)現(xiàn)不同個(gè)數(shù)的圖片顯示。

上半部分cell布局

這個(gè)是我上半部分cell的布局。中間的大方框就是我放圖片的位置,我在這單獨(dú)擺放了一個(gè)UIView,方便后續(xù)的界面布局。這個(gè)方框的寬度不會(huì)改變,唯一會(huì)變的應(yīng)該是高度(虛線顯示的約束),因此我將這個(gè)高度約束設(shè)置成變量,在cell的.m文件中,通過(guò)改變變量的值來(lái)動(dòng)態(tài)調(diào)整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;
    //點(diǎn)擊圖片展示
     [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;
    }
  }
}

這里其實(shí)有一點(diǎn)不足之處,如果每次顯示cell都將控件remove再add一遍,其實(shí)是很耗性能的,如果有什么好的建議歡迎再評(píng)論區(qū)分享。

文字點(diǎn)擊事件TTTAttributedLabel

文字點(diǎn)擊事件獲取一直都是這類界面的難點(diǎn)。我們都知道NSMutableAttributedString可以改變字體顏色,大小等,但是不支持響應(yīng)事件。如果專門為了這個(gè)功能去封裝UIViewtouch事件又太過(guò)麻煩。因此,我選擇上網(wǎng)查找第三方控件,很幸運(yùn),TTTAttributedLabel剛好能滿足我的需求。

TTTAttributedLabel的使用很簡(jiǎn)單,首先設(shè)置addLinkToAddress:withRange:方法,將響應(yīng)的參數(shù)和范圍傳進(jìn)去,然后設(shè)置delegate。在代理的attributedLabel:didSelectLinkWithAddress:會(huì)返回回調(diào),在里面處理點(diǎn)擊事件就可以了。TTTAttributedLabel還能像NSMutableAttributedString那樣,通過(guò)setText:afterInheritingLabelAttributesAndConfiguringWithBlock:方法設(shè)置文字顏色,點(diǎn)擊顏色等。關(guān)鍵代碼如下:

    TTTAttributedLabel * textLabel = [[TTTAttributedLabel alloc] initWithFrame:CGRectMake(0, 0, 20, 0)];
    textLabel.extendsLinkTouchArea = NO;//網(wǎng)上說(shuō)設(shè)置這個(gè)可以減少點(diǎn)擊面積,從而使滑動(dòng)更流暢
    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:@"%@ 回復(fù) %@",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) {
            //設(shè)置可點(diǎn)擊文本的大小
            [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)font range:firstRange];
            [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)font range:secondRange];
            //設(shè)置可點(diǎn)擊文本的顏色
            [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];
    ///添加長(zhǎng)按事件
    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);
}];

將評(píng)論添加到view上并布局我采用Masonry設(shè)置約束,代碼如上最后一段。參考:Autolayout進(jìn)階之代碼編寫(xiě)約束(一)

自動(dòng)計(jì)算cell高度

朋友圈類型的界面,自動(dòng)計(jì)算高度是少不了的。這里我采用的是自己的一套框架,用法比較簡(jiǎn)單,而且我以前也介紹過(guò),這里就不再累述。參考:AutoLayout進(jìn)階之可變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;
    }

//先從緩存中查看數(shù)據(jù),如果有數(shù)據(jù)就直接返回,如果沒(méi)有再進(jìn)行計(jì)算
    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;
}

總結(jié)

類似朋友圈最大的問(wèn)題就是滑動(dòng)卡頓。如果仔細(xì)觀察,微信的朋友圈也是有略微卡頓的。因此要盡可能優(yōu)化代碼。我曾經(jīng)將評(píng)論都放在一個(gè)cell,結(jié)果評(píng)論一多就根本劃不動(dòng),原因是每條評(píng)論都設(shè)置了多個(gè)autoLayout約束,在一個(gè)cell中的話,計(jì)算高度十分復(fù)雜、緩慢。后來(lái)我將評(píng)論分成多個(gè)cell,這樣就減少了計(jì)算量。一定要記得要緩存高度,這樣能極大的優(yōu)化加載速度。還有富文本label的使用盡量少,因?yàn)楦晃谋颈旧砭秃芟男阅堋?/p>

Show Me The Code!

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

我是翻滾的牛寶寶,歡迎大家評(píng)論交流~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,074評(píng)論 4 61
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協(xié)議。它實(shí)...
    香橙柚子閱讀 24,705評(píng)論 8 183
  • wxg 我披著一層皮 身著一件光鮮艷麗的衣 我被人群高高抬起 認(rèn)不清 自 己 迷茫 迷失 在 人群里 我、想...
    silencesky閱讀 385評(píng)論 0 2
  • “哎呀,我的小寶貝哭了?!?“沒(méi)事媽,我沖好奶就過(guò)去。” “那你不早說(shuō),給我抱啊?!?“媽,你別抱。他是故意大聲哭...
    chen姐chen閱讀 3,874評(píng)論 0 2
  • 你一定要清楚,自己想成為什么樣的人。三十歲時(shí),你想要的生活是什么樣的?你眼下要做的事,應(yīng)該是有助于你實(shí)現(xiàn)你的長(zhǎng)期目...
    充滿自信的我閱讀 189評(píng)論 0 0

友情鏈接更多精彩內(nèi)容