iOS基礎-高級視圖-UITableView--實例:QQ聊天

1、搭建UI界面
1.在普通視圖控制器中放一個TableView
2.拖一個UIView,做爲底部工具條
3.在UIView上放一個imageView,換成純白色背景。而後在UIView上放一個按鈕
4.將按鈕的image屬性換成語音圖標,高度寬度均爲44。x,y爲0.(注意不要把背景圖
片屬性換成語音圖標,會被拉伸。),同理再拖2個按鈕換成相應圖標
5.拖一個文本輸入框,將其背景圖片屬性設置爲相應的圖片。數組

2、往TableView中放數據
1.設置數據源
2.新建一個模型MJMessage(plist裏有3個屬性,因此添加3條屬性)ide

typedef enum {
MJMessageTypeMe = 0//本身發的
MJMessageTypeOther // 別人發的
} MJMessageType;
//聊天內容
@property (nonatomic,copy)NSString *text;
//消息發送時間
@property (nonatomic,copy)NSString *time;
//發送者
@property (nonatomic,copy)MJMessageType *type;
//是否顯示時間
@property (nonatomic,assign)BOOL hideTime ;

//提供字典轉模型的方法,並實現。
+(instancetype)messageWithDict:(NSDictionary *)dict;
-(instancetype)initWithDict:(NSDictionary *)dict;

+(instancetype)messageWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}

-(instancetype)initWithDict:(NSDictionary *)dict
{
if(self = [super init]) {
       [self setValuesForKeysWithDictionary:dict];
   }
       return self;
}

 

3.加載模型數據工具

@property(nonatomic,strong)NSMutableArray *messageFrames;
-(NSMutableArray *)messageFrames
{
if(_messageFrames == nil){
//從plist裏面加載出來字典數組
NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"nessages.plist" ofType:nil]]; 
NSMutbleArray *msgArray = [NSMutableArray array];
// 將字典轉成message模型
for (NSDictionary *dict in dictArray) {
//消息模型
MJMessage *msg = [MJMessage messageWithDict:dict];

//取出上一個模型
MJMessageFrame *lastMf = [mfArray lastObejct];
MJMessage *lastMsg = lastMf.message;

//判斷兩個消息的時間是否一致
msg.hideTime = [msg.time isEqualToString:lastMsg.time];

//frame模型
MJMessageFrame *mf = [MJMessageFrame alloc] init];
mf.message = msg;

//添加
[mfArray addObejct:mf];
}

      _messageFrames = mfArray;
   }
       return _messageFrames;
}

4.遵照協議並實現數據源方法字體

第一個數據源方法: 由於只有一列因此能夠不實現。默認爲1列
第二個數據源方法: numberOfRowsInSection:方法
return self.messageFrames.count;
第三個數據源方法: cellForRowAtIndexPath:方法
//1.建立cell
MJMessageCell *cell = [MJMessageCell cellWithTableView:tableView];
//2.給cell傳遞模型(在算完frame和cell高度以後進行這一步)
cell.messageFrame = self.messageFrames[indexPath.row];
//3.返回cell
return cell;

5.設置行高(設置代理遵照協議並實現代理方法 heightForRowAtIndexPath:方法)atom

{
    MJMessageFrame *mf = self.messageFrames[indexPath.row];
    return cellHeight;
}

6..經過代碼自定義cell(cell的高度不一致)
1>新建一個Cell類MJMessageCell(注意要提供一個方法快速建立cell)
2>在cell的實現文件中重寫initWithStyle:reuseIndetifier:方法
添加全部須要顯示的子控件(不須要設置子控件的屬性和frame,子控件要添加到contentView中)
進行子控件一次性的屬性設置(有些屬性只須要設置一次,好比字體、固定的圖片)spa

//由於時間,頭像和正文要在其餘方法中使用,因此先將它們聲明爲成員變量
@property (nonatomic,weak)UILabel *timeView;
@property (nonatomic,weak)UIImageView *iconView;
@property (nonatomic,weak)UIButton *textView;
在這個例子中
//1.時間
UILabel *timeView = [[UILabel alloc] init];
timeView.textAlignment = NSTextAlignmentCenter
timeView.textColor = [UIColor lightGrayColor];
timeView.font = [UIFont systemFont:13];
[self.contentView addSubview:timeView];
self.timeView = timeView;
//2.頭像
UIImageView *iconView = [UIImageView alloc] init];
[self.contentView addSubview:iconView];
self.iconView = iconView;
//3.正文
UIButton *textView = [[UIButton alloc] init];
textView.titleLabel.numberOfLines = 0//自動換行
textView.titleLabel.font = MJTextFont;
textView.contextEdgaInsets = UIEdgeInsetsMake(MJTextPadding,MJTextPadding,MJTextPadding,MJTextPadding); 
[textView setTitleColor:[UIColor blackColor] ForState:UIControlStateNormal];
[self.contentView addSubview:textView];
self.textView = textView;

//4.設置cell的背景色
self.backgroundColor = [UIColor clearColor];


3>提供2個模型

數據模型:存放文字數據/圖片數據。已經建立好了,爲MJMessage
frame模型:存放數據模型/全部子控件的frame/cell的高度
新建一個類MJMessageFrame並添加屬性代理

//頭像frame
@property(nonatomic,assgin,readonly)CGRect iconF;
//事件的frame
@property(nonatomic,assgin,readonly)CGRect timeF;
//正文的frame
@property(nonatomic,assgin,readonly)CGRect textF;
//cell的高度
@property(nonatomic,assgin,readonly)CGFloat cellHeight;
//數據模型
@class MJMessage;
@property(nonatomic,strong)MJMessage *message;

4>cell擁有一個frame模型(不要直接擁有數據模型)
@property(nonatomic,strong)MJMessageFrame *messageFrame;
5>重寫frame模型屬性的setter方法,在這個方法中設置子控件的顯示數據和framecode

-(void)setMessageFrame:(MJMessageFrame *)messageFrame
{
   _messageFrame = messageFrame;

   MJMessage *message = messageFrame.message; 
//1.時間
self.timeView.text = message.time;
self.timeView.frame = messageFrame.timeF;
//2.頭像
NSString *icon = message.type == MJMessageTypeMe ? @"me"@"other";
self.iconView.image = [UIImage imageNamed:icon];
self.iconView.frame = messageFrame.iconF;
//3.正文
[self.textView setTitle:message.text forState:UIControlStateNormal];
self.textView.frame = messageFrame.textF;

//4.正文的背景
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]; 
   }
} 

知識點:圖片過小文字放不下怎麼辦-->設置按鈕的內邊距orm

-(void)setMessage:(MJMessage *)message
{
_message = message;
//間距
CGFloat padding = 10//屏幕的寬度
CGFloat screenW = [UIScreen mainScreen].bounds.width;

//1.時間
message.time
if (message.hideTime == NO ){ //顯示時間
CGFloat timeX = 0;
CGFloat timeY = 0;
CGFloat timeW= screenW;
CGFloat timeH= 40;
_timeF = CGRectMake(timeX,timeY,timeW,timeH);
}
//2.頭像
CGFloat iconY = CGRectGetMaxY(_timeF)+ padding;
CGFloat iconW = 40;
CGFloat iconH = 40;
CGFloat iconX;
if(message.type == MJMessageTypeOther) { //別人發的
iconX = padding;
} else { //本身發的
iconX = screenW - padding - iconW; 
} 
_iconF = CGRectMake(iconX,iconY,iconW,iconH);

//3.正文
CGFloat textY = iconY;


//文字計算的最大的尺寸
CGSize textMaxSize = CGSizeMake(150,MAXFLOAT);
//文字計算出來的真實尺寸(按鈕內部label的尺寸)
CGSize textRealSize = [message.text sizeWithFont:MJTextFont  maxSize:textMaxSize];
//按鈕最終的真實尺寸
CGSize textBtnSize = CGSizeMake(textRealSize.width + MJTextPadding * 2,textRealSize.height+ MJTextPadding * 2); 
CGFloat textX;
if(message.type == MJMesageTypeOther) {
textX= CGRectGetMaxX(_iconF)+padding;
} else { 
textX = iconX - padding - textBtnSize.width ;
}
}
_textF =(CGRect){{textX,textY}, textBtnSize};
}

//4.cell的高度
CGFloat textMaxY = CGRectGetMaxY(_textF);
CGFloat iconMaxY = CGRectGetMaxY(_iconF);
_cellHeight = MAX(textMaxY,iconMaxY) + padding;

6>frame模型數據的初始化已經採起惰性初始化的方式(每個cell對應的frame模型數據只加載一次) blog

細節:
1.在viewDidLoad中去除分隔線
1>連線拿到tableView
2>self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
2.添加背景色

self.tableView.backgroundColor = [UIColor colorWithRed:224/255.0 green:224/255.0 Blue:224/255.0 alpha:1.0]; 

3.去掉狀態欄

-(BOOL)prefersStatusBarHidden
{
    return YES;
}

4.cell不能被選中

self.tableView.allowsSelection = NO;

3、將實用的功能抽成分類(不必使用類)
分類:給已經存在的類擴展一些方法
1.功能1: 計算文字尺寸
1>新建一個NSString的分類Extension
2>聲明並實現下列方法

/* 
@param font 文字的字體
@param maxSize 文字的最大尺寸
*/
-(CGSzie)sizeWithFont:(UIFont *)font maxSize:(CGSzie)maxSize
{
    NSDictionary *attrs = @[NSFontAttributeName : font ];
    return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs  context:nil].size; 
}

3>導入分類頭文件便可使用該分類裏的方法。

2.功能二:返回一張能夠隨意拉伸不變形的圖片
1>新建一個UIImage的分類Extension
2>聲明並實現下列方法

+(UIImage *)resizableImage:(NSString *)name
{
UIImage *normal = [UIImage imageNamed:name];
CGFloat w = normal.size.width * 0.5;
CGFloat h = normal.size.height * 0.5return [normal resizableImageWithCapInsets:UIEdgeInsetsMake(h,w,h,w) ]; 
}

3>導入分類頭文件便可使用該分類裏的方法。

相關文章
相關標籤/搜索