UI之 08-QQ自定义布局

效果展示:

Snip20160405_1.png

01 加载模型数据\创建cell

在这里面, 这个代码和步骤, 与我们上一次总结的一样, 唯一要注意的细节就是我们在

昨天创建自定义cell的第二步中的有一个创建cell中的控件, 中
我们创建:

/**
 *  时间
 */
@property (nonatomic, weak) UILabel *timeView;
/**
 *  头像
 */
@property (nonatomic, weak) UIImageView *iconView;
/**
 *  正文
 */
@property (nonatomic, weak) UIButton *textView;

这几个控件的时候, 我们会发现, 他们都是弱指针, 所以我们不能直接将这些控件添加给我们的cell,所以我们一般会选择这样做:

// 1.时间
UILabel *timeView = [[UILabel alloc] init];
[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];
    [self.contentView addSubview:textView];
    self.textView = textView;

为什么不可以直接添加到cell中???

由于 , 这个是利用弱指针创建的, 所以, 当我们这一行添加代码运行过之后, 这些控件会自被销毁

02 计算子控件的frame

我们在计算我们的frame的时候, 情况和我上一次做的微博一样

frame的.h文件

// 正文的字体
#define GJTextFont [UIFont systemFontOfSize:15]

#import 

@class GJMessage;

@interface GJMessageFrame : 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) GJMessage *message;
@end

frame的.m文件

#import "GJMessageFrame.h"
#import "GJMessage.h"

@implementation GJMessageFrame
/**
 *  计算文字尺寸
 *
 *  @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:(GJMessage *)message
{
    _message = message;
    // 间距
    CGFloat padding = 10;
    // 屏幕的宽度
    CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
    
    // 1.时间
    CGFloat timeX = 0;
    CGFloat timeY = 0;
    CGFloat timeW = screenW;
    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 == GJMessageTypeOther) {// 别人发的
        iconX = padding;
    } else { // 自己的发的
        iconX = screenW - padding - iconW;
    }
    _iconF = CGRectMake(iconX, iconY, iconW, iconH);
    
    // 3.正文
    CGFloat textY = iconY;
    // 文字的尺寸
    CGSize textMaxSize = CGSizeMake(150, MAXFLOAT);
    CGSize textSize = [self sizeWithText:message.text font:MJTextFont maxSize:textMaxSize];
    CGFloat textX;
    if (message.type == GJMessageTypeOther) {// 别人发的
        textX = CGRectGetMaxX(_iconF) + padding;
    } else {// 自己的发的
        textX = iconX - padding - textSize.width;
    }
//    _textF = CGRectMake(textX, textY, textSize.width, textSize.height);
    _textF = (CGRect){{textX, textY}, textSize};
    
    // 4.cell的高度
    CGFloat textMaxY = CGRectGetMaxY(_textF);
    CGFloat iconMaxY = CGRectGetMaxY(_iconF);
    _cellHeight = MAX(textMaxY, iconMaxY) + padding;
}

@end

03 修正聊天细节

小细节:

1. 我们如果按照上面的代码写的话, 就会发现, 我们的每一个聊天内容(cell)就可以被选中. 在我们的[super viewDidLoad];下面写上这样一行代码就可以了: (这个是利用代码写的)

self.tableView.allowSelection = NO;

storyboard中也可以这个大家可以自己找一下, 就是在我们的tableView中的

2 . 有些消息时间一致, 但是它依旧会显示两个相同的时间, 解决问题:

  • 首先, 我们如果确定两个相同的时间不会一起显示, 我们就需要将第二个相同的时间隐藏 所以我们就需要在我们的数据模型类中增加一个新的属性hiddenTime他的类型是BOOL是为了判断是否显示时间 代码就是:

数据模型类.h文件

@property (nonatomic, assign) BOOL hiddenTime;

frame模型类.m文件

if (massage.hiddenTime == NO){

    CGFloat timeX = 0;
    CGFloat timeY = 0;
    CGFloat timeW = screenW;
    CGFloat timeH = 40;
    _timeF = CGRectMake(timeX, timeY, timeW, timeH);
}
  • 如何确定这个BOOL类型的正确性???

我们就需要在我们的控制器的数据转模型中写了
为了比较时间相同与否, 我们需要拿到上一个时间, 然后两个时间进行比较, 这就需要在控制器中的数据转模型中写了, 代码如下:

for (NSDictionary *dict in dictArray) {
            // 消息模型
            GJMessage *msg = [GJMessage messageWithDict:dict];
            
            // 取出上一个模型
            GJMessageFrame *lastMf = [mfArray lastObject];
            GJMessage *lastMsg = lastMf.message;
            
            // 判断两个消息的时间是否一致
            msg.hideTime = [msg.time isEqualToString:lastMsg.time];
            
            // frame模型
            GJMessageFrame *mf = [[GJMessageFrame alloc] init];
            mf.message = msg;
            
            // 添加模型
            [mfArray addObject:mf];
}

为什么是lastObject???
这是由于我们在添加模型的之前, 我们最后一个模型就是就是我们的上一个时间. 所以, 我们使用的是lastObject而且, 整个代码要写在[mfArray addObject:mf];

3 . 关于我们聊天正文的背景图片

我们在设置聊天正文背景的时候, 是不是直接将图片放到正文后面???
其实不是的, 如果我们是直接拖到里面会发生这样的情况:

Snip20160405_2.png

我们可以看到, 我们的那个图片已经变形了, 所以我们解决的办法就是利用我们美工制作的图片的原理:

其实我们可以发现, 在我们的正文背景图片中, 边缘的都有点失真了,
而中间的那一部分, 却很完美,(这个就是我们美工利用特殊的工具才能做出来的效果) 所以我们要利用一个方法, 当文字, 变多时, 将我们的图片中间的那个一部分不断的放大, 不断地填充. 来完成我们平时QQ聊天时的那种效果.
而, 我们要不断放大我们图片中间的那一点. 就系统, 需要告诉我们的系统, 是需要将哪一个部分不断放大, 这就需要下面的这个方法了 :

当然这是在我们的GJMassageCell.m文件中写的

// 正文的背景
    if (message.type == MJMessageTypeMe) { // 自己发的,蓝色
        
        UIImage *normal = [@"chat_send_nor"];
        CGFloat w = normal.size.width * 0.5;
        CGFloat h = normal.size.height * 0.5;
        UIImage *lastNomal = [normal resizableImageWithCapInsets:UIEdgeInsetsMake(h, w, h, w)];
        [self.textView setBackgroundImage: lastNormal forState: UIControlStateNormal];
    } else { // 别人发的,白色
        
        
        // 大概的步骤和上面一样
    }

`
注意: 我们关于那个一个中间部分的算法, 其实就是最中心的那一个点, 只是这一个点, 坐标连1都不到.

当然这样, 我们的代码可以封装(以前我们就说过, 一旦遇到相同的代码, 一般都可以封装)

4 .封装上面的部分代码:

为什么封装代码???

有时候 , 在做其他的项目的时候 , 发现有时候, 我们的这种图片拉伸, 和上面的文本框大小设置, 有很多的地方可以使用, 但是如果我们不进行封装的话 ,一旦我们在其他地方使用的时候, 就必须拥有这个模型.

解决方法 ,就是创建一个分类, 来存储我们的这些将来可以共用的方法, 而, 我们注意到, 我们的上面的图片拉伸,是我们的UIImage的, 所以我们要创建一个UIImage的分类来 存放这个拉伸图片的方法.

首先创建一个UIImage的分类:

Snip20160405_3.png

然后在这个分类中写我们的方法:

// .h文件
#import 

@interface UIImage (Extension)
+ (UIImage *)resizableImage:(NSString *)name;
@end

图片分类的.m文件

#import "UIImage+Extension.h"

@implementation UIImage (Extension)
/**
 *  返回一张可以随意拉伸不变形的图片
 *
 *  @param name 图片名字
 */
+ (UIImage *)resizableImage:(NSString *)name
{
    UIImage *normal = [UIImage imageNamed:name];
    CGFloat w = normal.size.width * 0.5;
    CGFloat h = normal.size.height * 0.5;
    return [normal resizableImageWithCapInsets:UIEdgeInsetsMake(h, w, h, w)];
}
@end

而这个方法的调用, 就变成这个样子了:

// 4.正文的背景
    if (message.type == GJMessageTypeMe) { // 自己发的,蓝色
        [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_send_nor"] forState:UIControlStateNormal];
    } else { // 别人发的,白色
        [self.textView setBackgroundImage:[UIImage resizableImage:@"chat_recive_nor"] forState:UIControlStateNormal];
    }

而我们先前说的, 关于我们正文字体的设置, 也是相同的道理. 但是区别就在于, 我们字体设置, 是创建一个对象方法, 而上面的是类方法

// .h文件
#import 

@interface NSString (Extension)
/**
 *  返回字符串所占用的尺寸
 *
 *  @param font    字体
 *  @param maxSize 最大尺寸
 */
- (CGSize)sizeWithFont:(UIFont *)font maxSize:(CGSize)maxSize;
@end


// .m文件
#import "NSString+Extension.h"

@implementation NSString (Extension)
- (CGSize)sizeWithFont:(UIFont *)font maxSize:(CGSize)maxSize
{
    NSDictionary *attrs = @{NSFontAttributeName : font};
    return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
}

调用的方式为:

 [textView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [self.contentView addSubview:textView];
        self.textView = textView;

新知识: (这一部分的代码和我们做的这个应用的代码不相关)

4. 通知机制:

**原因: **
在上面我们会发现, 当我们的点击那个输入按钮的时候, 我们的键盘(手机键盘)弹出, 会将我们输入的那个按钮遮住, 所以我们要利用一个新的知识让我们的输入框, 当我们的键盘弹出的时候, 他会逐渐上升, 当键盘隐藏的时候, 他会逐渐下降.

为什么不使用代理

因为, 如果是监听我们键盘的弹出或者隐藏, 是没有办法用代理的, 所以我们要学习新的知识: 通知

4.1 什么是通知:

通知就是用于多个对象之间通信的.
假如说对象A发生了一些事情, 他想告诉对象B, 和对象C, 甚至对象D都可以.

**代理和通知之间的区别: **
代理只能是一对一, 就是一个对象对应一个对象 .
通知可以是一对多, 多对一, 多对多

而今天我们讲通知那些知识:

  • 通知的发布
  • 通知的监听
  • 通知的移除

4. 2 通知的三要素:

  • 通知名称
  • 通知发布者
  • 通知接受者
Snip20160405_4.png

4. 3 通知中心

Snip20160405_5.png

从上面的图片我们也可以看出, 我们通知的发布者, 和接收者 , 中间需要一个通知中心帮助我们把通知发布者, 发布的通知告诉接收者.

4. 4发布通知:

Snip20160405_6.png

以上的三个方法都是我们发布通知的方法.

4. 5 注册通知监听器

Snip20160405_7.png

4. 6 取消注册通知监听器

Snip20160405_8.png

其实为了避免出现野指针, 我们一般会在监听器销毁之前取消注册, 因为, 就像上面所说的, 如果不这样做的话, 会导致系统崩溃

话不多说, 直接看代码:

**介绍: **

这是一个利用, 用户阅读新闻的情景介绍通知的, 所以在这里面有两个类:
一个是company新闻公司.
一个是person用户类 .

公司通过用户所喜爱的栏目(军事新闻, 或者娱乐新闻)来决定是否给用户发送通知

代码如下:

首先是公司类中的代码

#import 

@interface NewsCompany : NSObject
/**
 *  机构名称
 */
@property (nonatomic, copy) NSString *name;
@end

就是一个简单的新闻公司名称属性

person类(.h文件的代码就不写了, 因为就只是一个简单的方法声明, 这个方法的名称可以在.m文件中看到)

#import "Person.h"
#import "NewsCompany.h"

@implementation Person
- (void)newsCome:(NSNotification *)note
{
    // 通知的发布者
    NewsCompany *obj = note.object;
    
    NSLog(@"%@接收到了%@发出的通知,通知内容是:%@", self.name, obj.name, note.userInfo);
}

- (void)dealloc
{
//    [super dealloc];
    
    // 取消注册通知监听器
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end

main函数:

#import 
#import "Person.h"
#import "NewsCompany.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        // 1.初始化机构
        NewsCompany *tx = [[NewsCompany alloc] init];
        tx.name = @"腾讯新闻";
        
        NewsCompany *sina = [[NewsCompany alloc] init];
        sina.name = @"新浪新闻";
        
        // 2.初始化3个人
        Person *zhangsan = [[Person alloc] init];
        zhangsan.name = @"张三";
        
        Person *lisi = [[Person alloc] init];
        lisi.name = @"李四";
        
        Person *wangwu = [[Person alloc] init];
        wangwu.name = @"王五";
        
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        // 3.添加监听器
        // zhangsan只监听tx发出的junshi_news_come通知
        // 2
        [center addObserver:zhangsan selector:@selector(newsCome:) name:@"junshi_news_come" object:nil];
        [center addObserver:zhangsan selector:@selector(newsCome:) name:@"yule_news_come" object:nil];
        // 1
        [center addObserver:lisi selector:@selector(newsCome:) name:nil object:tx];
        // 2
        [center addObserver:wangwu selector:@selector(newsCome:) name:nil object:nil];
        
        // 4.发布新闻

        // tx发布了一则叫做junshi_news_come的通知
        [center postNotificationName:@"junshi_news_come"
                              object:tx
                            userInfo:@{@"title" : @"伊拉克战争停止了",
                                       @"intro" : @"伊拉克战争停止了.........."}];
        
        // sina发布了一则叫做junshi_news_come的通知
        [center postNotificationName:@"yule_news_come"
                              object:sina
                            userInfo:@{@"title" : @"6456456456456",
                                       @"intro" : @"7657567567567"}];
    }
    return 0;
}

这个代码就可以简单的介绍了, 关于通知的一些方法的使用.

说了这么多的通知, 他和我们的键盘有什么关系吗???

其实, 我们说了这么就是想讲一下, 我们的这个东西:

Snip20160405_9.png

我们的这个UIDevice中的一些通知, 相当一部分是用户不需要关心的, 因为 , 但是, 作为我们开发者, 我们必须知道, 这些通知, 其中就包括了, 我们的键盘通知 :

Snip20160405_10.png

而上面的关于我们键盘的通知, 那些又是对现在的我们来说是有用的呢???

其实我们需要在意的是那些, 带Will的方法, 因为我们的输入框是要随着我们键盘的上升而上升, 随着我们键盘的下降而下降的.

回到正题上: 利用上面的知识完成程序

5. 键盘处理

首先, 由于我们通知是控制器监听我们键盘的弹出与显示
所以我们, 这个键盘处理的代码应该写在控制器里面

首先我们是要在viewDidLoad这个方法中写: 其次, 按照上面的介绍方法

  1. 首先, 应该监听键盘的通知
 // 2.监听键盘的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];

2 . 然后我们要在监听键盘frame变化的方法中写我们的代码:

    /**
     *  当键盘改变了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);
        }];
    }
    
    /*
     UIKeyboardAnimationCurveUserInfoKey = 7;  // 动画的执行节奏(速度)
     UIKeyboardAnimationDurationUserInfoKey = "0.25"; // 键盘弹出\隐藏动画所需要的时间
     UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}";
     UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 588}";
     UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}";
     UIKeyboardFrameChangedByUserInteraction = 0;
     
     // 键盘弹出
     UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";// 键盘刚出来那一刻的frame
     UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; //  键盘显示完毕后的frame
     
     // 键盘隐藏
     UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}";
     UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";
     */

这里面的设置窗口颜色的那一行代码的意思, 就是:

当我们的键盘退出的那一刻, 我们会发现, 在键盘和我们tableView之间会出现黑色区域, 这是由于: 其实在我们手机界面后面还有一个winview, 为了不让颜色显示出来所以要改变颜色


注意这一行代码为什么是这样写:

 // 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);
        }];
  • 首先, 拿到我们键盘最后的frame
  • 然后再利用键盘的Y值 - view的高度
  • 这个差值就是view移动的距离

为什么是这样算的???

分析一下:
假设view的高度为480
当我们的键盘的Y值为264的时候, 那么算出来的值就是 -216(这个距离恰好是键盘隐藏时的距离)

如果键盘的Y值为480(即为隐藏状态)-480 = 0, 那么view就是充满整个屏幕.

  1. 取消注册监听通知
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
  1. 后面小处理

用过QQ都知道, 当我们拖拽我们手机上面的界面时 , 我们的键盘会自动隐藏 , 所以我们现在做好这个工作

要想让键盘由于用户的拖拽 自动隐藏, 我们需要监听用户的点击, 拖拽, 那就需要利用代理

由于我们以前就介绍过scrollView, 所以我们就需要用scrollView的代理, 当然, 我们的UITableViewDelegate继承自scrollView的代理, 所以我们只用直接遵守UITableView的协议, 就好了. 然后在代理中写上隐藏键盘的代码:

/**
 *  当开始拖拽表格的时候就会调用
 */
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    // 退出键盘
    [self.view endEditing:YES];
}
@end

06. 文本输入框处理

一些小的处理;

Snip20160405_11.png
  1. 第一个是显示我们的发送按钮, 以前的是return 现在我们给改成了send

  2. 第二个的那个Auto-enable-Return Key, 当我们在文本框内输入数据的时候, 就文本框没有数据, 那个发送按钮依旧可以点击, 而当我们选择这个选项之后, 就可以解决这个问题

  3. 第三个: 注意到, 我们的在文本框输入数据的时候, 发现: 数据是直接顶格显示的, 这个不够美观, 所以我们要将文本框的左边留一点空隙

  • 首先, 利用拖线 让文本框成为控制器的属性, (inputView)
  • 其实我们每一个文本框都有这两个view (leftView, rightView)我们选择就是用一个看不见的leftView来使文本框左边留出一点缝隙
 // 3.设置文本框左边显示的view
    self.inputView.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 8, 0)];
  • 然后, 我们的每一个view都具有这样一个枚举: leftViewMode他是用来分出这个leftView显示的方式, 时间
self.inputView.leftViewMode = UITextFieldViewModeAlways;

而这个就是永远显示的意思

07 自动回复

在我们的自动回复之前, 首先我们要完成的是, 我们可以发消息

如果要使我们发送的消息可以显示到界面上, 我们首先要监听文本框和键盘的点击.

  • 遵守代理:
UITextFieldDelegate
  • 实现方法:
/**
 *  点击了return按钮(键盘最右下角的按钮)就会调用
 */
- (BOOL)textFieldShouldReturn:(UITextField *)textField

然后在这个方法中写关于我们发送消息的代码:

首先, 我们可以试想一下, 关于自动回复, 意思就是我们发一条消息, 他就自动回复一条 , 我们是如果发的(就是简单的增加一个模型, 在模型中添加数据), 它就会如何会h回复, 所以我们直接将我们发送消息, 和系统自动回复消息, 整合到一个方法中去. 只需要告诉(传参)这个方法, 是谁发消息以及发送消息的内容:

/**
 *  发送一条消息
 */
- (void)addMessage:(NSString *)text type:(GJMessageType)type
{
    // 1.数据模型
    GJMessage *msg = [[GJMessage alloc] init];
    msg.type = type;
    msg.text = text;
    // 设置数据模型的时间
    NSDate *now = [NSDate date];
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"HH:mm";
    msg.time = [fmt stringFromDate:now];
    
    // 看是否需要隐藏时间
    GJMessageFrame *lastMf = [self.messageFrames lastObject];
    GJMessage *lastMsg = lastMf.message;
    msg.hideTime = [msg.time isEqualToString:lastMsg.time];
    
    // 2.frame模型
    GJMessageFrame *mf = [[GJMessageFrame 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];
}

而发送消息的步骤就在上面的方法中

而这样我们的文本框代理需要做的就是调用该方法然后

将是谁发的, 以及发送的内容告诉这个方法便可:

#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;
}

至于自动回复, 我们写了一个这样的plist文件:

Snip20160405_12.png

只要我们遍历我们发送的内容中的每一个汉字, 有和上面相同的汉字, 就自动回复后面的文字, 如果没有就直接发送滚蛋

**取出plist文件: **

- (NSDictionary *)autoreply
{
    if (_autoreply == nil) {
        _autoreply = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"autoreply.plist" ofType:nil]];
    }
    return _autoreply;

}

遍历

/**
 *  根据自己发的内容取得自动回复的内容
 *
 *  @param text 自己发的内容
 */
- (NSString *)replayWithText:(NSString *)text
{
    for (int i = 0; i

这样就完成了, 自动回复功能了.

作者说:

以后的代码量可能比较多, 所以在这里我就不写了. 也是为我自己节省时间那嘛, 见谅啦各位

你可能感兴趣的:(UI之 08-QQ自定义布局)