QQChat Layout - 第二季

  • 本来第二季是快写好了, 也花了点功夫, 结果gitbook出了点问题, 给没掉了。有些细节可能会一带而过, 如有疑问, 相互交流进步~.

在第一季中我们完成了QQ聊天界面的基本框架.但是相对于iphone上手机QQ的聊天界面还存在以下差距。

  • 第二季中的工程源文件下载地址:点击到百度云下载
  • 聊天消息没有左右区分。
  • 聊天内容没有背景图片。
  • 菜单栏还没做出, 不能发消息。

###现在我们就一步步来解决这些问题。首先我们解决消息没有左右区分的问题。
- **第四步**:
我们打开StoryBoard。拖入和左边一样的两个控件ImageView和UIButton。并设置和左边一样的约束。具体的**约束思路**如下:

1.设置ImageView距离右边10 , 宽高为40==》确定了x,和宽高

2.设置ImageView的上面和timeLabel下面对齐 ==》确定了Y, 确定了Button

3.设置Button右边距离ImageView左边10, 固定宽高。

4.设置Button的上面与ImageView上面对齐。

SB图片如下:
![](http://images0.cnblogs.com/blog2015/604808/201506/082123337071629.png)

  • 修改完SB的cell界面后开始编码了。我们主要需要在setMessage这个setter方法中, 加入判断聊天消息是属于左边还是属于右边。具体逻辑如下:
- (void)setMessage:(Message *)message {

    _message = message;

    MessageWhoIsMe ==
_message.type?
[self setShowButton: _rightText andIcon: _rightIcon withMessage:message]:
[self setShowButton: _text andIcon: _icon withMessage:message]; } /**
* 设置要展示的消息内容与头像
*
* @param button 设置要显示的信息。
* @param icon 设置要显示的头像
*/
- (void)setShowButton:(UIButton *)text andIcon:(UIImageView *)icon withMessage:(Message*)message{ _rightIcon.hidden = _rightText.hidden = (text != _rightText);
_icon.hidden = _text.hidden = (text != _text);
// 1.给控件装数据
icon.image = [UIImage imageNamed:[self getPicture: message.type]]; [text setTitle:message.text forState:UIControlStateNormal]; _timeLabel.text = message.time; // 2.装完数据强制布局, 使得设置按钮高度的值准确, 并且更新约束
[text layoutIfNeeded]; // 要先强制布局, 这时候更新约束才准确
// 更新约束, 使得按钮的高度此时等于文本的高度。 [text updateConstraints:^(MASConstraintMaker *make) {
CGFloat textH = CGRectGetHeight(text.titleLabel.frame); //+ 30;
make.height.equalTo(textH);
}]; // 3.再次强制布局, 使得约束生效, 这样获取到的按钮高度才准确
[text layoutIfNeeded]; CGFloat textH = CGRectGetMaxY(text.frame);
CGFloat iconH = CGRectGetMaxY(icon.frame);
CGFloat cellH = MAX(textH, iconH) + 10; // 4.更新cell的高度到模型中
message.height = cellH; }

效果图如下(已经实现了左右排列):

  • 第五步:
  • 我们已经完成了QQ消息的可以分左右排列, 接下去我们需要给消息上背景图, 也就是设置按钮的背景图。由于按钮有状态,所以你不能操作它的图片控件来给它设置图, 应该用其提供的设置图片的接口。具体的逻辑比较简单。你可以直接看代码,我主要讲下[UIImage resizeWithImageName:的知识点。
    .....省略N行代码
_timeLabel.text = message.time; // 1.2 改进背景图。 if (!_rightText.hidden) { // 当前显示的是右边, 则设置右边的背景 [_rightText setBackgroundImage:[UIImage resizeWithImageName:@"chat_send_nor"] forState:UIControlStateNormal]; [_rightText setBackgroundImage:[UIImage resizeWithImageName:@"chat_send_press_pic"] forState:UIControlStateHighlighted]; }else { // 显示的是左边 [_text setBackgroundImage:[UIImage resizeWithImageName:@"chat_recive_press_pic"] forState:UIControlStateNormal]; [_text setBackgroundImage:[UIImage resizeWithImageName:@"chat_recive_nor"] forState:UIControlStateHighlighted]; } // 2.装完数据强制布局, 使得设置按钮高度的值准确, 并且更新约束
.....省略N行代码
  • 具体的逻辑很简单,但是我要介绍下图片拉伸的知识。在实际项目中, 我们使用的资源图片不可能是十分大的, 能小则小。不然很消耗内存。你可以打开工程看到, 这个工程中的资源图片中消息背景图。你可以尝试把UIImage resizeWithImageName:替换成UIImage imageNamed:来加载图片, 会发现,当按钮中的文字变大时候,图片还是那么大,也就说图片没有随着按钮的尺寸进行伸缩。好在苹果已经为我们提供了一个方法来伸缩图片。其实UIImage resizeWithImageName:只是我对Apple官方的方法的一个封装, 并将它做成UIImage的分类
  • 细说-(UIImage *)resizableImageWithCapInsets:这个方法是Apple提供的Image类的实例方法。为了不误导大家, 特意查了官方解释如下:

1.简单来说该方法是用来返回一个可随着Button尺寸自动伸缩的图片,并且能保留住原来图片的四个边角, 也就说你要把它设置成Button的背景图
 2.该方法主要通过保护区域是不是有宽、高,和保护区域的大小来决定渲染的方式。当保护区域有高该图片就是竖直可伸缩, 有宽则是水平可伸缩。当宽高都是1px时候,选用的渲染方式是直接把这1px的图片扯大, 渲染的效率十分高。

      那么究竟如何确定保护区域呢?根据官方文档,我们最好将保护区域设置成1*1的大小。这样水平、竖直方向都可以进行拉伸, 并且渲染方式也高, 还有一点就是这个区域我们最好选择的是最靠近正中间的, 因为一般来说这样才能尽可能把图片边缘切掉, 保证渲染出来的图片和远图片看上去是放大后的效果。否则可能出现,图片存在菱角。当然我们还能通过resizableImageWithCapInsets:resizingMode:来说明图片渲染的模式,一种是使用拉伸来resize图片, 一种是使用平铺的方式来resize图片.说了那么多, 你应该懂得了原理, 那么直接看我给UIImage扩充的分类方法吧。

#import "UIImage+Resizingable.h"

@implementation UIImage (Resizingable)

+ (UIImage *)resizeWithImageName:(NSString *)imageName {

    UIImage * image = [UIImage imageNamed: imageName];

    int W = image.size.width * 0.5;
int H = image.size.height * 0.5;
return [image resizableImageWithCapInsets: UIEdgeInsetsMake(H, W, image.size.height - H - 1 , image.size.width - W - 1)]; }
@end

第五步-1效果图:

  • 你一定会看出还存在一点问题。问什么文字没有全部被背景包括着,这是因为很多时候美工给的图片背景都会有留白问题。也就是不是没有被图片包括着,是因为图片旁边有一些空白,显示出来就成这样了。这是后我们又可以利用按钮的内边距来把Label向左右推,这样Label就会变高了,会超出Button,所以我们需要再给Button加点高度。应为给Button设置内边距只需要设置一次,所以我一般将这种操作方法- (void)awakeFromNib方法中
- (void)awakeFromNib {

    // 设置自动换行
_text.titleLabel.numberOfLines = 0;
_rightText.titleLabel.numberOfLines = 0; // 设置button的内边距
_text.contentEdgeInsets = UIEdgeInsetsMake(0, 30, 0, 30);
_rightText.contentEdgeInsets = UIEdgeInsetsMake(0, 30, 0, 30); }

更改Button的高度约束,多加30

    [text updateConstraints:^(MASConstraintMaker *make) {
CGFloat textH = CGRectGetHeight(text.titleLabel.frame)+ 30;
make.height.equalTo(textH);
}];

我觉得你会对内边距存在很大的疑惑, 请看我的博客有专门介绍了下内边距。

最终效果图如下:

时间有限,菜单栏还介绍, 敬请关注第三季。

QQ聊天界面的布局和设计(IOS篇)-第二季的更多相关文章

  1. QQ聊天界面的布局和设计(IOS篇)-第一季

    我写的源文件整个工程会再第二季中发上来~,存在百度网盘, 感兴趣的童鞋, 可以关注我的博客更新,到时自己去下载~.喵~~~ QQChat Layout - 第一季 一.准备工作 1.将假数据messa ...

  2. 高仿qq聊天界面

    高仿qq聊天界面,给有需要的人,界面效果如下: 真心觉得做界面非常痛苦,给有需要的朋友. chat.xml <?xml version="1.0" encoding=&quo ...

  3. Objective-c——UI基础开发第八天(QQ聊天界面)

    一.知识点: QQ聊天界面 双模型的使用(dataModel和frameModel) UITextField的使用 通知的使用 拉伸图片的两种方法(slicing/image对象的resizeable ...

  4. 在WEB项目中调用QQ通讯组件打开QQ聊天界面

    在很多WEB项目中,需要提供在线服务的功能,加上自己的联系方式,例如:QQ,不用添加QQ好友也可以交谈,那这到底是怎么实现的呢? 对于这个功能,需要提到一个组件,即“QQ通讯组件”.QQ通讯组件是一种 ...

  5. Android—简单的仿QQ聊天界面

    最近仿照QQ聊天做了一个类似界面,先看下界面组成(画面不太美凑合凑合呗,,,,):

  6. Android 内部启动其他应用,以及打开指定qq聊天界面

    在自己应用中打开第三方应用,有好多种方法,这里举例一种: //以打开微信为例,前提需要知道打开应用的包名,一般一个发布版本的应用,包名不会轻易改变的,但是,打开QQ就要注意了,毕竟QQ的发布版本有不下 ...

  7. Android 根据QQ号跳转到QQ聊天界面

    从自己开发的应用中根据QQ号跳转到QQ应用的聊天界面,实现起来很方便: 即: startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(" ...

  8. 在移动网页网页上点击链接跳转到QQ聊天界面

    打开qq聊天窗口的方法 <a href="http://wpa.qq.com/msgrd?v=3&uin=1450612626&site=qq&menu=yes ...

  9. IOS第九天(3:QQ聊天界面通知的使用)

    #import <Foundation/Foundation.h> #import "Person.h" #import "XQCompany.h" ...

随机推荐

  1. MyEclipse第一个Servlet程序 --解决Win7系统下MyEclipse与Tomcat连接问题

    前言 本文旨在帮助学习java web开发的人员,熟悉环境,在Win7系统下运行自己的第一个Servlet程序,因为有时候配置不当或系统原因可能会运行不成功,这给初学者带来了一定烦恼,我也是为此烦恼过 ...

  2. 第31讲 UI组件之 Gallery画廊控件

    第31讲 UI组件之 Gallery画廊控件 1.Gallery的简介 Gallery(画廊)是一个锁定中心条目并且拥有水平滚动列表的视图,一般用来浏览图片,并且可以响应事件显示信息.Gallery只 ...

  3. 安装tcmalloc

    安装google-perftools:#tar zxvf google-perftools-1.6.tar.gz #cd google-perftools-1.6 #./configure#make# ...

  4. [Unit Testing] Based on input value, spyOn function

    describe( 'Forgot Password: with username', ()=> { let dirElementInput; beforeEach( ()=> { // ...

  5. 单片机脚本语言-移植lua到stm32-MDK

    Lua简单介绍 Lua[1]  是一个小巧的脚本语言.作者是巴西人.该语言的设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能. Lua脚本能够非常easy的被C/C++ 代码调用, ...

  6. [转载]C#开源项目(国外的还是很多)

    C#开源项目(国外的还是很多)一.Ajax框架Ajax.NET Professional (AjaxPro)是最先把AJAX技术在微软.NET环境下的实现的AJAX框架之一.它在客户端脚本之上创建代理 ...

  7. compilation 元素(ASP.NET 设置架构)

    配置 ASP.NET 用于编译应用程序的所有编译设置. <configuration> 元素  system.web 元素(ASP.NET 设置架构)    compilation 元素( ...

  8. JavaScript操作剪贴板(转)

    IE是第一个支持与剪贴板相关的事件,以及通过JavaScript访问剪贴板数据的浏览器.IE的实现成为了某种标准,不仅Safari 2.Chrome和Firefox 3也都支持类似的事件和剪贴板(Op ...

  9. 数据泵导出/导入Expdp/impdp

    一下转自 http://blog.csdn.net/jionjionyoushen/article/details/6789686 数据泵导出/导入Expdp/impdp Oracle 10g引入了D ...

  10. BestCoder Round #81 (div.2)1001

    Machine Accepts: 580 Submissions: 1890 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65 ...