预览效果图:
上图中的聊天软件主要完成了一下四项功能:
a.消息文本以气泡的形似显示在界面上,一行一个气泡
b.在textField中输入发出的消息文本,可以以气泡形式显示在界面上
c.编辑消息文本时键盘弹起,此时界面所有控件同步上移
d.搜索模块完成消息文本的搜索
====聊天气泡的创建====
主控制器GYViewController中拖拽表视图UITableView,cell为自定义GYMessageCell,每行气泡的大小取决于消息文本的大小,气泡的样式以及布局则取决于消息文本的来源,因此GYMessageCell在设计时对外公开属性为GYMessage,由GYMessage外部传入相关属性。
数据模型类GYMessage中对外公开属性:
(1)NSString* content 用来存放消息文本;
(2)BOOL fromMe 用来标知消息文本来源,是发出还是接收。
//确定文本的高度,给出一个范围值
CGRect rectOfText=CGRectMake(0, 0, MAX_WIDTH_OF_TEXT, 999);
//根据给定的范围以及text计算label的尺寸,这肯定是个变量
rectOfText=[self.label
textRectForBounds:rectOfText limitedToNumberOfLines:0];
ps.
由rectOfText可推算出气泡的大小以及坐标,主要抓住几个不变量:label在气泡中的上下左右边距;气泡的尾巴与屏幕的距离;气泡与cell的上下边距。
气泡的图片我是做了九切片处理,保证其放大缩小都不失真;由于cell的高度是根据气泡的大小变化的,所以还需调用协议方法处理下行高。
====发出的消息文本气泡显示====
textField选择响应事件为did end on exit,即编辑完成后点击return后键盘收起,响应事件:
- (IBAction)sendMessage:(UITextField *)sender {
if (self.textField.text.length>0) {
GYMessage* newMessage=[[GYMessage alloc]init];
newMessage.content=self.textField.text;
newMessage.fromMe=YES;
self.textField.text=@""; //清空文本框
//数据保存到GYMessage类数组self.allMessages中
[self.allMessages addObject:newMessage];
//更新表格,针对单个位置的方法insertRowsAtIndexPaths
NSIndexPath* indexPath=[NSIndexPath
indexPathForRow:self.allMessages.count-1 inSection:0];
[self.tableView insertRowsAtIndexPaths:
@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
} }
====键盘通知模式====
UIKeyboardWillShowNotification以及UIKeyboardWillHideNotification为系统自带的通知内容,在键盘弹出和收起时自动post,则需要去NSNotificationCenter注册以上两种模式的观察者,在观察者响应方法中改变界面控件的布局。
系统自带notification有userInfo属性,可以通过查看该属性获取键盘弹起或收起时的具体信息,比如notification.userInfo[UIKeyboardFrameEndUserInfoKey]可知键盘的frame属性值,从而可依据设计其他控件的布局。
在需要键盘通知处理的界面切换时切记remove观察者,养成好习惯。
//注册键盘通知
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(openKeyboard:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(closeKeyboard:)
name:UIKeyboardWillHideNotification object:nil];
}
//取消键盘通知
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter]
removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]
removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
====搜索功能模块====
创建GYSearchTableViewController负责搜索结果的表视图显示,同时还需要在主控制器GYViewController中设置UISearchController,通过UISearchController UISearchResultsUpdating> 配置UISearchController: self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.searchResultViewController]; self.searchController.searchResultsUpdater = self; self.searchResultViewController.tableView.delegate = self; self.searchController.delegate = self; self.searchController.searchBar.delegate = self; 主控制器中需要完成以下UISearchResultsUpdating协议的required方法: -(void)updateSearchResultsForSearchController:(UISearchController *)searchController{ NSString *searchText = searchController.searchBar.text; NSMutableArray *searchResults = [NSMutableArray array]; for (TRMessage* msg in self.allMessages) { if ([msg.content rangeOfString:searchText].length>0) { [searchResults addObject:msg];} } //遍历后将符合条件的信息通过GYSearchTableViewController的外部属性传入,再刷新数据 self.searchResultViewController.resultArray = searchResults; [self.searchResultViewController.tableView reloadData]; }
将主控制器中的显示全部消息的表视图与搜索结果表视图联系起来。首先主控制器需要遵守协议