首页 > 代码库 > UI基础之UITableView案例QQ聊天界面

UI基础之UITableView案例QQ聊天界面

数据模型:

#import <Foundation/Foundation.h>typedef enum{    LLMessageTypeMe,    LLMessageTypeOther}LLMessageType;@interface LLMessage : NSObject/** *  time */@property (nonatomic, copy) NSString *time;/** *  text */@property (nonatomic, copy) NSString *text;/** *  type 定义为枚举类型的好处 */@property (nonatomic, assign) LLMessageType type;/** *  hiddenTime 时间是否隐藏 */@property (nonatomic, assign, getter=isHiddenTime) BOOL hiddenTime;- (instancetype)initWithDic:(NSDictionary *)dic;+ (instancetype)messageWithDic:(NSDictionary *)dic;+ (NSMutableArray *)messageList;@end
#import "LLMessage.h"@implementation LLMessage- (instancetype)initWithDic:(NSDictionary *)dic{    if (self = [super init]) {        [self setValuesForKeysWithDictionary:dic];    }    return self;}+ (instancetype)messageWithDic:(NSDictionary *)dic{    return [[self alloc] initWithDic:dic];}+ (NSMutableArray *)messageList{    NSString *path = [[NSBundle mainBundle] pathForResource:@"messages" ofType:@"plist"];    NSArray *dicArr = [NSArray arrayWithContentsOfFile:path];        NSMutableArray *tmpArr = [[NSMutableArray alloc] initWithCapacity:dicArr.count];    for (NSDictionary *dic in dicArr) {        LLMessage *endMessage = [tmpArr lastObject];        LLMessage *message = [LLMessage messageWithDic:dic];                if ([message.time isEqualToString:endMessage.time]) {                        message.hiddenTime = YES;        }                [tmpArr addObject:message];    }    return tmpArr;}@end

frame模型

#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>#define LLTIMEFONT [UIFont systemFontOfSize:12]#define LLTEXTFONT [UIFont systemFontOfSize:13]#define LLPADDING 20@class LLMessage;@interface LLMessageFrame : NSObject@property (nonatomic, strong) LLMessage *message;@property (nonatomic, assign,readonly) CGRect timeF;@property (nonatomic, assign, readonly) CGRect textF;@property (nonatomic, assign, readonly) CGRect iconF;@property (nonatomic, assign, readonly) CGFloat cellHeight;+ (NSMutableArray *)messageFrameList;@end
#import "LLMessageFrame.h"#import "LLMessage.h"#import "NSString+LLNSStringExtension.h"@implementation LLMessageFrame+ (NSMutableArray *)messageFrameList{    NSMutableArray *messageArr = [LLMessage messageList];    NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithCapacity:messageArr.count];    for (LLMessage *message in messageArr) {        LLMessageFrame *frame = [[LLMessageFrame alloc] init];        frame.message = message;        [tmpArray addObject:frame];    }    return tmpArray;}- (void)setMessage:(LLMessage *)message{    _message = message;        CGFloat margin = 10;    // 时间    CGFloat timeX = 0;    CGFloat timeY = 0;    CGFloat timeW = 320;    CGFloat timeH = 40;    if (!message.isHiddenTime){        _timeF = CGRectMake(timeX, timeY, timeW, timeH);    }        // icon    CGFloat iconY = CGRectGetMaxY(_timeF);    CGFloat iconWH = 30;    CGFloat iconX;    if (message.type == LLMessageTypeMe) { // Me                iconX = timeW - iconWH - margin;    } else { // Other                iconX = margin;    }    _iconF = CGRectMake(iconX, iconY, iconWH, iconWH);        // text    CGFloat textY = iconY;    CGSize textSize = [message.text textOfSize:CGSizeMake(200, MAXFLOAT) font:LLTEXTFONT];    CGSize buttonSize = CGSizeMake(textSize.width + LLPADDING * 2, textSize.height + LLPADDING * 2);    CGFloat textX;    if (message.type == LLMessageTypeMe) { // Me                textX = iconX - margin - buttonSize.width;    } else {                textX = CGRectGetMaxX(_iconF) + margin;    }    _textF = (CGRect){{textX, textY} , buttonSize};        CGFloat textMaxY = CGRectGetMaxY(_textF);    CGFloat iconMaxY = CGRectGetMaxY(_iconF);        _cellHeight = MAX(textMaxY, iconMaxY);    }@end

代码自定义cell

#import <UIKit/UIKit.h>@class LLMessageFrame;@interface LLMessageCell : UITableViewCell@property (nonatomic, strong) LLMessageFrame *messageFrame;+ (instancetype)messageCellWith:(UITableView *)tableView;@end
#import "LLMessageCell.h"#import "LLMessageFrame.h"#import "LLMessage.h"#import <UIKit/UIKit.h>#import "UIImage+LLUIImageExtension.h"@interface LLMessageCell ()@property (nonatomic, weak) UILabel *timeView;@property (nonatomic, weak) UIImageView *iconView;@property (nonatomic, weak) UIButton *textView;@end@implementation LLMessageCell+ (instancetype)messageCellWith:(UITableView *)tableView{    static NSString *ID = @"messageCell";    LLMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];    if (!cell) {                cell = [[LLMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];    }    return cell;}- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {                // 创建cell子控件        self.backgroundColor = [UIColor clearColor];        // time        UILabel *timeView = [[UILabel alloc] init];        [self.contentView addSubview:timeView];        timeView.textAlignment = NSTextAlignmentCenter;        timeView.font = LLTIMEFONT;        self.timeView = timeView;                // icon        UIImageView *iconView = [[UIImageView alloc] init];        [self.contentView addSubview:iconView];        self.iconView = iconView;                // text        UIButton *textView = [[UIButton alloc] init];        [self.contentView addSubview: textView];        textView.titleLabel.font = LLTEXTFONT;        textView.titleLabel.numberOfLines = 0;        textView.contentEdgeInsets = UIEdgeInsetsMake(LLPADDING, LLPADDING, LLPADDING, LLPADDING);        self.textView = textView;                    }    return self;}- (void)setMessageFrame:(LLMessageFrame *)messageFrame{    _messageFrame = messageFrame;        // 1,设置数据    [self setDate];        // 2,设置frame    [self setSubviewsFrame];}- (void)setDate{    LLMessage *message = self.messageFrame.message;    self.timeView.text = message.time;        NSString *iconName = message.type == LLMessageTypeMe ? @"me" : @"other";    self.iconView.image = [UIImage imageNamed:iconName];    // 设置图片背景        #warning 设置按钮上label字体方法    [self.textView setTitle:message.text forState:UIControlStateNormal];    if (message.type == LLMessageTypeMe) {        [self.textView setBackgroundImage:[UIImage registerImage:@"chat_send_nor"] forState:UIControlStateNormal];        [self.textView setBackgroundImage:[UIImage registerImage:@"chat_send_press_pic"] forState:UIControlStateHighlighted];        [self.textView setTitleColor:[UIColor redColor] forState:UIControlStateNormal];    } else {        [self.textView setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];        [self.textView setBackgroundImage:[UIImage registerImage:@"chat_recive_nor"] forState:UIControlStateNormal];        [self.textView setBackgroundImage:[UIImage registerImage:@"chat_recive_press_pic"] forState:UIControlStateHighlighted];    }}- (void)setSubviewsFrame{    self.timeView.frame = self.messageFrame.timeF;    self.iconView.frame = self.messageFrame.iconF;    self.textView.frame = self.messageFrame.textF;}@end

分类:NSString

#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@interface NSString (LLNSStringExtension)- (CGSize)textOfSize:(CGSize)maxSize font:(UIFont *)font;@end#import "NSString+LLNSStringExtension.h"@implementation NSString (LLNSStringExtension)- (CGSize)textOfSize:(CGSize)maxSize font:(UIFont *)font{    return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : font} context:nil].size;}@end

UIImage分类

#import <UIKit/UIKit.h>@interface UIImage (LLUIImageExtension)+ (UIImage *)registerImage:(NSString *)imageName;@end#import "UIImage+LLUIImageExtension.h"#import <UIKit/UIKit.h>@implementation UIImage (LLUIImageExtension)+ (UIImage *)registerImage:(NSString *)imageName{    UIImage * image = [UIImage imageNamed:imageName];    return [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5];}@end

controller:

#import "ViewController.h"#import "LLMessageFrame.h"#import "LLMessage.h"#import "LLMessageCell.h"@interface ViewController () <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>@property (nonatomic, strong) NSMutableArray *messageFrames;@property (weak, nonatomic) IBOutlet UITableView *tableView;@property (weak, nonatomic) IBOutlet UIView *footerView;@property (weak, nonatomic) IBOutlet UITextField *textField;@end@implementation ViewController#pragma mark - 懒加载数据模型- (NSMutableArray *)messageFrames{    if (!_messageFrames) {               _messageFrames = [LLMessageFrame messageFrameList];    }    return _messageFrames;}- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.        // 隐藏分割线    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;        // 取消tableView的点击    self.tableView.allowsSelection = NO;    self.tableView.backgroundColor = [UIColor colorWithRed:240/255.0 green:224/255.0 blue:224/255.0 alpha:1.0];        // 监听通知    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clickTextFiled:) name:UIKeyboardWillChangeFrameNotification object:nil];        // 设置文本框左边内容默认有间距    self.textField.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 8, 0)];    self.textField.leftViewMode = UITextFieldViewModeAlways;}- (void)clickTextFiled:(NSNotification *)noti{    CGRect rect = [noti.userInfo[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];    CGFloat moveY = rect.origin.y - self.view.frame.size.height;    self.view.transform = CGAffineTransformMakeTranslation(0, moveY);}- (void)dealloc{    [[NSNotificationCenter defaultCenter] removeObserver:self];}#pragma mark - 数据源方法- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    return self.messageFrames.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    // 1,创建cell    LLMessageCell *cell = [LLMessageCell messageCellWith:tableView];        // 2,设置cell    cell.messageFrame = self.messageFrames[indexPath.row];        return cell;}#pragma mark - 代理方法- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    return [self.messageFrames[indexPath.row] cellHeight];}- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{    [self.view endEditing:YES];}#pragma mark - 文本框代理方法- (BOOL)textFieldShouldReturn:(UITextField *)textField{    LLMessageFrame *frame = [[LLMessageFrame alloc] init];    LLMessage *message = [[LLMessage alloc] init];    NSDate *date = [NSDate date];    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];    formatter.dateFormat = @"hh:mm";    NSString *time = [formatter stringFromDate:date];    message.time = time;    message.text = textField.text;    message.type = LLMessageTypeMe;    LLMessageFrame *lastMF = [self.messageFrames lastObject];    if ([lastMF.message.time isEqualToString:message.time]) {        message.hiddenTime = YES;    }        frame.message = message;    [self.messageFrames addObject:frame];        // 刷新    [self.tableView reloadData];        // 自动上滚    NSIndexPath *path = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0];    [self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionBottom animated:YES];            textField.text = nil;    return YES;}- (BOOL)prefersStatusBarHidden{    return YES;}@end

效果;

UI基础之UITableView案例QQ聊天界面