你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS_29仿微信聊天界面

iOS_29仿微信聊天界面

編輯:IOS開發綜合

最終效果圖:


\



<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+19S2qNLlY2VsbLXEt+LXsDwvcD4KPHA+PC9wPgo8cCBjbGFzcz0="p1">BeyondCell

//
//  BeyondCell.h
//  29_仿微信聊天
//
//  Created by beyond on 14-9-4.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import 
@class BeyondCellFrame;

@interface BeyondCell : UITableViewCell


// 一行自定義的cell,初始化的時候,全部生成各個控件並添加到contentView,然後通過cellWithCellFrame方法,將參數CellFrame(內含Msg對象)的所有成員frame和數據 設置到cell中的各個控件上面去



// 返回xib界面上寫的重用cellID
+ (NSString *)cellID;


// 通過一個WeiboFrames模型對象(它本身就含有一個Weibo數據 模型),返回一個填充好數據的cell對象
- (BeyondCell *)cellWithCellFrame:(BeyondCellFrame *)cellFrame;

@end

//
//  BeyondCell.m
//  29_仿微信聊天
//
//  Created by beyond on 14-9-4.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "BeyondCell.h"
#import "BeyondCellFrame.h"
#import "Msg.h"

// 類擴展,又叫匿名分類
@interface BeyondCell()
{
    // 1,頭像
    UIImageView *_headImg;
    // 2,正文內容
    UILabel *_content;
    // 3,大圖片
    UIImageView *_bgImg;
}
@end
@implementation BeyondCell
// 返回xib界面上寫的重用cellID
+ (NSString *)cellID
{
    return @"BeyondCell";
}

// 當池中沒有Cell的時候,創建出一個純潔的Cell,一次性alloc 出所有的各個子控件 ,並加到contentView
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        
        //選中cell後背景無顏色
        self.selectionStyle = UITableViewCellSelectionStyleNone;
        self.backgroundColor = [UIColor clearColor];
        
        
        
        // 不管三七二十一,先把所有的控件實例化,並添加到contentView裡面
        // 1,頭像
        _headImg = [[UIImageView alloc]init];
        _headImg.layer.cornerRadius = 10;
        _headImg.layer.masksToBounds = YES;
        [self.contentView addSubview:_headImg];
        
       
        
        
        
        // 2,大圖片
        _bgImg = [[UIImageView alloc]init];
        [self.contentView addSubview:_bgImg];
        
        
        // 3,正文內容,添加大背景圖片裡面
        _content = [[UILabel alloc]init];
        _content.backgroundColor = [UIColor clearColor];

        // 正文內容用的字體,宏定義在.h
        _content.font = kContentFnt;
        _content.numberOfLines = 0;
        _content.lineBreakMode = NSLineBreakByWordWrapping;
        [_bgImg addSubview:_content];
        
        
    }
    return self;
}


// 通過一個Frames模型對象(它本身就含有一個數據 模型),返回一個填充好數據的cell對象,將參數Frames(內含對象)的所有成員frames和數據 設置到cell中的各個控件上面去
- (BeyondCell *)cellWithCellFrame:(BeyondCellFrame *)cellFrame
{
    Msg *msg = cellFrame.msg;
    
    
    // 將模型對象中的所有屬性值,全部賦值到cell對象中的成員控件上顯示
    // 1,頭像
    
    
    
    if ([msg.name isEqualToString:@"nana"]) {
        _headImg.image = [UIImage imageNamed:@"icon01.jpg"];
    } else {
        _headImg.image = [UIImage imageNamed:@"icon02.jpg"];
    }
    
    
    // 5,正文內容
    _content.text = msg.content;
    
    // 6,大圖片
    if ([msg.name isEqualToString:@"nana"]) {
        _bgImg.image = [UIImage imageStretchedWithName:@"chatfrom_bg_normal.png" xPos:0.5 yPos:0.6];

    } else {
        _bgImg.image = [UIImage
                    imageStretchedWithName:@"chatto_bg_normal.png" xPos:0.5 yPos:0.6];
    }
    
    
    
    
    // 1,頭像的frame
    _headImg.frame = cellFrame.headImgFrame;
    

    
    
    // 2,正文的frame
    _content.frame = cellFrame.contentFrame;
    
    // 3,bigImg的frame
    _bgImg.frame = cellFrame.contentBgImgFrame;
    
    
    

    
    
    return self;
}

@end


封裝的數據源Model

//
//  Msg.h
//  29_仿微信聊天
//
//  Created by beyond on 14-9-4.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  模型,成員:icon,正文text

#import 

// 內容 用的字體
#define kContentFnt [UIFont fontWithName:@"HelveticaNeue" size:18.0f]

@interface Msg : NSObject
// 頭像圖片名
@property (nonatomic,copy) NSString *headImg;


// 消息內容
@property (nonatomic,copy) NSString *content;

@property (nonatomic,copy) NSString *name;

@property (nonatomic,strong) NSString *recordFileFath;

// 類方法,字典 轉 對象 類似javaBean一次性填充
+ (Msg *)msgWithDict:(NSDictionary *)dict;
// 對象方法,設置對象的屬性後,返回對象
- (Msg *)initWithDict:(NSDictionary *)dict;

+ (Msg*)msgWithName:(NSString *)name content:(NSString *)content recordFilePath:(NSString *)path;
@end


//
//  Msg.m
//  29_仿微信聊天
//
//  Created by beyond on 14-9-4.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "Msg.h"

@implementation Msg

// 類方法,字典 轉 對象 類似javaBean一次性填充
+ (Msg *)msgWithDict:(NSDictionary *)dict
{
    return [[self alloc]initWithDict:dict];
}

// 對象方法,設置對象的屬性後,返回對象
- (Msg *)initWithDict:(NSDictionary *)dict
{
    // 必須先調用父類NSObject的init方法
    if (self = [super init]) {
        // 設置對象自己的屬性
        // 通過遍歷 將 字典 賦值為對象各個屬性
        for (NSString *key in dict) {
            [self setValue:dict[key] forKeyPath:key];
        }
        // 一次性 將 字典 賦值為對象各個屬性
        // [self setValuesForKeysWithDictionary:dict];
        
    }
    // 返回填充好的對象
    return self;
}

+ (Msg*)msgWithName:(NSString *)name content:(NSString *)content recordFilePath:(NSString *)path
{
    Msg *msg = [[self alloc]init];
    msg.name = name;
    msg.content = content;
    msg.recordFileFath = path;

    return msg;
}

@end


重點:根據數據源計算frame


//
//  BeyondCellFrame.h
//  29_仿微信聊天
//
//  Created by beyond on 14-9-4.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import 
@class Msg;
// 控件與控件之間的外邊距
#define kMargin 7
// 頭像的高寬
#define kHeadImgHW 85


@interface BeyondCellFrame : NSObject

// 最大的Y值,就是行高
@property (nonatomic,assign,readonly) CGFloat maxY;

// 重要,擁有一個成員:對象,目的是在控制器中,傳遞對象進來之後,可以通過此模型對象的數據,計算出所有的frames
@property (nonatomic,strong) Msg *msg;



// 頭像 的frame
@property (nonatomic,assign,readonly) CGRect headImgFrame;

// 聊天正文的背景圖片 的frame
@property (nonatomic,assign,readonly) CGRect contentBgImgFrame;

// 正文內容 的frame
@property (nonatomic,assign,readonly) CGRect contentFrame;




@end


//
//  BeyondCellFrame.m
//  29_仿微信聊天
//
//  Created by beyond on 14-9-4.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "BeyondCellFrame.h"
#import "Msg.h"
@implementation BeyondCellFrame



// CellFrame類 唯一的一個方法:設置Msg的時候,可以通過其數據,計算出各個frame,以及最大的Y,也就是行高
- (void)setMsg:(Msg *)msg
{
    _msg = msg;
    
    // 具體的計算各個frame的代碼,放在這兒~~~
    
    if ([msg.name isEqualToString:@"nana"]) {
        [self standLeft:msg];
    } else {
        [self standRight:msg];
    }
    
    
}
// 我說的放在右邊
- (void)standRight:(Msg *)msg
{
    // 1,頭像的frame
    // 頭像的x
    CGFloat headImgX = 320 - kHeadImgHW - kMargin;
    // 頭像的y
    CGFloat headImgY = 0;
    // 頭像的H
    CGFloat headImgH = kHeadImgHW;
    // 頭像的W
    CGFloat headImgW = kHeadImgHW;
    _headImgFrame = CGRectMake(headImgX, headImgY, headImgH, headImgW);
    
    
    //===============****************=======================
    
    // 2,bg的frame
    // 寬度W
    CGFloat bgW = 320 - kHeadImgHW - kMargin;
    // x
    CGFloat bgX = 320 - bgW - kHeadImgHW - kMargin;
    // y
    CGFloat bgY = 0;
    
    // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame].size.width;
    
    // 高度先假設 H
    CGFloat bgH = 300;
    _contentBgImgFrame = CGRectMake(bgX, bgY, bgW,bgH);
    
    
    //===============****************=======================

    // 3,正文的frame 正文添加到圖片裡面,以圖片的左上角為 0 0
    // x
    CGFloat contentX =  kMargin*1.5;
    // y
    CGFloat contentY = kMargin;
    
    
    // 寬度W 先假設大於一行
    CGFloat contentW = bgW - contentX - kMargin  ;
    CGFloat contentH = 0;
    
    // 判斷 內容夠不夠一行...
    // 根據字體得到NSString的尺寸
    CGSize oneLineSize = [msg.content sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil]];
    CGFloat oneLineW = oneLineSize.width;
    
    if (oneLineW < contentW) {
        // 如果不夠一行
        CGFloat oneLineH = oneLineSize.height;
        contentX =  kMargin * 1.2;
        _contentFrame = CGRectMake(contentX, contentY, oneLineW,oneLineH);
        
        contentH = oneLineH;
        contentW = oneLineW;
        
        // 5,重新調整 contentBgImg的frame的高度
        // 以下三步為OC標准代碼,因為OC中不允許直接修該對象中結構體屬性的成員的值,要通過中間的臨時結構體變量
        CGRect frame = _contentBgImgFrame;
        frame.size.width = contentW + kMargin *3.5;
        frame.size.height = contentH + kMargin * 3 ;
        frame.origin.x = 320 - contentW - headImgW - kMargin*4;
        _contentBgImgFrame = frame;
        
    } else {
        // 如果超過一行,按下面算法計算 高度
        // 根據內容動態設置 高度
        CGRect tmpRect = [msg.content boundingRectWithSize:CGSizeMake(contentW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil] context:nil];
        // 高度H
        contentH = tmpRect.size.height;
        _contentFrame = CGRectMake(contentX, contentY, contentW,contentH);
        
        // 5,重新調整 contentBgImg的frame的高度
        // 以下三步為OC標准代碼,因為OC中不允許直接修該對象中結構體屬性的成員的值,要通過中間的臨時結構體變量
        CGRect frame = _contentBgImgFrame;
        frame.size.height = contentH + kMargin * 3 ;
        _contentBgImgFrame = frame;
    }
    
    
    // 8,這個時候就可以計算最大Y 即行高了
    if (headImgH > _contentBgImgFrame.size.height) {
        _maxY = CGRectGetMaxY(_headImgFrame) + kMargin;
    } else {
        _maxY = CGRectGetMaxY(_contentBgImgFrame) + kMargin;
    }
}

- (void)standLeft:(Msg *)msg
{
    // 1,頭像的frame
    // 頭像的x
    CGFloat headImgX = kMargin;
    // 頭像的y
    CGFloat headImgY = kMargin;
    // 頭像的H
    CGFloat headImgH = kHeadImgHW;
    // 頭像的W
    CGFloat headImgW = kHeadImgHW;
    _headImgFrame = CGRectMake(headImgX, headImgY, headImgH, headImgW);
    
    
    //===============****************=======================
    
    // 4,bg的frame
    // x
    CGFloat bgX = _headImgFrame.size.width + kMargin;
    // y
    CGFloat bgY = _headImgFrame.origin.y;
    
    // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame].size.width;
    
    // 寬度W
    CGFloat bgW = 320 - bgX - kMargin;
    
    
    
    // 高度H
    CGFloat bgH = 300;
    _contentBgImgFrame = CGRectMake(bgX, bgY, bgW,bgH);
    
    
    
    
    
    // 4,正文的frame 正文添加到圖片裡面,以圖片的左上角為 0 0
    // x
    CGFloat contentX =  kMargin*3;
    // y
    CGFloat contentY = kMargin;
    
    // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame].size.width;
    
    // 寬度W 先假設大於一行
    CGFloat contentW = bgW - contentX - kMargin  ;
    CGFloat contentH = 0;
    
    // 判斷 內容夠不夠一行...
    // 根據字體得到NSString的尺寸
    CGSize oneLineSize = [msg.content sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil]];
    CGFloat oneLineW = oneLineSize.width;
    
    if (oneLineW < contentW) {
        // 如果不夠一行
        CGFloat oneLineH = oneLineSize.height;
        contentX =  kMargin * 2;
        _contentFrame = CGRectMake(contentX, contentY, oneLineW,oneLineH);
        
        contentH = oneLineH;
        contentW = oneLineW;
        
        // 5,重新調整 contentBgImg的frame的高度
        // 以下三步為OC標准代碼,因為OC中不允許直接修該對象中結構體屬性的成員的值,要通過中間的臨時結構體變量
        CGRect frame = _contentBgImgFrame;
        frame.size.width = contentW + kMargin *3.5;
        frame.size.height = contentH + kMargin * 3 ;
        _contentBgImgFrame = frame;
        
    } else {
        // 如果超過一行,按下面算法計算 高度
        // 根據內容動態設置 高度
        CGRect tmpRect = [msg.content boundingRectWithSize:CGSizeMake(contentW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:kContentFnt,NSFontAttributeName, nil] context:nil];
        // 高度H
        contentH = tmpRect.size.height;
        _contentFrame = CGRectMake(contentX, contentY, contentW,contentH);
        
        // 5,重新調整 contentBgImg的frame的高度
        // 以下三步為OC標准代碼,因為OC中不允許直接修該對象中結構體屬性的成員的值,要通過中間的臨時結構體變量
        CGRect frame = _contentBgImgFrame;
        frame.size.height = contentH + kMargin * 3 ;
        _contentBgImgFrame = frame;
    }
    
    
    // 8,這個時候就可以計算最大Y 即行高了
    if (headImgH > _contentBgImgFrame.size.height) {
        _maxY = CGRectGetMaxY(_headImgFrame) + kMargin;
    } else {
        _maxY = CGRectGetMaxY(_contentBgImgFrame) + kMargin;
    }
}
@end


控制器

//
//  BeyondViewController.m
//  29_仿微信聊天
//
//  Created by beyond on 14-9-2.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "BeyondViewController.h"
#import "Msg.h"
#import "BeyondCellFrame.h"
#import "BeyondCell.h"

@interface BeyondViewController ()
{
    // 從plist文件中加載的所有weiboFrames(因為它已經含有一個weibo成員),返回所有的對象組成的數組
    NSMutableArray *_msgFrames;
}
@end

@implementation BeyondViewController





- (void)viewDidLoad
{
    [super viewDidLoad];
    // 初始化 對象數組
    _msgFrames = [NSMutableArray array];
}

#pragma mark - UITextField代理,發送請求
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    
    if (textField.text.length == 0){
        return NO;
    }
    
    

    BeyondCellFrame *frame = [[BeyondCellFrame alloc]init];
    // ***********設置的WeiboFrames的成員weibo的同時,進行了復雜的計算,並填充了WeiboFrames各個frame成員
    frame.msg = [Msg msgWithName:@"jackey" content:textField.text recordFilePath:@"NoRecord"];
    // 添加到對象數組
    [_msgFrames addObject:frame];
    [self.tableView reloadData];
    return YES;
}

#pragma mark - UITableView代理方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    //去除cell間隔線
    tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    
    // 返回對象數組的長度
    return _msgFrames.count;
}
// 生成自定義的cell,並傳遞cellFrame給它,設置好後,返回cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1,從池中取
    BeyondCell *cell = [tableView dequeueReusableCellWithIdentifier:[BeyondCell cellID]];
    // 2,取不到的時候,創建一個純潔的WeiboCell
    if (cell == nil) {
        cell = [[BeyondCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[BeyondCell cellID]];
    }
    // 3,設置獨一無二的數據
    BeyondCellFrame *frame = [_msgFrames objectAtIndex:indexPath.row];
    cell = [cell cellWithCellFrame:frame];
    return cell;
}
// cellFrame對象數組有每一行的行高,其內部已經計算好了
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    // cellFrame的成員有:Msg數據模型對象,以及根據數據模型計算出來的所有的frames,以及最大的Y即對應數據模型的行高
    BeyondCellFrame *frame = [_msgFrames objectAtIndex:indexPath.row];
    return frame.maxY;
}

// 恢復view全屏,並且讓鍵盤退出
- (void)exitKeyboard
{
    [UIView animateWithDuration:0.2 animations:^{
        self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, [[UIScreen mainScreen]bounds].size.height);
        
    }completion:^(BOOL finished){}];
    [_chatInput resignFirstResponder];
}
// 滾至表格最後一行
- (void)scrollToLastCell;
{
    if (_msgFrames.count >1) {
        [self.chatTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:_msgFrames.count-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
    }
}









  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved