关情纸尾-----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";//先从缓存池中取cellZLMessageCell *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.取得键盘最后的frameCGRect 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.设置文本框左边显示的viewself.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:56msg.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]; }
最终界面如图:
学的不精,笔记做的不好,见谅见谅。。。。。。。
转载于:https://www.cnblogs.com/Lorraine1/p/5766054.html
关情纸尾-----UIKit基础--QQ自定义布心布局相关推荐
- 关情纸尾-----Quartz2D-绘制富文本,绘制图片.
一般使用UIKit给我们提供的绘图来绘制一些文字,图片这些东西. UIKit给我们提供画图的方法底层也是分为四步.所以也必须在drawRect方法当中去写. 1.如何画文字? 先创建好要画的文字 使用 ...
- special effects - 鼠标移动,出现自定义的表情拖尾
鼠标移动,出现自定义的表情拖尾 一. 效果图 二. 实现代码 一. 效果图 二. 实现代码 <!DOCTYPE html> <html lang="en"> ...
- django基础、自定义框架
django基础 HTTP 超文本传输协议 是在应用层 如今广泛使用的是HTTP1.1 默认为80端口 5层协议: HTTP协议 应用层 TCP/UDP协议 运输层 IP 网络层 数据链路层 物理层 ...
- 纸的大小图解_折纸大全图解基础之如何裁切美元尺寸纸张
本育儿文章是育儿天堂最新发布的<折纸大全图解基础之如何裁切美元尺寸纸张>的详细页面,觉得有用就收藏了,这里给大家转摘到育儿天堂,为了大家阅读方便. 折纸大全图解中有一类折纸教程是比力奇特的 ...
- QQ自定义在线机型状态源码
简介: QQ自定义在线状态源码 网盘下载地址: http://kekewl.cc/nr2LzGn4gQN0 图片:
- 柱底反力求和lisp软件_AutoLISP 基础——认识自定义函数
AutoLISP 基础--认识自定义函数 ( 本文由 LL_J ‚认识自定义函数‛和‚ Autolisp 编程心得‛两篇巨著合成, 并融入了其他人的一些经验,以快速打通你的任督二脉 --自贡黄明儒注 ...
- 纸壳CMS现已支持自定义扩展字段
简介 纸壳CMS是开源免费的可视化内容管理系统. GitHub https://github.com/SeriaWei/ZKEACMS 自定义字段 纸壳CMS现已支持自定义字段,在不修改代码的情况下, ...
- 零基础创建自定义gym环境——以股票市场为例
零基础创建自定义gym环境--以股票市场为例 翻译自medium上的一篇文章Create custom gym environments from scratch - A stock market e ...
- QQ自定义个人文件夹
QQ自定义的配置是从X:\Users\Public\Documents\Tencent\QQ\UserDataInfo.ini这个文件中读出来的,当设置QQ自定义个人文件夹却无效,可能是上面的配置文件 ...
最新文章
- 推荐个所见即所得的编辑器
- 学习深度网络需要直观的感知
- 迭代器与生成器yield
- 移动端web设计尺寸_移动端页面设计规范尺寸大起底
- 12019.LMT84模拟温度传感器
- oracle 客户端 for mips,盒子里的世界: MIPS虚拟机(zt)
- 浅析ASP.NET 2.0的用户密码加密机制
- Untiy3D里用C#做出连线题目~
- Linux 发展史小览
- whisper客服源码_whisper客服系统兼容HTTPS方案
- CAN通讯程序C语言,AT90CAN单片机CAN通信模块介绍及软件编程
- php 一天是多少秒,1天 等于 86400 秒?
- [Zer0pts2020]Can you guess it?
- 手机端上传照片实现 压缩、拖放、缩放、裁剪、合成拼图等功能
- 红外热成像仪测温模块简要介绍说明
- IDEA报错:Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found
- 超强技巧分享,如何将人民币大小写转换?
- 千里走单骑:02-北京到上海骑记--Day1.首日征程
- 前端国际化如何对中文——>英文自动化翻译小demo
- 大容量充电宝或成乘机“累赘”
热门文章
- Andriod 破解之道(一)
- 一个表格中文字怎么换行_Excel表格中怎样快速将阿拉伯数字转化为大写文字?这样操作一键完成...
- QGraphicsScene 的简单理解--关于手册的简要翻译
- mysql 接口访问_MySQL的数据库访问接口-阿里云开发者社区
- vue 心跳监控_vue websocket 加心跳
- 2017年10月05日普及组 约数
- Codeforces 1326F Wise Men (容斥原理、状压 DP、子集和变换、划分数)
- 关于三维莫队问题的一些思考和探究
- mvc和php的关系,php - 什么是HMVC模式?
- 点击延迟_300ms 延迟是什么,如何解决