zoukankan      html  css  js  c++  java
  • UI基础--UITableView实现仿QQ聊天页面

    需求:类似于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的像素来平铺图片,直到平铺满整个图片为止。

     

  • 相关阅读:
    PAT B1027 打印沙漏 (20 分)
    PAT B1025 反转链表 (25 分)
    PAT B1022 D进制的A+B (20 分)
    PAT B1018 锤子剪刀布 (20 分)
    PAT B1017 A除以B (20 分)
    PAT B1015 德才论 (25 分)
    PAT B1013 数素数 (20 分)
    PAT B1010 一元多项式求导 (25 分)
    HDU 1405 The Last Practice
    HDU 1165 Eddy's research II
  • 原文地址:https://www.cnblogs.com/xiaomoge/p/4200221.html
Copyright © 2011-2022 走看看