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

效果;

posted @ 2014-11-30 21:01  _boy  阅读(1005)  评论(0编辑  收藏  举报