聊天界面,frame模型

本文详细介绍了如何使用iOS开发环境和React Native框架进行跨平台移动应用开发,包括项目搭建、组件使用、状态管理及性能优化等方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//
//  ViewController.m
//  01_QQ聊天信息
//
//  Created by Itcast.GuangZhou on 15/9/23.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#import "ViewController.h"
#import "CZMessage.h"
#import "CZMessageCellFrame.h"
#import "CZMessageCell.h"

@interface ViewController ()<UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UITextField *inputText;
@property (nonatomic,strong) NSMutableArray *messageFrames;
@end

@implementation ViewController
//懒加载
- (NSMutableArray *) messageFrames
{
    if (_messageFrames==nil) {
        _messageFrames=[CZMessageCellFrame messageFrames];
    }
    return _messageFrames;
}
//隐藏状态栏
- (BOOL)prefersStatusBarHidden
{
    return YES;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.dataSource=self;
    self.tableView.delegate=self;
    
    self.inputText.delegate=self;
    //去除表格的分割线
    self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;
    //1.创建通知中心
    NSNotificationCenter *center=[NSNotificationCenter defaultCenter];
    //2.注册通知监听器
    [center addObserver:self selector:@selector(keyboardFrameChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
    
    //为tableView设置图片图片
    UIImageView *bgView=[[UIImageView alloc] init];
    bgView.image=[UIImage imageNamed:@"bgView"];
    self.tableView.backgroundView=bgView;
    
}

//实现UITextFieldDelegate代理方法
//点击return 键的时候调用这个应方法
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
    //1.获取文本框的内容
    NSString *text=self.inputText.text;
    //2.添加到模型数组中
    CZMessageCellFrame *newFrame=[[CZMessageCellFrame alloc] init];
    CZMessage *newMsg=[[CZMessage alloc] init];
    newMsg.text=text;
    
    NSDate *date=[NSDate date];
    NSDateFormatter *format=[[NSDateFormatter alloc] init];
    //一定要设置格式的的样式
    format.dateFormat=@"HH:mm";
    
    newMsg.time=[format stringFromDate:date];
    //NSLog(@"%@",newMsg.time);
    
    
    newMsg.type=MessageTypeMe;
    
    CZMessageCellFrame *lastFrame=[self.messageFrames lastObject];
    if (![lastFrame.message.time isEqualToString:newMsg.time]) {
        newFrame.showTime=YES;
    }
    
    newFrame.message=newMsg;
    
    [self.messageFrames addObject:newFrame];
    //3.刷新tableView
    [self.tableView reloadData];
    NSIndexPath *path=[NSIndexPath indexPathForRow:self.messageFrames.count-1 inSection:0];
    [self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
    
    //清空文本框的数据
    self.inputText.text=nil;
    return  YES;
}

- (void) keyboardFrameChange:(NSNotification *)notice
{
    NSDictionary *dic=notice.userInfo;
    //NSLog(@"%@",dic);
    CGFloat offset=[dic[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue].origin.y-self.view.frame.size.height;
    //使整个view上移
    self.view.transform=CGAffineTransformMakeTranslation(0, offset);
    NSIndexPath *path=[NSIndexPath indexPathForRow:self.messageFrames.count-1 inSection:0];
    [self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];

}

- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}

//确定所有行的数量
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.messageFrames.count;
}

- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //1.获取cell
    CZMessageCell *cell=[CZMessageCell messageCell:tableView];
    //清除单元格的背景色
    cell.backgroundColor=[UIColor clearColor];
    //2.为cell赋值
    CZMessageCellFrame *frame=self.messageFrames[indexPath.row];
    cell.messageFrame=frame;
    //3.返回创建好的cell
    return  cell;
}

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
     CZMessageCellFrame *frame=self.messageFrames[indexPath.row];
    return frame.cellHeight;
}



@end



<pre name="code" class="objc">//
//  CZMessage.h
//  01_QQ聊天信息
//
//  Created by Itcast.GuangZhou on 15/9/23.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>
//消息类型
typedef enum
{
    MessageTypeMe,
    MessageTypeOther
}CZMessageType;

@interface CZMessage : NSObject
@property (nonatomic,copy) NSString *text;
@property (nonatomic,copy) NSString *time;
//类型--为了提高代码的可读性,将类型定义为枚举
@property (nonatomic,assign)CZMessageType type;


+ (NSArray *) messages;

+ (instancetype) messageWithDic:(NSDictionary *)dic;
- (instancetype) initWithDic:(NSDictionary *)dic;
@end




<pre name="code" class="objc">//
//  CZMessage.m
//  01_QQ聊天信息
//
//  Created by Itcast.GuangZhou on 15/9/23.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#import "CZMessage.h"

@implementation CZMessage

+ (NSArray *) messages
{
    NSArray *sourceArr=[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil]];
    NSMutableArray *desArr=[NSMutableArray array];
    //循环遍历字典数组,字典转模型
    for (NSDictionary *dic in sourceArr) {
        //每一个字典对应着一个模型对象
        CZMessage *msg=[CZMessage messageWithDic:dic];
        [desArr addObject:msg];
    }
    return desArr;
}


+ (instancetype) messageWithDic:(NSDictionary *)dic
{
    return [[self alloc] initWithDic:dic];
}

- (instancetype) initWithDic:(NSDictionary *)dic
{
    if (self=[super init]) {
        [self setValuesForKeysWithDictionary:dic];
    }
    return self;
}
@end




<pre name="code" class="objc">//
//  CZMessageCellFrame.h
//  01_QQ聊天信息
//
//  Created by Itcast.GuangZhou on 15/9/23.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#define btnPadding 20

@class CZMessage;

@interface CZMessageCellFrame : NSObject
//行高
@property (nonatomic,assign)CGFloat cellHeight;

//所有子控件的frame
@property (nonatomic,assign,readonly) CGRect timeViewF;
@property (nonatomic,assign,readonly) CGRect iconViewF;
@property (nonatomic,assign,readonly) CGRect textViewF;

//message数据模型
@property (nonatomic,strong) CZMessage *message;

//所以frame模型数据数组
+(NSMutableArray *)messageFrames;

//添加属性,标记是否需要显示时间  默认值:NO
@property (nonatomic,assign) BOOL showTime;
@end




<pre name="code" class="objc">//
//  CZMessageCellFrame.m
//  01_QQ聊天信息
//
//  Created by Itcast.GuangZhou on 15/9/23.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#import "CZMessageCellFrame.h"
#import "CZMessage.h"

@implementation CZMessageCellFrame
//返回所有模型数据
+(NSMutableArray *)messageFrames
{
    NSMutableArray *desArr=[NSMutableArray array];
    //1.取出原始的message数据
    NSArray *sourceArr=[CZMessage messages];
    //循环遍历,将原始的message模型数据一个一个添加到Frame模型中
    for (CZMessage *msg in sourceArr) {
        CZMessageCellFrame *frame=[[CZMessageCellFrame alloc] init];
        //判断是否需要显示时间
        //1.得先取出desArr  中最后一个Frame模型
        CZMessageCellFrame *lastFrame=[desArr lastObject];
        //2.判断获取 的最后一个frame模型数据中message成员的time值是否与当前需要添加的msg时间相等
        if(![lastFrame.message.time isEqualToString:msg.time])
        {
            frame.showTime=YES;
        }
        //赋值模型数据   1.提供创建cell所需要的message模型  2.计算子控件的frame和行高
        frame.message=msg;
        [desArr addObject:frame];
        
    }
    return  desArr;
}

//计算子控件的frame和计算行高
- (void)setMessage:(CZMessage *)message
{
    _message=message;
    
    CGFloat padding=10;
    //获取当前物理屏幕
     UIScreen *screen=[UIScreen mainScreen];
    //获取屏幕的宽度
    CGFloat width=screen.bounds.size.width;
    //1.计算时间的frame
    CGFloat timeViewX=0;
    CGFloat timeViewY=0;
    CGFloat timeViewW=width;
    CGFloat timeViewH=20;
    _timeViewF=CGRectMake(timeViewX, timeViewY, timeViewW, timeViewH);
    //2.计算头像的frame,判断消息类型
    CGFloat iconViewW=30;
    CGFloat iconViewH=iconViewW;
    CGFloat iconViewX=0;
    CGFloat iconViewY=CGRectGetMaxY(_timeViewF)+padding;
    if (self.message.type==MessageTypeMe) {
        iconViewX=width-padding-iconViewW;
    }
    else
    {
        iconViewX=padding;
    }
    _iconViewF=CGRectMake(iconViewX, iconViewY, iconViewW, iconViewH);
    //3.计算textView的frame,主要计算文本占据的宽高
    CGFloat textViewX=0;
    CGFloat textViewY=CGRectGetMinY(_iconViewF)+padding;
    //设置最大宽高,如果大于这个宽度则自动换行,如果小于这个宽度,则返回实际的宽
    CGSize maxSize=CGSizeMake(250, MAXFLOAT);
    //设置用来计算文本宽高的字体大小
    NSDictionary *att=@{NSFontAttributeName:[UIFont systemFontOfSize:14]};
    //计算文本的实际宽高
    CGSize textSize=[self.message.text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:att context:nil].size;
    CGFloat textViewW=textSize.width;
    CGFloat textViewH=textSize.height;
    //判断消息类型
    if (self.message.type==MessageTypeMe) {
        textViewX=iconViewX-padding-textViewW-2*btnPadding;
    }
    else
    {
        textViewX=CGRectGetMaxX(_iconViewF)+padding;
    }
    _textViewF=CGRectMake(textViewX, textViewY, textViewW+btnPadding*2, textViewH+btnPadding*2);
    
    //4.计算行高
    _cellHeight=CGRectGetMaxY(_textViewF)+padding;
}
@end




<pre name="code" class="objc">//
//  CZMessageCell.h
//  01_QQ聊天信息
//
//  Created by Itcast.GuangZhou on 15/9/23.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#import <UIKit/UIKit.h>
@class CZMessageCellFrame;

@interface CZMessageCell : UITableViewCell
+ (instancetype) messageCell:(UITableView *)tableView;

@property (nonatomic,strong) CZMessageCellFrame *messageFrame;
@end




<pre name="code" class="objc">//
//  CZMessageCell.m
//  01_QQ聊天信息
//
//  Created by Itcast.GuangZhou on 15/9/23.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#import "CZMessageCell.h"
#import "CZMessage.h"
#import "CZMessageCellFrame.h"

@interface CZMessageCell ()
@property (nonatomic,weak) UILabel *timeView;
@property (nonatomic,weak) UIImageView *iconView;
@property (nonatomic,weak) UIButton *textView;
@end

@implementation CZMessageCell

+ (instancetype) messageCell:(UITableView *)tableView
{
    NSString *ID=@"QQ";
    CZMessageCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
    if (cell==nil) {
        //这个方法是父类的方法,也就意味着它只能创建出父类中默认的系统自带的cell.而不能满足我们的需要,所以我们就需要做重写,在调用方法的时候调用我们子类自己重写过后的方法。
        cell=[[CZMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    return  cell;
}
//根据多态,系统会根据类型调用子类重写过后的方法
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    //1.先初始化父类成员
    self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        //1.添加timeView
        UILabel *timeView=[[UILabel alloc] init];
        self.timeView=timeView;
        //设置居中
        timeView.textAlignment=NSTextAlignmentCenter;
        timeView.font=[UIFont systemFontOfSize:13];
        timeView.textColor=[UIColor lightGrayColor];
        [self addSubview:timeView];
        //2.添加iconView
        UIImageView *iconView=[[UIImageView alloc] init];
        self.iconView=iconView;
        [self addSubview:iconView];
        //3.添加textView
        UIButton *textView=[[UIButton alloc] init];
        self.textView=textView;
        //设置按钮的文本色
        [textView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        //设置按钮的字体大小
        textView.titleLabel.font=[UIFont systemFontOfSize:14];
        //设置自动换行
        textView.titleLabel.numberOfLines=0;
        //为按钮添加内容的内间距
        textView.contentEdgeInsets=UIEdgeInsetsMake(0, 20, 0, 20);
        //为按钮添加背景色
        //textView.backgroundColor=[UIColor redColor];
        [self addSubview:textView];
    }
    return self;
}

- (void)setMessageFrame:(CZMessageCellFrame *)messageFrame
{
    _messageFrame=messageFrame;
    //设置数据
    [self setDatas];
    //设置frame
    //[self setFrames];
}
//设置数据
- (void) setDatas
{
    CZMessage *msg=self.messageFrame.message;
    
    self.timeView.text=msg.time;
    
    if (msg.type==MessageTypeMe) {
        self.iconView.image=[UIImage imageNamed:@"me"];
        //根据消息类型设置消息文本的背景图片
//        [self.textView setBackgroundImage:[UIImage imageNamed:@"chat_send_nor"] forState:UIControlStateNormal];
//        [self.textView setBackgroundImage:[UIImage imageNamed:@"chat_send_press_pic"] forState:UIControlStateHighlighted];
        [self.textView setBackgroundImage:[self resizeImageWithName:@"chat_send_nor"] forState:UIControlStateNormal];
        [self.textView setBackgroundImage:[self resizeImageWithName:@"chat_send_press_pic"] forState:UIControlStateHighlighted];
    }
    else
    {
        self.iconView.image=[UIImage imageNamed:@"other"];
//        [self.textView setBackgroundImage:[UIImage imageNamed:@"chat_recive_nor"] forState:UIControlStateNormal];
//        [self.textView setBackgroundImage:[UIImage imageNamed:@"chat_recive_press_pic"] forState:UIControlStateHighlighted];
        [self.textView setBackgroundImage:[self resizeImageWithName:@"chat_recive_nor"] forState:UIControlStateNormal];
        [self.textView setBackgroundImage:[self resizeImageWithName:@"chat_recive_press_pic"] forState:UIControlStateHighlighted];
    }
    [self.textView setTitle:msg.text forState:UIControlStateNormal];
    
}

//返回拉伸之后的图片
- (UIImage *) resizeImageWithName:(NSString *)name
{
    return [[UIImage imageNamed:name] resizableImageWithCapInsets:UIEdgeInsetsMake(30, 20, 18, 30) resizingMode:UIImageResizingModeStretch];
}

//当将当前控件添加到父容器的时候,自动调用这个方法,设置它的子控件的Frame
//如现在这个情况:当创建好cell,添加到tableView中的时候,会调用这个方法设置cell 的三个子控件的frame
- (void) layoutSubviews
{
    //判断是否需要显示时间
    self.timeView.hidden=! self.messageFrame.showTime;
    
    self.timeView.frame=self.messageFrame.timeViewF;
    self.iconView.frame=self.messageFrame.iconViewF;
    self.textView.frame=self.messageFrame.textViewF;

}

@end





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值