我是靠谱客的博主 危机保温杯,最近开发中收集的这篇文章主要介绍QQ聊天界面实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

QQ聊天界面实现

效果如下:

实现过程:

1、首先实现基本界面

头像使用 UIImageView :

文字消息使用 UIButton

标签使用 UILable :水平居中

所有元素在一个cell中,在加载cell时进行判断显示和隐藏。

合理设置各个控件之间的约束关系。主要是UIIimageVIew和UIButton顶部对齐,间距为10。UIButton的宽度设置一个约束范围,比如说 (>=60 &&  <=300);

底部添加一个UIView ,添加输入框等。

2、创建模型文件

所有元素在一个cell中,在加载cell时进行判断显示和隐藏。

按照message.plist文件内容添加需要的属性,然后添加一个cellHeight属性计算cell高度,和一个决定是否显示时间到cell得属性hideTime。

#import <UIKit/UIKit.h> 

// 枚举类型,

typedefenum {

SLQMessageTypeMe = 0 , 

SLQMessageTypeOther = 1

}SLQMessageType;

@interface SLQMessage : NSObject

/* 内容 */ 

@property ( strong , nonatomic ) NSString *text;

/* 时间 */ 

@property ( strong , nonatomic ) NSString *time;

/* 类型 */ 

@property ( assign , nonatomic ) SLQMessageType type;

/*cellHeight*/

@property ( assign , nonatomic ) CGFloat cellHeight;

/* 是否隐藏时间 */

@property ( assign , nonatomic , getter =isHideTime) BOOL hideTime;

+ ( instancetype )MessageWithDict:( NSDictionary *)dict; 

@end

实现文件

#import "SLQMessage.h" 

@implementation SLQMessage

+( instancetype )MessageWithDict:( NSDictionary *)dict 

{

SLQMessage *message = [[ SLQMessage alloc ] init ]; 

[message setValuesForKeysWithDictionary :dict];

return message; 

}

@end

这里需要注意的就是枚举类型的使用,如果在一个类中要定义枚举类型,那么命名规则就是:

以类名开头后面直接跟操作标识;如 SLQMessage + Type ; 

3、实现对cell操作的封装

#import <UIKit/UIKit.h> 

@class SLQMessage ;

@interface SLQMessageCell : UITableViewCell

/* 模型对象 */ 

@property ( strong , nonatomic ) SLQMessage *message;

+ ( instancetype )cellWithTableView:( UITableView *)tableView; 

@end

对tableView的每一个控件拖线建立关联。然后重写setter方法,对控件进行赋值。

#import "SLQMessageCell.h" 

#import "SLQMessage.h" 

//define this constant if you want to use Masonry without the 'mas_' prefix

#define MAS_SHORTHAND

//define this constant if you want to enable auto-boxing for default syntax

#define MAS_SHORTHAND_GLOBALS

#import "Masonry.h" 

@interface SLQMessageCell ()

@property ( weak , nonatomic ) IBOutlet UILabel *timeLable;

@property ( weak , nonatomic ) IBOutlet UIButton *meBtn;

@property ( weak , nonatomic ) IBOutlet UIImageView *meImage;

@property ( weak , nonatomic ) IBOutlet UIButton *otherBtn;

@property ( weak , nonatomic ) IBOutlet UIImageView *otherImage;

@end

@implementation SLQMessageCell 

// 重写 setter 方法

- ( void )setMessage:( SLQMessage *)message 

{

_message = message; 

self . backgroundColor = [ UIColor brownColor ];

if (message. isHideTime ) // 隐藏时间

{

self . timeLable . hidden = YES ; 

[ self . timeLable updateConstraints :^( MASConstraintMaker *make) {

make. height . equalTo ( 0 ); // 高度为0 

}];

}

else

{

self . timeLable . text = message. time ; 

self . timeLable . hidden = NO ; 

[ self . timeLable updateConstraints :^( MASConstraintMaker *make) {

make. height . equalTo ( 22 ); 

}];

}

if (message. type == SLQMessageTypeMe ) 

{

[ self setShowBtn : self . meBtn WithShowImage : self . meImage WithHideBtn :self . otherBtn WithHideImage : self . otherImage ];

}

if (message. type == SLQMessageTypeOther ) 

{

[ self setShowBtn : self . otherBtn WithShowImage : self . otherImage WithHideBtn : self . meBtn WithHideImage : self . meImage ];

}

}

因为每次显示cell都要进行计算,将cell的显示封装到方法中。

// 显示隐藏控件并计算控件的高度

- ( void )setShowBtn:( UIButton *)showBtn WithShowImage:( UIImageView*)showImage WithHideBtn:( UIButton *)hideBtn WithHideImage:( UIImageView*)hideImage 

{

[showBtn setTitle : self . message . text forState : UIControlStateNormal ];

// 隐藏其他

hideBtn. hidden = YES ; 

hideImage. hidden = YES ; 

// 显示自己

showBtn. hidden = NO ; 

showImage. hidden = NO ; 

// 强制更新

[ self layoutIfNeeded ];

// 更新约束,设置按钮的高度就是 textLable 的高度 

[showBtn updateConstraints :^( MASConstraintMaker *make) { 

CGFloat buttonH = showBtn. titleLabel . frame . size . height ; // 

make. height . equalTo (buttonH); 

}];

// 强制更新

[ self layoutIfNeeded ];

CGFloat btnMaxY = CGRectGetMaxY (showBtn. frame ); 

CGFloat imageMaxY = CGRectGetMaxY (showImage. frame ); 

// 设置 cell 高度

self . message . cellHeight = MAX (btnMaxY, imageMaxY) + 10 ; 

}

其他方法和以往一样

+ ( instancetype )cellWithTableView:( UITableView *)tableView 

{

SLQMessageCell *cell = [tableView dequeueReusableCellWithIdentifier :@"message" ];

return cell; 

}

- ( void )awakeFromNib { 

// Initialization code 

// 多行显示

self . meBtn . titleLabel . numberOfLines = 0 ;

self . otherBtn . titleLabel . numberOfLines = 0 ;

}

4、接下来说说按钮背景的问题

按钮背景默认填充整个按钮,但是默认情况下的填充效果不是很好。

如下代码:

UIImageView *imageView = [[ UIImageView alloc ] init ]; 

imageView. frame = CGRectMake ( 10 , 10 , 300 , 200 ); 

UIImage *image = [ UIImage imageNamed : @"chat_send_nor" ]; 

// 方法 1 , 设置拉伸间距,默认拉伸中心 1*1 像素 

//image = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5]; 

// 方法 2 设置边界

UIEdgeInsets edge = UIEdgeInsetsMake ( 50 , 40 , 40 , 40 ); 

//image = [image resizableImageWithCapInsets:edge ]; 

// UIImageResizingModeStretch 拉伸模式

// UIImageResizingModeTile 填充模式

image = [image resizableImageWithCapInsets :edge resizingMode :UIImageResizingModeStretch ];

// 方法 3 

// 在 images.xcassets 中对图片进行设置

imageView. image = image; 

[ self . view addSubview :imageView]; 

// 对比图片

UIImageView *imageView1 = [[ UIImageView alloc ] init ]; 

imageView1. frame = CGRectMake ( 10 , 210 , 300 , 200 ); 

UIImage *image1 = [ UIImage imageNamed : @"chat_send_nor" ]; 

imageView1. image = image1; 

[ self . view addSubview :imageView1]; 

会出现以下效果,默认是下边的图片,所以有必要对图片进行拉伸。

其中方法3的设置是将图片导入Image.xcassets中后选中图片设置。

可以通过代码设置按钮的内间距

//  可以这样设置内间距 

UIEdgeInsets edge =  UIEdgeInsetsMake ( 15 ,  15 ,  15 ,  15 ); 

[showBtn setTitleEdgeInsets :edge]; 

或者直接在按钮的属性里设置

设置过间距后,就可以计算btn的高度时,因为textlable的高度不固定,所以让btn的高度等于textLable 的高度。但是又因为按钮背景图片的边缘有一部分是透明的,如下:红色是按钮,蓝色是图片。  

   

所以显示文字高度会,这里对其按钮高度 + 30,而textLable默认会水平垂直居中。

5、在控制器中得实现方法和以往的一样

只需要在这里判断以下消息显示的时间是否一致,如果一致就隐藏。

- ( NSMutableArray *)messages 

{

if ( _messages == nil ) 

{

NSArray *dictArray = [ NSArray arrayWithContentsOfFile :[[ NSBundle mainBundle ] pathForResource : @"messages.plist" ofType : nil ]];

NSMutableArray *tempArray = [ NSMutableArray array ];

// 记录上一个 message ,判断是否显示时间

SLQMessage *lastMessage = nil ; 

for ( NSDictionary *dict in dictArray) 

{

SLQMessage *message = [ SLQMessage MessageWithDict :dict]; 

message. hideTime = [message. time isEqualToString :lastMessage. time ]; 

[tempArray addObject :message]; 

// 重新赋值

lastMessage = message;

}

_messages = tempArray; 

}

return _messages ;

}

- ( void )viewDidLoad { 

[ super viewDidLoad ];

}

/**

*  tableView 行数

*/

- ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section 

{

//NSLog(@"%zd",self.messages.count); 

returnself . messages . count ;

}

/**

* 设置每一个 cell 

*/

- ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath 

{

SLQMessageCell *cell = [ SLQMessageCell cellWithTableView :tableView];

cell. message = self . messages [indexPath. row ]; 

return cell; 

}

/**

* 设置 cell 高度

*/

- ( CGFloat )tableView:( UITableView *)tableView heightForRowAtIndexPath:( NSIndexPath *)indexPath 

{

SLQMessage *message = self . messages [indexPath. row ]; 

return message. cellHeight ; 

}

/**

*  给出预估高度 

*/

- ( CGFloat )tableView:( UITableView *)tableView estimatedHeightForRowAtIndexPath:( NSIndexPath *)indexPath 

{

return 200 ; 

}

@end

总结:

这是一种方法,还有其他的实现方法,接下来尝试一下。

5、用两个cell实现界面

只需改动一些代码就行。

1、改动每个cell的标志 一个是me,一个是other

2、修改setter方法

// 重写 setter 方法

- ( void )setMessage:( SLQMessage *)message 

{

_message = message; 

self . backgroundColor = [ UIColor brownColor ];

if (message. isHideTime ) // 隐藏时间

{

self . timeLable . hidden = YES ; 

[ self . timeLable updateConstraints :^( MASConstraintMaker *make) {

make. height . equalTo ( 0 ); 

}];

}

else

{

self . timeLable . text = message. time ; // 显示时间

self . timeLable . hidden = NO ; 

[ self . timeLable updateConstraints :^( MASConstraintMaker *make) {

make. height . equalTo ( 22 ); 

}];

}

//

[ self . contentBtn setTitle :message. text forState : UIControlStateNormal ];

// 强制布局

[ self layoutIfNeeded ];

// 添加约束

[ self . contentBtn updateConstraints :^( MASConstraintMaker *make) {

CGFloat textLableHeight = self . contentBtn . titleLabel . frame . size . height + 30 ; 

make. height . equalTo (textLableHeight); 

}];

[ self layoutIfNeeded ];

CGFloat btnMaxY = CGRectGetMaxY ( self . contentBtn . frame ); 

CGFloat iconMaxY = CGRectGetMaxY ( self . iconImage . frame ); 

message. cellHeight = MAX (btnMaxY, iconMaxY); 

}

3、修改返回cell对象的方法,传入一个message用来判断是哪个cell

/**

* 返回 cell 对象

*/

+ ( instancetype )cellWithTableView:( UITableView *)tableView andMessage:( SLQMessage *)message 

{

NSString *ID =  (message. type == SLQMessageTypeMe )? @"me" : @"other" ; 

SLQMessageCell *cell = [tableView dequeueReusableCellWithIdentifier :ID];

return cell; 

}

4、在控制器中设置如下

/**

* 设置每一个 cell 

*/

- ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath 

{

// 获取一个 cell ,根据类型

SLQMessageCell *cell = [ SLQMessageCell cellWithTableView :tableView andMessage : self . messages [indexPath. row ]]; 

cell. message = self . messages [indexPath. row ]; 

return cell; 

}

好了,效果一样。

最后

以上就是危机保温杯为你收集整理的QQ聊天界面实现的全部内容,希望文章能够帮你解决QQ聊天界面实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(79)

评论列表共有 0 条评论

立即
投稿
返回
顶部