zoukankan      html  css  js  c++  java
  • iOS基础-高级视图-UITableView--实例:QQ聊天

    一、搭建UI界面
    1.在普通视图控制器中放一个TableView
    2.拖一个UIView,作为底部工具条
    3.在UIView上放一个imageView,换成纯白色背景。然后在UIView上放一个按钮
    4.将按钮的image属性换成语音图标,高度宽度均为44。x,y为0.(注意不要把背景图
    片属性换成语音图标,会被拉伸。),同理再拖2个按钮换成相应图标
    5.拖一个文本输入框,将其背景图片属性设置为相应的图片。

    二、往TableView中放数据
    1.设置数据源
    2.新建一个模型MJMessage(plist里有3个属性,所以添加3条属性)

    typedef enum {
    MJMessageTypeMe = 0//自己发的
    MJMessageTypeOther // 别人发的
    } MJMessageType;
    //聊天内容
    @property (nonatomic,copy)NSString *text;
    //消息发送时间
    @property (nonatomic,copy)NSString *time;
    //发送者
    @property (nonatomic,copy)MJMessageType *type;
    //是否显示时间
    @property (nonatomic,assign)BOOL hideTime ;
    
    //提供字典转模型的方法,并实现。
    +(instancetype)messageWithDict:(NSDictionary *)dict;
    -(instancetype)initWithDict:(NSDictionary *)dict;
    
    +(instancetype)messageWithDict:(NSDictionary *)dict
    {
    return [[self alloc] initWithDict:dict];
    }
    
    -(instancetype)initWithDict:(NSDictionary *)dict
    {
    if(self = [super init]) {
           [self setValuesForKeysWithDictionary:dict];
       }
           return self;
    }

    3.加载模型数据

    @property(nonatomic,strong)NSMutableArray *messageFrames;
    -(NSMutableArray *)messageFrames
    {
    if(_messageFrames == nil){
    //从plist里面加载出来字典数组
    NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"nessages.plist" ofType:nil]]; 
    NSMutbleArray *msgArray = [NSMutableArray array];
    // 将字典转成message模型
    for (NSDictionary *dict in dictArray) {
    //消息模型
    MJMessage *msg = [MJMessage messageWithDict:dict];
    
    //取出上一个模型
    MJMessageFrame *lastMf = [mfArray lastObejct];
    MJMessage *lastMsg = lastMf.message;
    
    //判断两个消息的时间是否一致
    msg.hideTime = [msg.time isEqualToString:lastMsg.time];
    
    //frame模型
    MJMessageFrame *mf = [MJMessageFrame alloc] init];
    mf.message = msg;
    
    //添加
    [mfArray addObejct:mf];
    }
    
          _messageFrames = mfArray;
       }
           return _messageFrames;
    }

    4.遵守协议并实现数据源方法

    第一个数据源方法: 因为只有一列所以可以不实现。默认为1列
    第二个数据源方法: numberOfRowsInSection:方法
    return self.messageFrames.count;
    第三个数据源方法: cellForRowAtIndexPath:方法
    //1.创建cell
    MJMessageCell *cell = [MJMessageCell cellWithTableView:tableView];
    //2.给cell传递模型(在算完frame和cell高度之后进行这一步)
    cell.messageFrame = self.messageFrames[indexPath.row];
    //3.返回cell
    return cell;

    5.设置行高(设置代理遵守协议并实现代理方法 heightForRowAtIndexPath:方法)

    {
        MJMessageFrame *mf = self.messageFrames[indexPath.row];
        return cellHeight;
    }

    6..通过代码自定义cell(cell的高度不一致)
    1>新建一个Cell类MJMessageCell(注意要提供一个方法快速创建cell)
    2>在cell的实现文件中重写initWithStyle:reuseIndetifier:方法
    添加所有需要显示的子控件(不需要设置子控件的属性和frame,子控件要添加到contentView中)
    进行子控件一次性的属性设置(有些属性只需要设置一次,比如字体、固定的图片)

    //因为时间,头像和正文要在其他方法中使用,所以先将它们声明为成员变量
    @property (nonatomic,weak)UILabel *timeView;
    @property (nonatomic,weak)UIImageView *iconView;
    @property (nonatomic,weak)UIButton *textView;
    在这个例子中
    //1.时间
    UILabel *timeView = [[UILabel alloc] init];
    timeView.textAlignment = NSTextAlignmentCenter
    timeView.textColor = [UIColor lightGrayColor];
    timeView.font = [UIFont systemFont:13];
    [self.contentView addSubview:timeView];
    self.timeView = timeView;
    //2.头像
    UIImageView *iconView = [UIImageView alloc] init];
    [self.contentView addSubview:iconView];
    self.iconView = iconView;
    //3.正文
    UIButton *textView = [[UIButton alloc] init];
    textView.titleLabel.numberOfLines = 0//自动换行
    textView.titleLabel.font = MJTextFont;
    textView.contextEdgaInsets = UIEdgeInsetsMake(MJTextPadding,MJTextPadding,MJTextPadding,MJTextPadding); 
    [textView setTitleColor:[UIColor blackColor] ForState:UIControlStateNormal];
    [self.contentView addSubview:textView];
    self.textView = textView;
    
    //4.设置cell的背景色
    self.backgroundColor = [UIColor clearColor];


    3>提供2个模型

    数据模型:存放文字数据/图片数据。已经创建好了,为MJMessage
    frame模型:存放数据模型/所有子控件的frame/cell的高度
    新建一个类MJMessageFrame并添加属性

    //头像frame
    @property(nonatomic,assgin,readonly)CGRect iconF;
    //事件的frame
    @property(nonatomic,assgin,readonly)CGRect timeF;
    //正文的frame
    @property(nonatomic,assgin,readonly)CGRect textF;
    //cell的高度
    @property(nonatomic,assgin,readonly)CGFloat cellHeight;
    //数据模型
    @class MJMessage;
    @property(nonatomic,strong)MJMessage *message;

    4>cell拥有一个frame模型(不要直接拥有数据模型)
    @property(nonatomic,strong)MJMessageFrame *messageFrame;
    5>重写frame模型属性的setter方法,在这个方法中设置子控件的显示数据和frame

    -(void)setMessageFrame:(MJMessageFrame *)messageFrame
    {
       _messageFrame = messageFrame;
    
       MJMessage *message = messageFrame.message; 
    //1.时间
    self.timeView.text = message.time;
    self.timeView.frame = messageFrame.timeF;
    //2.头像
    NSString *icon = message.type == MJMessageTypeMe ? @"me"@"other";
    self.iconView.image = [UIImage imageNamed:icon];
    self.iconView.frame = messageFrame.iconF;
    //3.正文
    [self.textView setTitle:message.text forState:UIControlStateNormal];
    self.textView.frame = messageFrame.textF;
    
    //4.正文的背景
    if(message.type == MJMessageTypeMe){ //自己发的(蓝色)
    [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_send_nor"] forState:UIControlStateNormal]; 
    } else { //别人发的(白色)
         [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_recive_nor"] forState:UIControlStateNormal]; 
       }
    } 

    知识点:图片太小文字放不下怎么办-->设置按钮的内边距

    -(void)setMessage:(MJMessage *)message
    {
    _message = message;
    //间距
    CGFloat padding = 10//屏幕的宽度
    CGFloat screenW = [UIScreen mainScreen].bounds.width;
    
    //1.时间
    message.time
    if (message.hideTime == NO ){ //显示时间
    CGFloat timeX = 0;
    CGFloat timeY = 0;
    CGFloat timeW= screenW;
    CGFloat timeH= 40;
    _timeF = CGRectMake(timeX,timeY,timeW,timeH);
    }
    //2.头像
    CGFloat iconY = CGRectGetMaxY(_timeF)+ padding;
    CGFloat iconW = 40;
    CGFloat iconH = 40;
    CGFloat iconX;
    if(message.type == MJMessageTypeOther) { //别人发的
    iconX = padding;
    } else { //自己发的
    iconX = screenW - padding - iconW; 
    } 
    _iconF = CGRectMake(iconX,iconY,iconW,iconH);
    
    //3.正文
    CGFloat textY = iconY;
    
    
    //文字计算的最大的尺寸
    CGSize textMaxSize = CGSizeMake(150,MAXFLOAT);
    //文字计算出来的真实尺寸(按钮内部label的尺寸)
    CGSize textRealSize = [message.text sizeWithFont:MJTextFont  maxSize:textMaxSize];
    //按钮最终的真实尺寸
    CGSize textBtnSize = CGSizeMake(textRealSize.width + MJTextPadding * 2,textRealSize.height+ MJTextPadding * 2); 
    CGFloat textX;
    if(message.type == MJMesageTypeOther) {
    textX= CGRectGetMaxX(_iconF)+padding;
    } else { 
    textX = iconX - padding - textBtnSize.width ;
    }
    }
    _textF =(CGRect){{textX,textY}, textBtnSize};
    }
    
    //4.cell的高度
    CGFloat textMaxY = CGRectGetMaxY(_textF);
    CGFloat iconMaxY = CGRectGetMaxY(_iconF);
    _cellHeight = MAX(textMaxY,iconMaxY) + padding;

    6>frame模型数据的初始化已经采取惰性初始化的方式(每一个cell对应的frame模型数据只加载一次)

    细节:
    1.在viewDidLoad中去除分隔线
    1>连线拿到tableView
    2>self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    2.添加背景色

    self.tableView.backgroundColor = [UIColor colorWithRed:224/255.0 green:224/255.0 Blue:224/255.0 alpha:1.0]; 

    3.去掉状态栏

    -(BOOL)prefersStatusBarHidden
    {
        return YES;
    }

    4.cell不能被选中

    self.tableView.allowsSelection = NO;

    三、将实用的功能抽成分类(没必要使用类)
    分类:给已经存在的类扩展一些方法
    1.功能1: 计算文字尺寸
    1>新建一个NSString的分类Extension
    2>声明并实现下列方法

    /* 
    @param font 文字的字体
    @param maxSize 文字的最大尺寸
    */
    -(CGSzie)sizeWithFont:(UIFont *)font maxSize:(CGSzie)maxSize
    {
        NSDictionary *attrs = @[NSFontAttributeName : font ];
        return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs  context:nil].size; 
    }

    3>导入分类头文件即可使用该分类里的方法。

    2.功能二:返回一张可以随意拉伸不变形的图片
    1>新建一个UIImage的分类Extension
    2>声明并实现下列方法

    +(UIImage *)resizableImage:(NSString *)name
    {
    UIImage *normal = [UIImage imageNamed:name];
    CGFloat w = normal.size.width * 0.5;
    CGFloat h = normal.size.height * 0.5return [normal resizableImageWithCapInsets:UIEdgeInsetsMake(h,w,h,w) ]; 
    }

    3>导入分类头文件即可使用该分类里的方法。

  • 相关阅读:
    CDN是如何工作的?
    JQuery UI的拖拽功能
    .net/C#开源操作系统学习系列
    [开源]KJFramework.Message 智能二进制消息框架 新能力
    [ASP.NET MVC]通过对HtmlHelper扩展简化“列表控件”的绑定
    Sencha Touch 2 官方文档翻译之 Managing Dependencies with MVC(管理MVC依赖项)
    Node.JS环境搭建手顺(无脑操作)
    找到拥有相同标签的用户对
    《算法导论》
    Controller的激活
  • 原文地址:https://www.cnblogs.com/marshall-yin/p/4754616.html
Copyright © 2011-2022 走看看