重新更新一篇可以说整个工程聊天界面最重要的一part,聊天列表的实现,这里我采用循序渐进的方法来完成学习,我先用setFrame的方法来实现,虽然setFrame方法复杂,但是对整体理解的要求更加高,更能理解面相对象的很多特性,例如封装、类的抽象化、对象消息传参等等重要的知识点。而setFrame的实现也是先实现纯文本的对话形式,当保证文本可以正常无bug的实现后再开枝散叶式地添加语音、图像、视频、表情等等等。而且setFrame的方法必须上网参考别人的起码三种实现,因为不同的代码风格和有一些实现技巧都可以对比对比,并且取其精华去其糟粕。当setFrame可以很好地实现,那么就开始尝试masonry的实现!
纯文本下setFrame方法:
先来看看实现一:
实现的类结构:
Model层的实现:
一:
ChartMessage.h
typedef enum
{
kMessageFrom = 0,
kMessageTo
} ChartMessageType;
#import <Foundation/Foundation.h>
@interface ChartMessage : NSObject
@property (nonatomic, assign) ChartMessageType messageType;//是消息的发送者还是接收者
@property (nonatomic, copy) NSString* icon;//icon是头像对应UIImage
@property (nonatomic, copy) NSString* content;//内容
@property (nonatomic, copy) NSDictionary* dict;//dic 装的是什么?
@end
ChartMessage.m
#import "ChartMessage.h"
@implementation ChartMessage
//这里可以开始掌握一种写法,在set方法里面设置数据变量
- (void)setDict:(NSDictionary *)dict
{
_dict = dict;
self.icon = dict[@"icon"];
self.content = dict[@"content"];
self.messageType = [dict[@"type"] intValue];
}
@end
二:
ChartCellFrame.h
#import "ChartMessage.h"
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@interface ChartCellFrame : NSObject
@property (nonatomic, assign) CGRect iconRect; //图标的Rect值
@property (nonatomic, assign) CGRect chartViewRect; //聊天内容的Rect值
@property (nonatomic, strong) ChartMessage* chartMessage; //聊天内容
@property (nonatomic, assign) CGFloat cellHeight; //整体的高度
@end
ChartCellFrame.m
#import "QQChating.h"
#import "ChartCellFrame.h"
@implementation ChartCellFrame
- (void)setChartMessage:(ChartMessage *)chartMessage
{
_chartMessage = chartMessage;
CGSize winSize = [UIScreen mainScreen].bounds.size;
CGFloat iconX = kIconMarginX;
CGFloat iconY = kIconMarginY;
CGFloat iconWidth = 40;
CGFloat iconHeight = 40;
if (chartMessage.messageType == kMessageFrom)
{
}
else if (chartMessage.messageType == kMessageTo)
{
iconX = winSize.width - kIconMarginX - iconWidth;
}
self.iconRect = CGRectMake(iconX, iconY, iconWidth, iconHeight);
CGFloat contentX = CGRectGetMaxX(self.iconRect) + kIconMarginX;
CGFloat contentY = iconY;
//这里为什么是写死200
NSDictionary* attributes = @{NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue" size:13]};
CGSize contentSize = [chartMessage.content boundingRectWithSize:CGSizeMake(200, MAXFLOAT)
options:NSStringDrawingTruncatesLastVisibleLine |
NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading
attributes:attributes
context:nil].size;
if (chartMessage.messageType == kMessageTo)
{
contentX = iconX - kIconMarginX - contentSize.width - iconWidth;
}
self.chartViewRect = CGRectMake(contentX, contentY,
contentSize.width + 35,
contentSize.height + 30);
self.cellHeight = MAX(CGRectGetMaxY(self.iconRect), CGRectGetMaxY(self.chartViewRect)) + kIconMarginY;
}
@end
View层的实现:
一:
ChartContentViewDelegate.h
#import <Foundation/Foundation.h>
@class ChartContentView, ChartMessage;
@protocol ChartContentViewDelegate <NSObject>
//定义一个委托类,越来越觉得委托的作用和接口一样了。
//如何定义参数上都是一门学问,例如可以传的东西有,self自身(self这种东西很有用的)
//这个时候就要第一个参数的类是self类,同时另外的参数可以根据需求来
- (void)chartContentViewLongPress:(ChartContentView *)chartView content:(NSString *)content;
- (void)chartContentViewTapPress:(ChartContentView *)chartView content:(NSString *)content;
@end
二:
ChartContentView.h
#import "QQChating.h"
#import <UIKit/UIKit.h>
#import "ChartMessage.h"
#import "ChartContentViewDelegate.h"
@interface ChartContentView : UIView
@property (nonatomic, strong)UILabel* contentLabel;
@property (nonatomic, strong)ChartMessage* chartMessage;
@property (nonatomic, strong)UIImageView* backImageView;
@property (nonatomic, strong)id<ChartContentViewDelegate> delegate;
@end
ChartContentView.m
#import "ChartContentView.h"
@implementation ChartContentView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backImageView = [[UIImageView alloc] init];
self.backImageView.userInteractionEnabled = YES;
[self addSubview:self.backImageView];
self.contentLabel = [[UILabel alloc] init];
self.contentLabel.numberOfLines = 0;
self.contentLabel.textAlignment = NSTextAlignmentLeft;
self.contentLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:13];
[self addSubview:self.contentLabel];
[self addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longTap:)]];
[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapPress:)]];
}
return self;
}
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
self.backImageView.frame = self.bounds;
CGFloat contentLabelX = 0;
if (self.chartMessage.messageType == kMessageFrom)
{
contentLabelX = kContentStartMargin*0.8;
}
else if (self.chartMessage.messageType == kMessageTo)
{
contentLabelX = kContentStartMargin*0.5;
}
self.contentLabel.frame = CGRectMake(contentLabelX, -3,
self.frame.size.width-kContentStartMargin-5, self.frame.size.height);
}
/**
* 表面上是一个普通的手势,其实内涵乾坤
* 这里的乾坤就是表面上是contentView的长按操作
* 其实就是为了委托方法的实现
* 就相当于textField输入框的代理方法里面,你一输入,调用的却是self.delegate的执行代理方法
*/
- (void)longTap:(UILongPressGestureRecognizer *)longTap
{
if ([self.delegate respondsToSelector:@selector(chartContentViewLongPress:content:)])
{
[self.delegate chartContentViewLongPress:self content:self.contentLabel.text];
}
}
- (void)tapPress:(UILongPressGestureRecognizer *)tapPress
{
if ([self.delegate respondsToSelector:@selector(chartContentViewTapPress:content:)])
{
[self.delegate chartContentViewTapPress:self content:self.contentLabel.text];
}
}
@end
接下篇!