zoukankan      html  css  js  c++  java
  • 关情纸尾-----UIKit基础--QQ自定义布心布局

    简述整个项目的开发过程

      1.在main.stroybord 中搭建基本界面

      2.创建模型,一个是数据模型,一个是frame模型

      3.实现对cell操作的封装

      4.解决显示时间的细节问题

      5.解决聊天内容的背景问题

      6.用通知机制监听键盘

      7.发送消息

    一、在main.stroybord 中搭建基本界面

    二、创建模型,一个是数据模型,一个是frame模型

    根据message.plist文件创建模型

    数据模型ZLMessage

     1 #import <Foundation/Foundation.h>
     2 
     3 
     4 
     5 typedef enum {
     6     ZLMessageTypeMe = 0, //0表示自己,并且系统默认的 也是0 ,然后递增加1
     7     ZLMessageTypeOther
     8 }ZLMessageType;
     9 
    10 @interface ZLMessage : NSObject
    11 
    12 //时间
    13 @property (nonatomic, strong) NSString *time;
    14 
    15 //内容
    16 @property (nonatomic, strong)NSString *text;
    17 
    18 //类型
    19 @property (nonatomic, assign)ZLMessageType type;
    20 
    21 //是否显示时间
    22 @property (nonatomic, assign)BOOL hideTime;
    23 
    24 +(instancetype)messageWithDict:(NSDictionary *)dict;
    25 -(instancetype)initWithDict:(NSDictionary *)dict;
    26 @end
    #import "ZLMessage.h"
    
    @implementation ZLMessage
    
    
    +(instancetype)messageWithDict:(NSDictionary *)dict{
    
        return [[self alloc] initWithDict:dict];
    }
    -(instancetype)initWithDict:(NSDictionary *)dict{
    
        if (self = [super init]) {
            [self setValuesForKeysWithDictionary:dict];
        }
        return self;
    
    }
    @end

    frame模型ZLMessageFrame

    #import <Foundation/Foundation.h>
    #import "UIKit/UIkit.h"
    @class ZLMessage;
    
    @interface ZLMessageFrame : NSObject
    // 头像的frame
    @property (nonatomic, assign, readonly) CGRect iconF;
    
    //时间的frame
    @property (nonatomic, assign, readonly) CGRect timeF;
    
    //正文的frame
    @property (nonatomic, assign, readonly) CGRect textF;
    
    //cell的高度
    @property (nonatomic, assign, readonly) CGFloat cellHeight;
    
    //数据模型
    @property (nonatomic, strong) ZLMessage* message;
    
    @end
    
    

    #define ZLTextFont [UIFont systemFontOfSize:15]

    
    

    #import "ZLMessageFrame.h"

    
    

    #import "ZLMessage.h"

    @implementation ZLMessageFrame

    /**

     *  计算文字尺寸

     *

     *  @param text    需要计算尺寸的文字

     *  @param font    文字的字体

     *  @param maxSize 文字的最大尺寸

     */

    
    

    - (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize

    {

        NSDictionary *attrs = @{NSFontAttributeName : font};

        return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;

    }

    -(void)setMessage:(ZLMessage *)message

    {    _message = message;

        //计算头像,正文,时间的Frame

        CGFloat sreenW = [UIScreen mainScreen].bounds.size.width;

        CGFloat padding = 10;    

        //1.时间

      CGFloat timeX = 0;

        CGFloat timeY = 0;

        CGFloat timeW = sreenW;

        CGFloat timeH = 40;

        _timeF = CGRectMake(timeX, timeY, timeW, timeH);

         //2.头像

        CGFloat iconY = CGRectGetMaxY(_timeF);

        CGFloat iconW = 40;

        CGFloat iconH = 40;

        CGFloat iconX;

        if (message.type == ZLMessageTypeOther) {

            iconX = padding;

        } else {

            iconX = sreenW - iconW - padding;

        }

        _iconF = CGRectMake(iconX, iconY, iconW, iconH);

        //3.正文

        CGFloat textY = iconY;

        CGFloat textX;

        //文字的尺寸

        CGSize textMaxSize = CGSizeMake(150, MAXFLOAT);

        CGSize textSize = [self sizeWithText:message.text font:ZLTextFont maxSize:textMaxSize];

        if (message.type == ZLMessageTypeOther) {

            textX = CGRectGetMaxX(_iconF) + padding;

        } else {

            textX = iconX - padding - textSize.width;

        }

        _textF = (CGRect){{textX,textY},textSize};

        //cell 的高度

        CGFloat textMaxY = CGRectGetMaxY(_textF);

        CGFloat iconMaxY = CGRectGetMaxY(_iconF);

       _cellHeight = MAX(textMaxY, iconMaxY) + padding;

    }

    
    

    @end

     
    - (NSMutableArray *)messagesFrames
    {
        if (_messagesFrames == nil){
            //取出路径
            NSString *path = [[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil];
            
            //取出该路劲下的数组
            NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
            
            NSMutableArray *mfArray = [NSMutableArray array];
            
            //遍历数组形成字典
            for (NSDictionary* dict  in dictArray) {
                //消息模型
                ZLMessage *msg = [ZLMessage messageWithDict:dict];
                
                
                //frame模型
                ZLMessageFrame *mgf =[[ZLMessageFrame alloc] init];
                mgf.message = msg;
                
                [mfArray addObject:mgf];
            }
            _messagesFrames = mfArray;
        }
        
        return _messagesFrames;
    }

    三、实现对cell操作的封装

    #import <UIKit/UIKit.h>
    
    @class ZLMessageFrame;
    
    @interface ZLMessageCell : UITableViewCell
    
    +(instancetype) cellWithTableView:(UITableView *)tableView;
    
    @property (nonatomic, strong) ZLMessageFrame* messageFrame;
    
    @end
    #define ZLTextFont [UIFont systemFontOfSize:15]
    #import "ZLMessageCell.h"
    #import "ZLMessageFrame.h"
    #import "ZLMessage.h"
    
    
    @interface ZLMessageCell()
    //时间
    @property (nonatomic, weak) UILabel *timeView;
    
    //头像
    @property (nonatomic, weak) UIImageView *iconView;
    
    //正文
    @property (nonatomic, weak) UIButton *textView;;
    
    @end
    
    @implementation ZLMessageCell
    
    +(instancetype) cellWithTableView:(UITableView *)tableView
    {
        static NSString *ID = @"message";
        //先从缓存池中取cell
        ZLMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID ];
        //如果缓存池中没有就自己创建cell,并且要带有标记
        if (cell == nil) {
            cell = [[ZLMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        }
        return cell;
    }
    
    //做一次性的初始化
    -(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
    
        self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
        if (self){
            
            //子控件的创建和初始化
            //1.时间
            UILabel *timeView = [[UILabel alloc] init];
            timeView.textColor = [UIColor grayColor];
            timeView.textAlignment = NSTextAlignmentCenter;
            timeView.font = [UIFont systemFontOfSize:13];
            [self.contentView addSubview:timeView];
            self.timeView = timeView;
            
            //2.头像
            UIImageView *iconView = [[UIImageView alloc] init];
            //iconView.backgroundColor = [UIColor redColor];
            [self.contentView addSubview:iconView];
            self.iconView = iconView;
            
            //3.正文
            UIButton *textView = [[UIButton alloc] init];
            textView.titleLabel.numberOfLines = 0;//自动换行
            textView.backgroundColor = [UIColor purpleColor];
            textView.titleLabel.font = ZLTextFont;
            [self.contentView addSubview:textView];
            self.textView = textView;
            
        }
        return self;
    
    }
    
    -(void)setMessageFrame:(ZLMessageFrame *)messageFrame
    {
        _messageFrame = messageFrame;
        ZLMessage *message = messageFrame.message;
        
        //时间
        self.timeView.text = message.time;
        self.timeView.frame = messageFrame.timeF;
        
        //头像
        NSString *icon = (message.type == ZLMessageTypeMe) ? @"me" : @"other";
        self.iconView.image = [UIImage imageNamed:icon];
        self.iconView.frame = messageFrame.iconF;
        
        
        //正文
        [self.textView setTitle:message.text forState:UIControlStateNormal];
        self.textView.frame = messageFrame.textF;
    
    }
    @end

    四、解决显示时间的细节问题

     如果时间是一样的,就只显示一个时间

    在ZLMessage.h文件中添加属性
    
    //是否显示时间
    @property (nonatomic, assign)BOOL hideTime;
    在控制器.m文件中添加代码,即取出上一个模型和刚刚添加的模型的时间作比较,如果时间一样,就只显示上一个模型的time数据
    //遍历数组形成字典
            for (NSDictionary* dict  in dictArray) {
                //消息模型
                ZLMessage *msg = [ZLMessage messageWithDict:dict];
                
                //取出上一个模型
                ZLMessageFrame *lastMf = [mfArray lastObject];
                ZLMessage *lastMg = lastMf.message;
                
                msg.hideTime = [msg.time isEqualToString:lastMg.

     五、解决聊天内容的背景问题

    //设置图片
    
    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];
        }
    //为了显示对话框背景图,需要设置正文按钮的内边距
            
    textView.contentEdgeInsets = UIEdgeInsetsMake(ZLTextPadding, ZLTextPadding, ZLTextPadding, ZLTextPadding);
    //文字计算的最大尺寸
        CGSize textMaxSize = CGSizeMake(150, MAXFLOAT);
    //文字计算出来的真实尺寸(显示文字的尺寸)
        CGSize textSize = [self sizeWithText:message.text font:ZLTextFont maxSize:textMaxSize];
     //按钮最终的尺寸   
        CGSize textBtnSize = CGSizeMake(textSize.width +ZLTextPadding *2, textSize.height +ZLTextPadding *2);
        
        if (message.type == ZLMessageTypeOther) {
            textX = CGRectGetMaxX(_iconF) + padding;
        } else {
            textX = iconX - padding - textBtnSize.width;
        }
    //    _textF = CGRectMake(textX, textY, textSize.width +40, textSize.height +40);
        _textF = (CGRect){{textX,textY},textBtnSize};
        

    六、用通知机制监听键盘

    首先介绍一下通知机制

    代码如下:

    // 监听键盘的通知
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
    
    //取消监听
    - (void)dealloc
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    
    
    /**
     *  当键盘改变了frame(位置和尺寸)的时候调用
     */
    - (void)keyboardWillChangeFrame:(NSNotification *)note
    {
        // 设置窗口的颜色
        self.view.window.backgroundColor = self.tableView.backgroundColor;
        
        // 0.取出键盘动画的时间
        CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        
        // 1.取得键盘最后的frame
        CGRect keyboardFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
        
        // 2.计算控制器的view需要平移的距离
        CGFloat transformY = keyboardFrame.origin.y - self.view.frame.size.height;
        
        // 3.执行动画
        [UIView animateWithDuration:duration animations:^{
            self.view.transform = CGAffineTransformMakeTranslation(0, transformY);
        }];
    }


    7.发送消息

    //监听文本框
    
    #import "MJViewController.h"
    #import "MJMessage.h"
    #import "MJMessageFrame.h"
    #import "MJMessageCell.h"
    
    @interface MJViewController () <UITableViewDataSource, UITableViewDelegate, UITableViewDelegate, UITextFieldDelegate>
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    @property (nonatomic, strong) NSMutableArray *messageFrames;
    
    @property (weak, nonatomic) IBOutlet UITextField *inputView;
    
    @property (nonatomic, strong) NSDictionary *autoreply;
    @end
    
    @implementation MJViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // 1.表格的设置
        // 去除分割线
        self.tableView.backgroundColor = [UIColor colorWithRed:235/255.0 green:235/255.0 blue:235/255.0 alpha:1.0];
        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        self.tableView.allowsSelection = NO; // 不允许选中
        self.tableView.delegate = self;
        // 2.监听键盘的通知
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
        // 3.设置文本框左边显示的view
        self.inputView.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 8, 0)];
        // 永远显示
        self.inputView.leftViewMode = UITextFieldViewModeAlways;
        self.inputView.delegate = self;
    }
    /**
     *  发送一条消息
     */
    - (void)addMessage:(NSString *)text type:(MJMessageType)type
    {
        // 1.数据模型
        MJMessage *msg = [[MJMessage alloc] init];
        msg.type = type;
        msg.text = text;
        // 设置数据模型的时间
        NSDate *now = [NSDate date];
        NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
        fmt.dateFormat = @"HH:mm";
        // NSDate  --->  NSString
        // NSString ---> NSDate
        //    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
        //  2014-08-09 15:45:56
        // 09/08/2014  15:45:56
        msg.time = [fmt stringFromDate:now];
        
        // 看是否需要隐藏时间
        MJMessageFrame *lastMf = [self.messageFrames lastObject];
        MJMessage *lastMsg = lastMf.message;
        msg.hideTime = [msg.time isEqualToString:lastMsg.time];
        
        // 2.frame模型
        MJMessageFrame *mf = [[MJMessageFrame alloc] init];
        mf.message = msg;
        [self.messageFrames addObject:mf];
        
        // 3.刷新表格
        [self.tableView reloadData];
        
        // 4.自动滚动表格到最后一行
        NSIndexPath *lastPath = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0];
        [self.tableView scrollToRowAtIndexPath:lastPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
    }
    
    /**
     *  根据自己发的内容取得自动回复的内容
     *
     *  @param text 自己发的内容
     */
    - (NSString *)replayWithText:(NSString *)text
    {
        for (int i = 0; i<text.length; i++) {
            NSString *word = [text substringWithRange:NSMakeRange(i, 1)];
            
            if (self.autoreply[word]) return self.autoreply[word];
        }
        
        return @"滚蛋";
    }
    
    #pragma mark - 文本框代理
    /**
     *  点击了return按钮(键盘最右下角的按钮)就会调用
     */
    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
        // 1.自己发一条消息
        [self addMessage:textField.text type:MJMessageTypeMe];
        
        // 2.自动回复一条消息
        NSString *reply = [self replayWithText:textField.text];
        [self addMessage:reply type:MJMessageTypeOther];
        
        // 3.清空文字
        self.inputView.text = nil;
        
        // 返回YES即可
        return YES;
    }
    
    /**
     *  当开始拖拽表格的时候就会调用
     */
    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    {
        // 退出键盘
        [self.view endEditing:YES];
    }

    最终界面如图:

     

    学的不精,笔记做的不好,见谅见谅。。。。。。。

  • 相关阅读:
    paddlex 使用-7 windows下脚本生成nb文件
    paddlex 使用-6 在Android下预测
    paddlex 使用-5 Andrdroid4.1报错插件无法删除
    paddlex 使用-4 format = EXTENSION[ext].6错误
    paddlex 使用-3 模型加载预测
    paddlex 使用-2 GUI版本
    paddlex 使用-1 安装
    企业微信登录态与显示姓名
    计算工龄(月份)的C#算法
    一个比较好用的Mongodb 工具
  • 原文地址:https://www.cnblogs.com/Lorraine1/p/5766054.html
Copyright © 2011-2022 走看看