iOS学习08代码2

来源:互联网 发布:阿里云搭建hadoop 编辑:程序博客网 时间:2024/05/24 07:33

两个小例子涉及到的知识:

1. 代码自定义cell,且高度不同

2. 文本在屏幕宽高的计算

3. 图片拉伸

4. 通知机制

5. 键盘处理

6. 代理设计模式

7. 模型中有模型

8. 自定义tableView每组的headerView

QQ聊天界面

//  Controller//  ViewController.m//  1107-QQcel////  Created by 修修 on 15/11/7.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import "ViewController.h"#import "SLMessageFrame.h"#import "SLMessage.h"#import "SLMessageCell.h"@interface ViewController () <UITableViewDataSource, UITableViewDelegate, UITextViewDelegate>@property (weak, nonatomic) IBOutlet UITableView *tableView;/** *  模型数组 */@property (nonatomic, strong) NSMutableArray *messageFrames;/** *  下面的工具条 */@property (weak, nonatomic) IBOutlet UIView *toolView;/** *  文本框 */@property (weak, nonatomic) IBOutlet UITextField *textView;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // 设置tableview的背景色    self.tableView.backgroundColor = [UIColor colorWithRed:224/255.0 green:224/255.0 blue:224/255.0 alpha:1.0];    // 去除tableview的分割线    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;            // 注册监听器    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];    [center addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];        // 光标位置    UIView *rigthview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 8, 0)];    self.textView.leftView = rigthview;    self.textView.leftViewMode = UITextFieldViewModeAlways;    }/** *  当return按下后调用 */- (BOOL)textFieldShouldReturn:(UITextField *)textField{    // 拿到文本框中的文字    NSString *content = textField.text;    SLMessage *newMessage = [[SLMessage alloc] init];    // 内容    newMessage.text = content;    // 类型    newMessage.type = MessageTypeMe;    // 时间    NSDate *now = [NSDate date];    NSDateFormatter *format = [[NSDateFormatter alloc] init];    format.dateFormat = @"HH:mm";    newMessage.time = [format stringFromDate:now];    // 时间是否与上一条一样    SLMessageFrame *lastFrame = [self.messageFrames lastObject];    SLMessage *lastMessage = lastFrame.message;    newMessage.sameTime = [newMessage.time isEqualToString:lastMessage.time];    // 增加模型    SLMessageFrame *newFrame = [[SLMessageFrame alloc] init];    newFrame.message = newMessage;    [self.messageFrames addObject:newFrame];    // 刷新界面    [self.tableView reloadData];    // 立即滚到所发的信息(最后一行)    NSIndexPath *lastPath = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0];    [self.tableView scrollToRowAtIndexPath:lastPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];    // 清空文本    self.textView.text = nil;        // 通常都是返回yes    return YES;}- (void)dealloc{    // 移除监听器    [[NSNotificationCenter defaultCenter] removeObserver:self];}// 收到通知后调用- (void)keyboardWillChangeFrame:(NSNotification *)notification{    // 取出通知中的的字典    NSDictionary *userInfoDict = notification.userInfo;    // 获得动画时间    CGFloat animTime = [userInfoDict[UIKeyboardAnimationDurationUserInfoKey] floatValue];    // 键盘的高度    CGFloat keybroadY = [userInfoDict[UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y;    // view的变化高度    CGFloat tranY = keybroadY - self.view.frame.size.height;    // 动画    [UIView animateWithDuration:animTime animations:^{        self.view.transform = CGAffineTransformMakeTranslation(0, tranY);    }];    }// 去除屏幕的状态栏- (BOOL)prefersStatusBarHidden {    return YES;}# pragma mark - getter懒加载方法- (NSMutableArray *)messageFrames{    if (_messageFrames == nil) {        // 拿到plist里的数组        NSString *path = [[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil];        NSArray *tempAry = [NSArray arrayWithContentsOfFile:path];        // 可变数组,临时保存模型的数据        NSMutableArray *tempMuary = [NSMutableArray array];        // 遍历数组,完成字典转模型        for (NSDictionary *dict in tempAry) {            // 通过字典初始化模型            SLMessage *message = [SLMessage messageWithDict:dict];            // 判断当前消息的时间是否与上一条消息相同,如果相同,不要显示时间            // 拿到上一个位置模型,就是可变数组的最后一个元素            SLMessageFrame *pastFrame = [tempMuary lastObject];            // 得到数据模型            SLMessage *pastMes = pastFrame.message;            // 判断事件是否相同            if ([pastMes.time isEqualToString:message.time]) {                // 将数据模型的sameTime设置为YES                message.sameTime = YES;            }            // 初始化位置模型            SLMessageFrame *messageframe = [[SLMessageFrame alloc] init];            // 给位置模型中的数据模型赋值,同时会计算出相应控件的位置            messageframe.message = message;            // 将位置模型添加到可变数组中            [tempMuary addObject:messageframe];        }        _messageFrames =tempMuary;    }    return _messageFrames;}#pragma mark - tableView数据源方法- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    return self.messageFrames.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    SLMessageCell *cell = [SLMessageCell messageCellWithTableView:tableView];        cell.messageFrame = self.messageFrames[indexPath.row];        return cell;}#pragma mark - tableView代理方法- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    SLMessageFrame *tempF = self.messageFrames[indexPath.row];    return tempF.cellHeight;}// tableview 滑动的时候退出键盘- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{    // 退出键盘    [self.view endEditing:YES];}@end<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
//  <span style="font-family: Arial, Helvetica, sans-serif;">Model-frame</span>//  SLMessageCell.h//  1107-QQcel////  Created by 修修 on 15/11/7.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import <UIKit/UIKit.h>@class SLMessageFrame;@interface SLMessageCell : UITableViewCell/** *  位置模型 */@property (nonatomic, strong) SLMessageFrame *messageFrame;/** *  初始化一个cell * *  @param tableView       当前的tableview *  @param reuseIdentifier cell的唯一标识 */- (instancetype)initWithTableView:(UITableView *)tableView reuseIdentifier:(NSString *)reuseIdentifier;+ (instancetype)messageCellWithTableView:(UITableView *)tableView;@end////  SLMessageCell.m//  1107-QQcel////  Created by 修修 on 15/11/7.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import "SLMessageCell.h"#import "SLMessageFrame.h"#import "SLMessage.h"@interface SLMessageCell ()/** *  icon */@property (nonatomic, weak) UIImageView *iconView;/** *  time */@property (nonatomic, weak) UILabel *timeLabel;/** *  text */@property (nonatomic, weak) UIButton *textBtn;@end@implementation SLMessageCell+ (instancetype)messageCellWithTableView:(UITableView *)tableView{    // 这里涉及到循环利用    static NSString *ID = @"message";    SLMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];    if (cell == nil) {        cell = [[SLMessageCell alloc] initWithTableView:tableView reuseIdentifier:ID];    }    return cell;}- (instancetype)initWithTableView:(UITableView *)tableView reuseIdentifier:(NSString *)reuseIdentifier{    // 一定要先将父类初始化    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];    if (self) {        // 设置cell的颜色        UIColor *col = [UIColor colorWithRed:224/255.0 green:224/255.0 blue:224/255.0 alpha:1];        [self setBackgroundColor:col];                        // 头像的ImageView控件        UIImageView *iconview = [[UIImageView alloc] init];        [self.contentView addSubview:iconview];        self.iconView = iconview;        // 时间的Label控件        UILabel *timelabel = [[UILabel alloc] init];        timelabel.font = [UIFont systemFontOfSize:10];  // 设置字体        timelabel.textAlignment = YES;  // 设置居中显示        [self.contentView addSubview:timelabel];        self.timeLabel = timelabel;        // 消息文本的Button        UIButton *textbtn = [[UIButton alloc] init];        textbtn.titleLabel.numberOfLines = 0;   // 设置文字可以换行        [textbtn.titleLabel setFont:[UIFont systemFontOfSize:15]];  // 设置字体        [textbtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; // 字体颜色        // 因为btn背景图片边缘是透明的,而图片是填充显示的,所以要文字向里缩(设置文字的内边距)        [textbtn setTitleEdgeInsets:UIEdgeInsetsMake(20, 20, 20, 20)];  // 文字的内边距        [self.contentView addSubview:textbtn];        self.textBtn = textbtn;    }    return self;}/** *  通过重写位置模型的setter方法,将控件的frame和相应属性设置值 */- (void)setMessageFrame:(SLMessageFrame *)messageFrame{    // 必须写    _messageFrame = messageFrame;    // 拿到位置模型的数据模型    SLMessage *message = messageFrame.message;        // time的Label控件    self.timeLabel.frame = messageFrame.timeF;    self.timeLabel.text = message.time;        // icon的ImageView控件    self.iconView.frame = messageFrame.iconF;    // 要根据消息的类型设置不一样的头像    if (message.type) {        self.iconView.image = [UIImage imageNamed:@"other"];    // 别人的    }else {        self.iconView.image = [UIImage imageNamed:@"me"];   // 自己的    }        // text的Button控件    self.textBtn.frame = messageFrame.textF;    [self.textBtn setTitle:message.text forState:UIControlStateNormal];            // 设置气泡(背景的图片)    if (message.type) {        // 图片拉伸        UIImage *imageN =[self resizeImage:@"chat_recive_nor"];        [self.textBtn setBackgroundImage:imageN forState:UIControlStateNormal];        UIImage *imageH =[self resizeImage:@"chat_recive_press_pic"];        [self.textBtn setBackgroundImage:imageH forState:UIControlStateHighlighted];    }else {        UIImage *imageN = [self resizeImage:@"chat_send_nor"];        [self.textBtn setBackgroundImage:imageN  forState:UIControlStateNormal];        UIImage *imageH =[self resizeImage:@"chat_send_press_pic"];        [self.textBtn setBackgroundImage:imageH forState:UIControlStateHighlighted];    }    }/** *  图片拉伸方法,不会改变边缘 * *  @param imageName 图片名称 * *  @return 一张拉伸好的的图片 */- (UIImage *)resizeImage:(NSString *)imageName{    // 拿到图片    UIImage *image = [UIImage imageNamed:imageName];    CGFloat internal = image.size.width * 0.5;    UIEdgeInsets inset = UIEdgeInsetsMake(internal, internal, internal, internal);    // 图片的一个类方法    return [image resizableImageWithCapInsets:inset];}/*- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets NS_AVAILABLE_IOS(5_0); // create a resizable version of this image. the interior is tiled when drawn.- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode NS_AVAILABLE_IOS(6_0); // the interior is resized according to the resizingMode */@end
//  Model-data//  SLMessage.h//  1107-QQcel////  Created by 修修 on 15/11/7.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import <Foundation/Foundation.h>@interface SLMessage : NSObject/** *  信息类型的枚举 */typedef enum {    MessageTypeMe = 0, // 自己发的    MessageTypeOther   // 别人发的} SLMessageType;/** *  消息 */@property (nonatomic, copy) NSString *text;/** *  时间 */@property (nonatomic, copy) NSString *time;/** *  发送人 */@property (nonatomic, assign) SLMessageType type;/** *  消息是否要显示时间(是不是同一时间发的) */@property (nonatomic, assign, getter=isSameTime) BOOL sameTime;+ (instancetype)messageWithDict:(NSDictionary *)dict;- (instancetype)initMessageWithDict:(NSDictionary *)dict;@end////  SLMessage.m//  1107-QQcel////  Created by 修修 on 15/11/7.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import "SLMessage.h"@implementation SLMessage+ (instancetype)messageWithDict:(NSDictionary *)dict{    return [[self alloc] initMessageWithDict:dict];}- (instancetype)initMessageWithDict:(NSDictionary *)dict{    if (self = [super init]) {        [self setValuesForKeysWithDictionary:dict];    }    return self;}@end

QQ分组

//  Controller//  ViewController.m//  1108-QQ分组////  Created by 修修 on 15/11/8.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import "SLViewController.h"#import "SLGroup.h"#import "SLFriend.h"#import "SLHeaderView.h"@interface SLViewController () <headerViewDelegate>/** *  模型数组 */@property (nonatomic, strong) NSArray *groups;@end@implementation SLViewController- (void)viewDidLoad {    [super viewDidLoad];    // 设置头部view的高度    self.tableView.sectionHeaderHeight = 50;}-(BOOL)prefersStatusBarHidden {    // 隐藏状态栏    return YES;}#pragma mark - 懒加载- (NSArray *)groups{    if (_groups == nil) {        NSArray *tempArr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil]];        NSMutableArray *tempMuArr = [NSMutableArray array];        for (NSDictionary *dict in tempArr) {            SLGroup *group = [SLGroup groupWithDict:dict];            [tempMuArr addObject:group];        }        _groups = tempMuArr;    }    return _groups;}#pragma mark - tableView的数据源和代理/** *  返回有多少组 */- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{    return self.groups.count;}/** *  返回每组有多少行,在这里控制分组的开关,关就是0行 */- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    SLGroup *group = self.groups[section];    return group.isOpen ? group.friends.count : 0;}/** *  返回每一行的cell,这里都一样就没有封装,实际上是要封装一步的,把创建cell的过程封装起来 */- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    NSString *ID = @"person";    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];    if (cell == nil) {        cell =  [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];    }    SLGroup *group = self.groups[indexPath.section];    NSArray *friends = group.friends;    SLFriend *firendData = friends[indexPath.row];    cell.imageView.image = [UIImage imageNamed:firendData.icon];    cell.textLabel.text = firendData.name;    cell.detailTextLabel.text = firendData.intro;        return cell;}/** *  返回每一组的headerView */- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{    // 生成headerView    SLHeaderView *headview = [SLHeaderView headviewWithTableView:tableView];    // 设置headview的代理为控制器,用来刷新数据    headview.delegate = self;    // 传递模型    headview.group =self.groups[section];    // 返回view    return headview;}#pragma mark - headerView的代理方法- (void)btnClickOnHeaderView:(SLHeaderView *)headerView{    [self.tableView reloadData];}@end
//  View//  SLHeaderView.h//  1108-QQ分组////  Created by 修修 on 15/11/8.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import <UIKit/UIKit.h>@class SLGroup, SLHeaderView;// 代理@protocol headerViewDelegate <NSObject>@optional/** *  当view上的按钮点击的时候,就会通知代理调用此方法 */- (void)btnClickOnHeaderView:(SLHeaderView *)headerView;@end@interface SLHeaderView : UITableViewHeaderFooterView/** *  headerView上的Button */@property (nonatomic, weak) UIButton * headBtn;/** *  显示在线人数的Label */@property (nonatomic, weak) UILabel * numLabel;/** *  当前的分组模型,用来为控件设置数据 */@property (nonatomic, strong) SLGroup *group;/** *  代理,遵守相应的协议headerViewDelegate */@property (nonatomic, strong) id<headerViewDelegate> delegate;/** *  初始化headerView */+ (instancetype)headviewWithTableView:(UITableView *)tableView;@end////  SLHeaderView.m//  1108-QQ分组////  Created by 修修 on 15/11/8.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import "SLHeaderView.h"#import "SLGroup.h"@implementation SLHeaderView// setter方法,设置数据- (void)setGroup:(SLGroup *)group{    _group = group;        [self.headBtn setTitle:group.name forState:UIControlStateNormal];        self.numLabel.text = [NSString stringWithFormat:@"%d/%ld", group.online, group.friends.count];}// 重写init方法,添加控件- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier{    self = [super initWithReuseIdentifier:reuseIdentifier];    if (self) {        // 按钮        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];        [btn setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal];        btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;        btn.imageEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);        btn.titleEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0);        [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];        [btn.titleLabel setFont:[UIFont systemFontOfSize:20]];        [btn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal];        [btn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted];        // 监听按钮的点击事件        [btn addTarget:self action:@selector(headBtnClick) forControlEvents:UIControlEventTouchUpInside];        // 设置按钮内部的imageView的内容模式为居中        btn.imageView.contentMode = UIViewContentModeCenter;        // 超出边框的内容不需要裁剪        btn.imageView.clipsToBounds = NO;        [self.contentView addSubview:btn];        self.headBtn = btn;        // 标签        UILabel *lab = [[UILabel alloc] init];        lab.textAlignment = NSTextAlignmentRight;        lab.font = [UIFont systemFontOfSize:13];        lab.textColor = [UIColor grayColor];        [self.contentView addSubview:lab];        self.numLabel = lab;    }    return self;}+ (instancetype)headviewWithTableView:(UITableView *)tableView{    NSString *ID = @"head";    SLHeaderView *cell = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ID];    if (cell == nil) {        cell = [[self alloc] initWithReuseIdentifier:ID];    }    return cell;}- (void)headBtnClick{    // 1.修改组模型的标记(状态取反)    self.group.open = !self.group.isOpen;    // 2.刷新表格    if ([self.delegate respondsToSelector:@selector(btnClickOnHeaderView:)]) {        [self.delegate btnClickOnHeaderView:self];    }}/** *  当一个空间的frame发生改变时就会调用 *  一般在这里布局子控件(设置frame) */- (void)layoutSubviews{#warning 一定要调用父类,,,要不然就GG了    [super layoutSubviews];        self.headBtn.frame = self.bounds;    CGFloat numLabelH = self.bounds.size.height;    CGFloat numLabelY = 0;    CGFloat numLabelW = 100;    CGFloat numLabelX = self.bounds.size.width - 100 - 10;    self.numLabel.frame = CGRectMake(numLabelX, numLabelY, numLabelW, numLabelH);}@end
//  Model//  SLFriend.h//  1108-QQ分组////  Created by 修修 on 15/11/8.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import <Foundation/Foundation.h>@interface SLFriend : NSObject/** *  好友头像 */@property (nonatomic, copy) NSString *icon;/** *  个性签名 */@property (nonatomic, copy) NSString *intro;/** *  昵称 */@property (nonatomic, copy) NSString *name;/** *  是否会员 */@property (nonatomic, assign) BOOL vip;- (instancetype)initWithDict:(NSDictionary *)dict;+ (instancetype)friendWithDict:(NSDictionary *)dict;@end////  SLFriend.m//  1108-QQ分组////  Created by 修修 on 15/11/8.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import "SLFriend.h"@implementation SLFriend- (instancetype)initWithDict:(NSDictionary *)dict{    if (self = [super init]) {        [self setValuesForKeysWithDictionary:dict];    }    return self;}+ (instancetype)friendWithDict:(NSDictionary *)dict{    return [[self alloc] initWithDict:dict];}@end////  SLGruop.h//  1108-QQ分组////  Created by 修修 on 15/11/8.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import <Foundation/Foundation.h>@class SLFriend;@interface SLGroup : NSObject/** *  分组名 */@property (nonatomic, copy) NSString *name;/** *  分组里的好友数组 */@property (nonatomic, strong) NSArray *friends;/** *  在线人数 */@property (nonatomic, assign) int online;/** *  分组是否打开 */@property (nonatomic, assign, getter=isOpen) BOOL open;- (instancetype)initWithDict:(NSDictionary *)dict;+ (instancetype)groupWithDict:(NSDictionary *)dict;@end////  SLGruop.m//  1108-QQ分组////  Created by 修修 on 15/11/8.//  Copyright © 2015年 cn.Xsoft. All rights reserved.//#import "SLGroup.h"#import "SLFriend.h"@implementation SLGroup- (instancetype)initWithDict:(NSDictionary *)dict{    if (self = [super init]) {        // 先将数据初始化        [self setValuesForKeysWithDictionary:dict];        // 在处理分组里的好友,从字典转到模型        NSMutableArray *tempMary = [NSMutableArray array];        for (NSDictionary *dict in self.friends) {            SLFriend *friendData = [SLFriend friendWithDict:dict];            [tempMary addObject:friendData];        }        self.friends = tempMary;    }    return self;}+ (instancetype)groupWithDict:(NSDictionary *)dict{    return [[self alloc] initWithDict:dict];}@end


0 0
原创粉丝点击