博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS聊天室 简单的对话聊天界面(cell自适应高度)
阅读量:4141 次
发布时间:2019-05-25

本文共 11536 字,大约阅读时间需要 38 分钟。

文章目录

难点

  • 因为聊天长度不一样,需要设置自适应高度
  • 发送信息后,需要使tableView添加一条cell,并更新
  • cell的所有子视图需要清除,否则会有bug(在最后会附上不清除子视图的效果)
  • 键盘弹出界面上移,点击空白处键盘回收,界面下移

思路

  • 聊天界面的对话其实就是一个tableView,创建一个可变数组记录每句话的高度,根据话语的高度设置单元格高度
  • 按发送键时插入一条新cell在最底端,获取该条对话的高度,存入数组,并让界面随着消息上移
  • 对话的label和聊天气泡的imageView随着对话的长度改变位置(这里没有什么一定的距离,自己观察在适合的顺眼的地方就成)

需要用到的方法的大致解析(只是简单的介绍,如果想要仔细理解推荐再去看看别的博客)

有的内容是我从别的博客中看到的,如有侵权请私聊我

有些我认为不太容易理解的方法在代码中也会有注释

  • boundingRectWithSize: options: attributes: context:

    用于计算自适应高度
    P1:文本显示的最大宽度和最大高度
    P2:计算的类型 NSStringDrawingUsesLineFragmentOrigin 绘制文本时使用,一般使用这项
    P3:文本属性
    P4:包括一些信息,例如如何调整字间距以及缩放。该参数一般可为 nil

  • NSDictionary *attri = @{NSFontAttributeName:[UIFont systemFontOfSize:18]};

    设置字典数组字体大小为18
    另外, 方法 NSForegroundColorAttributeName 为设置字典数组字体颜色
    NSBackgroundColorAttributeName: 设置背景颜色

  • insertRowsAtIndexPaths: withRowAnimation:

    在索引路径处插入行
    P1: 想要该行数之后
    P2: 指定插入单元格时要执行的动画类型
    此处我们使用UITableViewRowAnimationBottom动画类型,从底部滑入或滑出
    另外:
    UITableViewRowAnimationFade, 淡入或淡出UITableViewRowAnimationRight, 从右侧滑入或滑出 UITableViewRowAnimationLeft,从左侧滑入或滑出UITableViewRowAnimationTop, 从顶部滑入或滑出UITableViewRowAnimationBottom, 从底部滑入或滑出UITableViewRowAnimationNone, 使用默认动画,上部或下部cell,上下移动覆盖掉要删除的cell
    可参考简书 :

  • NSNotificationCenter

    观察者,在该代码中我们用于监测键盘的弹出及回收
    具体了解可看苹果公司:

  • scrollToRowAtIndexPath: atScrollPosition: animated:

    滚动视图至指定位置,该代码中我们用它来滚动视图(随着消息上移)
    P1: 索引行
    P2:标识row滚动结束时表视图中的相对位置
    P3: 是否产生动画效果(即缓冲)
    另外:
    UITableViewScrollPositionNone 表格视图以最小的移动滚动感兴趣的行,使其完全可见。如果该行已完全可见,则不会进行滚动
    UITableViewScrollPositionTop 表视图将感兴趣的行滚动到可见表视图的顶部。
    UITableViewScrollPositionMiddle 表视图将感兴趣的行滚动到可见表视图的中间。
    UITableViewScrollPositionBottom 表视图将感兴趣的行滚动到可见表视图的底部。

  • animateWithDuration: animations:

    P1:动画持续时间
    P2:方法, 这里让视图恢复原来的位置就好

前面说了这么多,下来放代码

GitHub地址

代码

此处我采用导航栏跳转的方式跳转至该界面,在第一个界面中设置点击跳转事件就好

ViewController.m 里:

- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view.        ChatViewController *chat = [[ChatViewController alloc] init];        _nav = [[UINavigationController alloc] initWithRootViewController:chat];}- (void)touchesBegan:(NSSet
*)touches withEvent:(UIEvent *)event { [self presentViewController:_nav animated:NO completion:nil];}

下来在 ChatViewController.h 中声明需要的属性及协议:

@interface ChatViewController : UIViewController
@property UITextField *textField;@property UITableView *tableView;@property NSMutableArray *messageArr;@property (nonatomic) NSNumber *rowHeight;@property NSMutableArray *rowHeightArr;

在 ChatViewController.m 里写具体操作:

首先,为了方便起见,宏定义屏幕的宽高

#define W ([UIScreen mainScreen].bounds.size.width)#define H ([UIScreen mainScreen].bounds.size.height)

在 - (void)viewDidLoad 里初始化

self.view.backgroundColor = [UIColor whiteColor];    self.navigationController.navigationBar.barTintColor = [UIColor colorWithRed:0.21 green:0.56 blue:0.8 alpha:1.0];    self.navigationItem.title = @"chat";    [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor], NSForegroundColorAttributeName:[UIFont systemFontOfSize:18]}];        //导航栏左侧按钮    UIButton *backbutton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];    [backbutton setImage:[UIImage imageNamed:@"back.png"] forState:UIControlStateNormal];    [backbutton addTarget:self action:@selector(back) forControlEvents:UIControlEventAllTouchEvents];    UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithCustomView:backbutton];    self.navigationItem.leftBarButtonItem = backItem;        //设置输入框    _textField = [[UITextField alloc] initWithFrame:CGRectMake(W * 0.07, H * 0.94, W * 0.75, H * 0.06)];    _textField.borderStyle = UITextBorderStyleRoundedRect;    _textField.layer.borderColor = [UIColor blackColor].CGColor;    _textField.delegate = self;        //设置发送按钮    UIButton *sendButton = [UIButton buttonWithType:UIButtonTypeCustom];    sendButton.backgroundColor = [UIColor colorWithRed:0.27 green:0.55 blue:0.8 alpha:1.0];    [sendButton setTitle:@"发送" forState:UIControlStateNormal];    [sendButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];    [sendButton addTarget:self action:@selector(send) forControlEvents:UIControlEventTouchDown];    sendButton.frame = CGRectMake(W * 0.83, H * 0.94, W * 0.15, H * 0.06);    sendButton.layer.borderWidth = 1;    sendButton.layer.cornerRadius = 10;       /* UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, W, H - 108)];    view.backgroundColor = [UIColor blackColor];    view.tag = 101;*/    [self.view addSubview:_textField];    [self.view addSubview:sendButton];        _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, W, H - 88) style:UITableViewStylePlain];    _tableView.delegate = self;    _tableView.dataSource = self;    //设置分割线(设置为无样式)    _tableView.separatorStyle = UITableViewCellAccessoryNone;    _tableView.showsVerticalScrollIndicator = NO;    [self.view addSubview:_tableView];//    [self.view addSubview:view];//    [self.view bringSubviewToFront:view];        //设置聊天信息数值    _messageArr = [NSMutableArray arrayWithObjects:@"选择总是会有代价的,承受它就好了", @"当你见到我时,我已是更好的自己", @"自律并不是一个什么远在天边的大词儿,它是你每一天每一分钟,能在那些不想做的一瞬间,说服自己咬着牙继续坚持下去", @"永远有期待", nil];    _rowHeightArr = [[NSMutableArray alloc] init];    for (NSString *str in _messageArr) {        //因为boundingRectWithSize: options: attributes: context: 函数中参数三需要使用字典数组        //P1:文本显示的最大宽度和最大高度        //P2:计算的类型 NSStringDrawingUsesLineFragmentOrigin 绘制文本时使用,一般使用这项        //P3:文本属性        //P4:包括一些信息,例如如何调整字间距以及缩放。该参数一般可为 nil        NSDictionary *attri = @{NSFontAttributeName:[UIFont systemFontOfSize:18]};        CGSize size = [str boundingRectWithSize:CGSizeMake(W * 0.6, H * 0.41) options:NSStringDrawingUsesLineFragmentOrigin attributes:attri context:nil].size;        //聊天框高度,+ W * 0.15为了保持会话之间的距离        int height = size.height + W * 0.15;        _rowHeight = [NSNumber numberWithInt:height];        //存储在数组里,设置行高时使用        [_rowHeightArr addObject:_rowHeight];    }    //监视键盘回收    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillAppear:) name:UIKeyboardWillShowNotification object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillDisAppear:) name:UIKeyboardWillHideNotification object:nil];

创建button发送事件

- (void)send{    [_messageArr addObject:_textField.text];    NSDictionary *attri = @{NSFontAttributeName:[UIFont systemFontOfSize:18]};    //自适应高度,并计算    CGSize size = [_textField.text boundingRectWithSize:CGSizeMake(W * 0.6, H * 0.58) options:NSStringDrawingUsesLineFragmentOrigin attributes:attri context:nil].size;    int height = size.height + W * 0.15;    _rowHeight = [NSNumber numberWithInt:height];    [_rowHeightArr addObject:_rowHeight];    //_messageArr.count - 1 : 显示的最后一行    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(_messageArr.count - 1) inSection:0];    //加入一个cell    [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];    //更新tableView    [_tableView reloadData];    //滚动界面(随着消息发送上移)    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];    //清空textField    _textField.text = @"";    }

!!!!!!核心: cell的使用:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{        static NSString *cellId = @"cell";    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];    if(!cell){        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId];    } else {        //tableView的复用,如果不删除,会出现bug        //删除cell所有的子视图        while ([cell.contentView.subviews lastObject] != nil) {            [(UIView *)[cell.contentView.subviews lastObject] removeFromSuperview];        }    }    //分割线风格(无显示)    cell.selectionStyle = UITableViewCellSelectionStyleNone;    //一人一句话    if(indexPath.row % 2 != 0){        //设置头像        UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed: @"image1.jpg"]];        imageView.frame = CGRectMake(W * 0.01, W * 0.05, W * 0.1, W * 0.1);        [cell.contentView addSubview:imageView];                //设置对话框        UILabel *label = [[UILabel alloc] init];        label.numberOfLines = 0;        label.text = _messageArr[indexPath.row];        label.font = [UIFont systemFontOfSize:18];        NSDictionary *attri = @{NSFontAttributeName:label.font};        //自适应高度        CGSize size = [label.text boundingRectWithSize:CGSizeMake(W * 0.6, H * 0.58) options:NSStringDrawingUsesLineFragmentOrigin attributes:attri context:nil].size;        label.frame = CGRectMake(W * 0.13, W * 0.07, size.width, size.height + W * 0.05);                //设置聊天气泡        UIImageView *imageViewBubble = [[UIImageView alloc] init];        imageViewBubble.backgroundColor = [UIColor colorWithRed:0.94 green:0.94 blue:0.94 alpha:1.0];        imageViewBubble.frame = CGRectMake(W * 0.12, W * 0.07, size.width + W * 0.05, size.height + W * 0.03);                [cell.contentView addSubview:imageViewBubble];        [cell.contentView addSubview:label];            } else {                UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image5.jpg"]];        imageView.frame = CGRectMake(W * 0.89, W * 0.01, W * 0.1, W * 0.1);        [cell.contentView addSubview:imageView];                UILabel *label = [[UILabel alloc] init];        label.numberOfLines = 0;        label.text = _messageArr[indexPath.row];        label.font = [UIFont systemFontOfSize:18];        NSDictionary *attri = @{NSFontAttributeName:label.font};        CGSize size = [label.text boundingRectWithSize:CGSizeMake(W * 0.6, H * 0.58) options:NSStringDrawingUsesLineFragmentOrigin attributes:attri context:nil].size;        label.frame = CGRectMake(W * 0.86 - size.width, W * 0.05, size.width, size.height);                UIImageView *imageViewBubble = [[UIImageView alloc] init];        imageViewBubble.backgroundColor = [UIColor colorWithRed:0.94 green:0.94 blue:0.94 alpha:1.0];        imageViewBubble.frame = CGRectMake(W * 0.82 - size.width, W * 0.03, size.width + W * 0.05, size.height + W * 0.03);                [cell.contentView addSubview:imageViewBubble];        [cell.contentView addSubview:label];            }        return cell;    }//设置单元格高度- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    //将NSNumber型的height转换为CGFloat型    CGFloat height = [_rowHeightArr[indexPath.row] floatValue];    return height;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {    return _messageArr.count;}

下来回收键盘:

//显示简单的键盘回收- (void)keyboardWillDisAppear:(NSNotification *)notification{    //第一个参数是动画持续时间    //第二个参数是方法,这里让视图恢复原来的位置就好    [UIView animateWithDuration:1 animations:^{self.view.transform = CGAffineTransformMakeTranslation(0, 0);}];    }- (void)keyboardWillAppear:(NSNotification *)notification{    //计算键盘高度    CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];    CGFloat keyboardY = keyboardFrame.origin.y;    //视图整体上升    [UIView animateWithDuration:1.0 animations:^{self.view.transform = CGAffineTransformMakeTranslation(0, keyboardY - self.view.frame.size.height);}];}//点击空白处回收键盘- (void)touchesBegan:(NSSet
*)touches withEvent:(UIEvent *)event{ [_textField endEditing:YES];}//点击return回收键盘- (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField endEditing:YES]; return YES;}

最后加上返回按钮事件:

- (void)back{    [self dismissViewControllerAnimated:NO completion:nil];}

效果图

这是我在初始化时加入的话:

在这里插入图片描述
这是我发送几句话后的效果:
在这里插入图片描述
若不清除cell的子视图,则会产生这样的bug:
在这里插入图片描述

转载地址:http://dukti.baihongyu.com/

你可能感兴趣的文章
《达芬奇的人生密码》观后感
查看>>
论文翻译:《一个包容性设计的具体例子:聋人导向可访问性》
查看>>
基于“分形”编写的交互应用
查看>>
《融入动画技术的交互应用》主题博文推荐
查看>>
链睿和家乐福合作推出下一代零售业隐私保护技术
查看>>
Unifrax宣布新建SiFAB™生产线
查看>>
艾默生纪念谷轮™在空调和制冷领域的百年创新成就
查看>>
NEXO代币持有者获得20,428,359.89美元股息
查看>>
Piper Sandler为EverArc收购Perimeter Solutions提供咨询服务
查看>>
RMRK筹集600万美元,用于在Polkadot上建立先进的NFT系统标准
查看>>
JavaSE_day14 集合中的Map集合_键值映射关系
查看>>
异常 Java学习Day_15
查看>>
Mysql初始化的命令
查看>>
MySQL关键字的些许问题
查看>>
浅谈HTML
查看>>
css基础
查看>>
Servlet进阶和JSP基础
查看>>
servlet中的cookie和session
查看>>
过滤器及JSP九大隐式对象
查看>>
软件(项目)的分层
查看>>