码迷,mamicode.com
首页 > 其他好文 > 详细

UI基础--UITableView实现仿QQ聊天页面

时间:2015-01-04 06:21:29      阅读:932      评论:0      收藏:0      [点我收藏+]

标签:

需求:类似于QQ聊天页面的展示,内容包括有头像、时间、聊天内容。相同时间发生的内容,只显示第一条内容的时间,并且点击输入框时,可以滚动到最后一条内容信息。具体效果图:

技术分享

实例的文件结构:

技术分享

实现的具体步骤:

1、布局界面,主要包括一个UIImageView、3个UIButton、1个UITextField;

2、自定义数据模型类,并测试数据是否能正常加载;

3、自定义cell,由于每行数据的高度都是不规则的,所以考虑先自定义好frame再来写自定义cell。属性包括frame模型以及生成可重用cell的方法,要注意的是需要重写- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier方法,写给cell各子控件赋值以及生成frame的方法;

4、自定义frame,属性包括模型数据和行高以及cell中各个子控件的frame;

5、在控制器中写UITableView的 数据显示的方法;

6、订阅键盘通知,并且弹出键盘时,改变view的frame,最后也要记得销毁通知(有订阅就要有销毁);

7、写UITextFieldDelegate方法,在界面中显示新发送的消息;

 

具体的代码:

Model:

 

 1 //
 2 //  JWMessage.h
 3 //  12-24-Message-Two
 4 //
 5 //  Created by xiaomoge on 14/12/24.
 6 //  Copyright (c) 2014年 xiaomoge. All rights reserved.
 7 //
 8 
 9 #import <Foundation/Foundation.h>
10 typedef enum {
11     JWMessageTypeSelf,
12     JWMessageTypeOther
13 } JWMessageType;
14 @interface JWMessage : NSObject
15 @property (nonatomic,copy) NSString *text;
16 @property (nonatomic,copy) NSString *time;
17 @property (nonatomic,assign) JWMessageType type;
18 @property (nonatomic,assign,getter=isHiddemTime) BOOL hiddemTime;
19 - (instancetype)initWithDic:(NSDictionary *)dic;
20 + (instancetype)messageWithDic:(NSDictionary *)dic;
21 + (NSMutableArray *)messageList;
22 @end

 

 

 1 //
 2 //  JWMessage.m
 3 //  12-24-Message-Two
 4 //
 5 //  Created by xiaomoge on 14/12/24.
 6 //  Copyright (c) 2014年 xiaomoge. All rights reserved.
 7 //
 8 
 9 #import "JWMessage.h"
10 
11 @implementation JWMessage
12 - (instancetype)initWithDic:(NSDictionary *)dic {
13     if (self = [super init]) {
14         [self setValuesForKeysWithDictionary:dic];
15     }
16     return self;
17 }
18 + (instancetype)messageWithDic:(NSDictionary *)dic {
19     return [[self alloc] initWithDic:dic];
20 }
21 
22 + (NSMutableArray *)messageList {
23     NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"messages" ofType:@"plist"]];
24     
25     NSMutableArray *tempArray = [NSMutableArray array];
26     //定义一个前信息
27     JWMessage *preMessage;
28     for (NSDictionary *dic in array) {
29         JWMessage *message = [JWMessage messageWithDic:dic];
30         //判断前信息和当前信息是否相同,如相同即隐藏当前信息的时间frame
31         if ([message.time isEqualToString:preMessage.time]) {
32             message.hiddemTime = YES;
33         }
34         [tempArray addObject:message];
35         //获得前信息的数据
36         preMessage = [tempArray lastObject];
37     }
38     return tempArray;
39 }
40 @end

 

 1 //
 2 //  JWMessageFrame.h
 3 //  12-24-Message-Two
 4 //
 5 //  Created by xiaomoge on 14/12/24.
 6 //  Copyright (c) 2014年 xiaomoge. All rights reserved.
 7 //
 8 #define TEXTFONT 14
 9 #import <UIKit/UIKit.h>
10 @class JWMessage;
11 @interface JWMessageFrame : NSObject
12 @property (nonatomic,assign) CGFloat rowHeight;
13 @property (nonatomic,assign) CGRect timeFrame;
14 @property (nonatomic,assign) CGRect iconFrame;
15 @property (nonatomic,assign) CGRect textFrame;
16 @property (nonatomic,strong) JWMessage *message;
17 + (NSMutableArray *)messageFrameList;
18 @end

 

 1 //
 2 //  JWMessageFrame.m
 3 //  12-24-Message-Two
 4 //
 5 //  Created by xiaomoge on 14/12/24.
 6 //  Copyright (c) 2014年 xiaomoge. All rights reserved.
 7 //
 8 
 9 #import "JWMessageFrame.h"
10 #import "JWMessage.h"
11 #import "NSString+Ext.h"
12 @implementation JWMessageFrame
13 /*
14  重写set方法,设置fram
15  */
16 - (void)setMessage:(JWMessage *)message {
17     _message = message;
18     
19     //屏幕宽度
20     UIScreen *screen = [UIScreen mainScreen];
21     CGFloat screenW = screen.bounds.size.width;
22     //间距
23     CGFloat margin = 10;
24     
25     //时间frame
26     if (!message.hiddemTime) {//如果时间不相同时,才设置时间的frame
27         _timeFrame = CGRectMake(0, 0, screenW, 40);
28     }
29         
30     //头像frame
31     CGFloat iconW = 50;
32     CGFloat iconH = 50;
33     CGFloat iconX;
34     CGFloat iconY = CGRectGetMaxY(_timeFrame);
35     if (message.type == JWMessageTypeSelf) {
36         //自己的头像在右边,所以是屏幕的宽度减去间距,再减去头像的宽度
37         iconX = screenW - margin - iconW;
38     }else {
39         iconX = margin;
40     }
41     _iconFrame = CGRectMake(iconX, iconY, iconW, iconH);
42     
43     //内容frame
44     //取得内容的大小
45     CGSize textSize = [message.text setTextSize:CGSizeMake(200, MAXFLOAT) andFontSize:TEXTFONT];
46     //取得内容按钮的大小
47     CGSize btnSize = CGSizeMake(textSize.width + 40, textSize.height + 40);
48     CGFloat textX;
49     //内容的Y值和头像的Y值是一样的
50     CGFloat textY = iconY;
51     if (message.type == JWMessageTypeSelf) {
52         //自己的内容在右边,所以是头像的X值减去按钮的宽度,再减去间距
53         textX = iconX - btnSize.width - margin;
54     }else {
55         //对方的内容在左边,所以是头像的宽度加上间距
56         textX = iconW + margin;
57     }
58     _textFrame = CGRectMake(textX, textY, btnSize.width, btnSize.height);
59     
60     //行高
61     //取得内容的最大Y值
62     CGFloat textMax = CGRectGetMaxY(_textFrame);
63     //取得头像的最大Y值
64     CGFloat iconMax = CGRectGetMaxY(_iconFrame);
65     //行高的多少是根据内容多少来判断的,内容少时是头像的最大Y值,内容过多时,就是内容的最大Y值了,所以用了一个MAX函数,取最大值
66     _rowHeight = MAX(textMax, iconMax) + margin;
67     
68 }
69 + (NSMutableArray *)messageFrameList {
70     NSArray *message = [JWMessage messageList];
71     NSMutableArray *tem = [NSMutableArray array];
72     for (JWMessage *msg in message) {
73         JWMessageFrame *frame = [[JWMessageFrame alloc] init];
74         frame.message = msg;
75         [tem addObject:frame];
76     }
77     return tem;
78 }
79 @end

 

View:

 1 //
 2 //  JWMessageCell.h
 3 //  12-24-Message-Two
 4 //
 5 //  Created by xiaomoge on 14/12/24.
 6 //  Copyright (c) 2014年 xiaomoge. All rights reserved.
 7 //
 8 
 9 #import <UIKit/UIKit.h>
10 @class JWMessageFrame;
11 @interface JWMessageCell : UITableViewCell
12 @property (nonatomic,strong) JWMessageFrame *messageFrame;
13 + (instancetype)cellWithTableView:(UITableView *)tableView;
14 @end

 

 1 //
 2 //  JWMessageCell.m
 3 //  12-24-Message-Two
 4 //
 5 //  Created by xiaomoge on 14/12/24.
 6 //  Copyright (c) 2014年 xiaomoge. All rights reserved.
 7 //
 8 
 9 #import "JWMessageCell.h"
10 #import "JWMessage.h"
11 #import "JWMessageFrame.h"
12 #import "UIImage+Ext.h"
13 @interface JWMessageCell ()
14 @property (nonatomic,weak) UILabel *timeLabel;
15 @property (nonatomic,weak) UIImageView *iconView;
16 @property (nonatomic,weak) UIButton *textBtn;
17 @end
18 @implementation JWMessageCell
19 //创建可重用的cell
20 + (instancetype)cellWithTableView:(UITableView *)tableView {
21     //创建缓存池标识
22     static NSString *resue = @"msg";
23     //当缓存池有空闲的cell时,可重用
24     JWMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:resue];
25     //当缓存池内暂时没有空闲的cell时,自动创建
26     if (!cell) {
27         cell = [[self alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:resue];
28     }
29     return cell;
30 }
31 //重写
32 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
33     if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
34         //清除背景颜色
35         self.backgroundColor = [UIColor clearColor];
36         //初始化时间子控件
37         UILabel *time = [[UILabel alloc] init];
38         [self.contentView addSubview:time];
39         self.timeLabel = time;
40         //把时间居中显示
41         time.textAlignment = NSTextAlignmentCenter;
42         //初始化头像子控件
43         UIImageView *img = [[UIImageView alloc] init];
44         [self.contentView addSubview:img];
45         self.iconView = img;
46         //设置头像的圆角
47         img.layer.cornerRadius = 25;
48         //设置是否剪裁多余的部分
49         img.layer.masksToBounds = YES;
50         //初始化内容子控件
51         UIButton *text = [UIButton buttonWithType:UIButtonTypeCustom];
52         [self.contentView addSubview:text];
53         self.textBtn = text;
54         [text setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
55         text.titleLabel.numberOfLines = 0;
56         //设置内容的间距
57         text.contentEdgeInsets = UIEdgeInsetsMake(20, 20, 20, 20);
58         //设置内容的字体大小
59         text.titleLabel.font = [UIFont systemFontOfSize:TEXTFONT];
60     }
61     return self;
62 }
63 - (void)setMessageFrame:(JWMessageFrame *)messageFrame {
64     _messageFrame = messageFrame;
65     [self setSubviewsContent];
66     [self setSubviewsFrame];
67 }
68 - (void)setSubviewsContent {
69     JWMessage *msg = self.messageFrame.message;
70     //给时间子控件赋值
71     self.timeLabel.text = msg.time;
72     //给头像子控件赋值
73     self.iconView.image = [UIImage imageNamed:msg.type == JWMessageTypeSelf ? @"me" :@"other"];
74     //给内容子控件赋值
75     [self.textBtn setTitle:msg.text forState:UIControlStateNormal];
76     //设置内容子控件的背景图片
77     if (msg.type == JWMessageTypeSelf) {
78        [self.textBtn setBackgroundImage:[UIImage setImage:@"chat_send_nor"] forState:UIControlStateNormal];
79         [self.textBtn setBackgroundImage:[UIImage setImage:@"chat_send_press_pic"] forState:UIControlStateHighlighted];
80     }else {
81         [self.textBtn setBackgroundImage:[UIImage setImage:@"chat_recive_nor"] forState:UIControlStateNormal];
82         [self.textBtn setBackgroundImage:[UIImage setImage:@"chat_recive_press_pic"] forState:UIControlStateHighlighted];
83     }
84 }
85 - (void)setSubviewsFrame {
86     self.timeLabel.frame = self.messageFrame.timeFrame;
87     self.iconView.frame = self.messageFrame.iconFrame;
88     self.textBtn.frame = self.messageFrame.textFrame;
89 }
90 @end

 

Controller:

 1 //
 2 //  ViewController.m
 3 //  12-24-Message-Two
 4 //
 5 //  Created by xiaomoge on 14/12/24.
 6 //  Copyright (c) 2014年 xiaomoge. All rights reserved.
 7 //
 8 
 9 #import "ViewController.h"
10 #import "JWMessage.h"
11 #import "JWMessageFrame.h"
12 #import "JWMessageCell.h"
13 @interface ViewController ()<UITextFieldDelegate,UITableViewDataSource,UITableViewDelegate>
14 @property (weak, nonatomic) IBOutlet UITableView *tableView;
15 @property (nonatomic,strong) NSMutableArray *messageFrame;
16 @end
17 
18 @implementation ViewController
19 #pragma mark - 隐藏状态栏
20 - (BOOL)prefersStatusBarHidden {
21     return YES;
22 }
23 #pragma mark - 懒加载
24 - (NSMutableArray *)messageFrame {
25     if (!_messageFrame) {
26         _messageFrame = [JWMessageFrame messageFrameList];
27     }
28     return _messageFrame;
29 }
30 - (void)viewDidLoad {
31     [super viewDidLoad];
32     //取消分割线
33     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
34     //设置背景颜色
35     self.tableView.backgroundColor = [UIColor colorWithRed:240/255.0 green:240/255.0 blue:240/255.0 alpha:1];
36     //订阅键盘通知
37     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clickTableView:) name:UIKeyboardWillChangeFrameNotification object:nil];
38 }
39 //键盘frame发生改变时,view也跟着改变
40 - (void)clickTableView:(NSNotification *)noti {
41     CGFloat duration = [noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
42     CGRect frame = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
43     CGFloat offX = frame.origin.y - self.view.frame.size.height;
44     [UIView animateWithDuration:duration animations:^{
45         self.view.transform = CGAffineTransformMakeTranslation(0, offX);
46     }];
47 }
48 //销毁订阅键盘通知
49 - (void)dealloc {
50     [[NSNotificationCenter defaultCenter] removeObserver:self];
51 }
52 #pragma mark - UITableViewDataSource方法
53 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
54     return self.messageFrame.count;
55 }
56 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
57     JWMessageCell *cell = [JWMessageCell cellWithTableView:tableView];
58     cell.messageFrame = self.messageFrame[indexPath.row];
59     return cell;
60 }
61 #pragma mark - UITableViewDelegate方法
62 - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
63     JWMessageFrame *frame = self.messageFrame[indexPath.row];
64     return frame.rowHeight;
65 }
66 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
67     [self.view endEditing:YES];
68 }
69 #pragma mark - UITextFieldDelegate方法
70 -(BOOL)textFieldShouldReturn:(UITextField *)textField {
71     JWMessage *msg = [[JWMessage alloc] init];
72     msg.type = JWMessageTypeSelf;
73     msg.text = textField.text;
74     NSDate *date = [NSDate date];
75     NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
76     formatter.dateFormat = @"HH:mm";
77     msg.time = [formatter stringFromDate:date];
78     
79     //判断前一条信息和当前信息的时间是否相同
80     JWMessage *preMessage = (JWMessage *)[[self.messageFrame lastObject] message];
81     if ([preMessage.time isEqualToString:msg.time]) {
82         msg.hiddemTime = YES;
83     }
84     
85     JWMessageFrame *frame = [[JWMessageFrame alloc] init];
86     frame.message = msg;
87     [self.messageFrame addObject:frame];
88     
89     //重新加载数据
90     [self.tableView reloadData];
91     NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messageFrame.count - 1 inSection:0];
92     //滚动显示最后一条数据
93     [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
94     return YES;
95 }
96 @end

 

Category:

 1 //
 2 //  UIImage+Ext.m
 3 //  12-24-Message-Two
 4 //
 5 //  Created by xiaomoge on 14/12/24.
 6 //  Copyright (c) 2014年 xiaomoge. All rights reserved.
 7 //
 8 
 9 #import "UIImage+Ext.h"
10 
11 @implementation UIImage (Ext)
12 //平铺图片,改变图片的大小
13 + (UIImage *)setImage:(NSString *)name {
14     UIImage *imageName = [UIImage imageNamed:name];
15     return [imageName stretchableImageWithLeftCapWidth:imageName.size.width * 0.5 topCapHeight:imageName.size.height * 0.5];
16 }
17 @end

Category中的NSString+Ext内容和上一篇的内容是一样的,都是获取文字的大小,可回看。http://www.cnblogs.com/xiaomoge/p/4200169.html

在这里,要注意的:

1、Category中的方法,该方法是在图片的中心,获取1X的像素来平铺图片,直到平铺满整个图片为止。

 

UI基础--UITableView实现仿QQ聊天页面

标签:

原文地址:http://www.cnblogs.com/xiaomoge/p/4200221.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!