QQ聊天界面的布局和設計(IOS篇)-第二季


QQChat Layout - 第二季

  • 本來第二季是快寫好了, 也花了點功夫, 結果gitbook出了點問題, 給沒掉了。有些細節可能會一帶而過, 如有疑問, 相互交流進步~.

在第一季中我們完成了QQ聊天界面的基本框架.但是相對於iphone上手機QQ的聊天界面還存在以下差距。

  • 第二季中的工程源文件下載地址:點擊到百度雲下載
  • 聊天消息沒有左右區分。
  • 聊天內容沒有背景圖片。
  • 菜單欄還沒做出, 不能發消息。
###現在我們就一步步來解決這些問題。首先我們解決消息沒有左右區分的問題。 - ** 第四步**: 我們打開StoryBoard。拖入和左邊一樣的兩個控件ImageView和UIButton。並設置和左邊一樣的約束。具體的**約束思路**如下:
1.設置ImageView距離右邊10 , 寬高為40==》確定了x,和寬高
2.設置ImageView的上面和timeLabel下面對齊 ==》確定了Y, 確定了Button
3.設置Button右邊距離ImageView左邊10, 固定寬高。
4.設置Button的上面與ImageView上面對齊。

SB圖片如下: ![](http://images0.cnblogs.com/blog2015/604808/201506/082123337071629.png)
  • 修改完SB的cell界面后開始編碼了。我們主要需要在setMessage這個setter方法中, 加入判斷聊天消息是屬於左邊還是屬於右邊。具體邏輯如下:
- (void)setMessage:(Message *)message {

    _message = message;

    MessageWhoIsMe ==
        _message.type?
        [self setShowButton: _rightText andIcon: _rightIcon withMessage:message]:
        [self setShowButton: _text andIcon: _icon withMessage:message];

}

/**
 *  設置要展示的消息內容與頭像
 *
 *  @param button 設置要顯示的信息。
 *  @param icon   設置要顯示的頭像
 */
- (void)setShowButton:(UIButton *)text andIcon:(UIImageView *)icon withMessage:(Message*)message{

    _rightIcon.hidden = _rightText.hidden = (text != _rightText);
    _icon.hidden = _text.hidden = (text != _text);
    // 1.給控件裝數據
    icon.image = [UIImage imageNamed:[self getPicture: message.type]];

    [text setTitle:message.text forState:UIControlStateNormal];

    _timeLabel.text = message.time;

    // 2.裝完數據強制布局, 使得設置按鈕高度的值准確, 並且更新約束
    [text layoutIfNeeded];

    // 要先強制布局, 這時候更新約束才准確
    // 更新約束, 使得按鈕的高度此時等於文本的高度。

    [text updateConstraints:^(MASConstraintMaker *make) {
        CGFloat textH = CGRectGetHeight(text.titleLabel.frame); //+ 30;
        make.height.equalTo(textH);
    }];

    // 3.再次強制布局, 使得約束生效, 這樣獲取到的按鈕高度才准確
    [text layoutIfNeeded];

    CGFloat textH = CGRectGetMaxY(text.frame);
    CGFloat iconH = CGRectGetMaxY(icon.frame);
    CGFloat cellH = MAX(textH, iconH) + 10;

    // 4.更新cell的高度到模型中
    message.height = cellH;

}

效果圖如下(已經實現了左右排列):

  • 第五步:
  • 我們已經完成了QQ消息的可以分左右排列, 接下去我們需要給消息上背景圖, 也就是設置按鈕的背景圖。由於按鈕有狀態,所以你不能操作它的圖片控件來給它設置圖, 應該用其提供的設置圖片的接口。具體的邏輯比較簡單。你可以直接看代碼,我主要講下[UIImage resizeWithImageName:的知識點。
    .....省略N行代碼
    _timeLabel.text = message.time;

    // 1.2 改進背景圖。

    if (!_rightText.hidden) {    // 當前顯示的是右邊, 則設置右邊的背景



        [_rightText setBackgroundImage:[UIImage resizeWithImageName:@"chat_send_nor"] forState:UIControlStateNormal];

        [_rightText setBackgroundImage:[UIImage resizeWithImageName:@"chat_send_press_pic"] forState:UIControlStateHighlighted];




    }else { // 顯示的是左邊

        [_text setBackgroundImage:[UIImage resizeWithImageName:@"chat_recive_press_pic"] forState:UIControlStateNormal];

        [_text setBackgroundImage:[UIImage resizeWithImageName:@"chat_recive_nor"] forState:UIControlStateHighlighted];


    }


    // 2.裝完數據強制布局, 使得設置按鈕高度的值准確, 並且更新約束
    .....省略N行代碼
  • 具體的邏輯很簡單,但是我要介紹下圖片拉伸的知識。在實際項目中, 我們使用的資源圖片不可能是十分大的, 能小則小。不然很消耗內存。你可以打開工程看到, 這個工程中的資源圖片中消息背景圖。你可以嘗試把UIImage resizeWithImageName:替換成UIImage imageNamed:來加載圖片, 會發現,當按鈕中的文字變大時候,圖片還是那么大,也就說圖片沒有隨着按鈕的尺寸進行伸縮。好在蘋果已經為我們提供了一個方法來伸縮圖片。其實UIImage resizeWithImageName:只是我對Apple官方的方法的一個封裝, 並將它做成UIImage的分類
  • 細說-(UIImage *)resizableImageWithCapInsets:這個方法是Apple提供的Image類的實例方法。為了不誤導大家, 特意查了官方解釋如下:

1.簡單來說該方法是用來返回一個可隨着Button尺寸自動伸縮的圖片,並且能保留住原來圖片的四個邊角, 也就說你要把它設置成Button的背景圖
 2.該方法主要通過保護區域是不是有寬、高,和保護區域的大小來決定渲染的方式。當保護區域有高該圖片就是豎直可伸縮, 有寬則是水平可伸縮。當寬高都是1px時候,選用的渲染方式是直接把這1px的圖片扯大, 渲染的效率十分高。

      那么究竟如何確定保護區域呢?根據官方文檔,我們最好將保護區域設置成1*1的大小。這樣水平、豎直方向都可以進行拉伸, 並且渲染方式也高, 還有一點就是這個區域我們最好選擇的是最靠近正中間的, 因為一般來說這樣才能盡可能把圖片邊緣切掉, 保證渲染出來的圖片和遠圖片看上去是放大后的效果。否則可能出現,圖片存在菱角。當然我們還能通過resizableImageWithCapInsets:resizingMode:來說明圖片渲染的模式,一種是使用拉伸來resize圖片, 一種是使用平鋪的方式來resize圖片.說了那么多, 你應該懂得了原理, 那么直接看我給UIImage擴充的分類方法吧。

#import "UIImage+Resizingable.h"

@implementation UIImage (Resizingable)

+ (UIImage *)resizeWithImageName:(NSString *)imageName {

    UIImage * image = [UIImage imageNamed: imageName];

    int W = image.size.width * 0.5;
    int H = image.size.height * 0.5;
    return [image resizableImageWithCapInsets: UIEdgeInsetsMake(H, W, image.size.height - H - 1 , image.size.width - W - 1)];

}
@end

第五步-1效果圖:

  • 你一定會看出還存在一點問題。問什么文字沒有全部被背景包括着,這是因為很多時候美工給的圖片背景都會有留白問題。也就是不是沒有被圖片包括着,是因為圖片旁邊有一些空白,顯示出來就成這樣了。這是后我們又可以利用按鈕的內邊距來把Label向左右推,這樣Label就會變高了,會超出Button,所以我們需要再給Button加點高度。應為給Button設置內邊距只需要設置一次,所以我一般將這種操作方法- (void)awakeFromNib方法中
- (void)awakeFromNib {

    // 設置自動換行
    _text.titleLabel.numberOfLines = 0;
    _rightText.titleLabel.numberOfLines = 0;

    // 設置button的內邊距
    _text.contentEdgeInsets = UIEdgeInsetsMake(0, 30, 0, 30);
    _rightText.contentEdgeInsets = UIEdgeInsetsMake(0, 30, 0, 30);

}

更改Button的高度約束,多加30

    [text updateConstraints:^(MASConstraintMaker *make) {
        CGFloat textH = CGRectGetHeight(text.titleLabel.frame)+ 30;
        make.height.equalTo(textH);
    }];

我覺得你會對內邊距存在很大的疑惑, 請看我的博客有專門介紹了下內邊距。

最終效果圖如下:

時間有限,菜單欄還介紹, 敬請關注第三季。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM