iOS开发小白学习体验-5

iOS开发小白学习体验-5

标签(空格分隔): iOS开发小白学习体验


UITableView学习

UITableView这个控件,我管它叫做列表控件(接下来说的列表控件就是UItableView)。因为它就想是一个表格,条理清晰,把所需要的信息都一行一行排列好显示出来。
想使用列表控件需要实现两个代理,一个是UITableViewDelegate,另一个是UITableViewDataSource。

  • UITableViewDataSource的代理实现的是数据源的操作。
  • UITableViewDelegate的代理实现的是列表的属性(列表的行高,头高等等)
    说明:
    *在程序中挂了代理之后,有两个必须实现的代理方法
/** 必须实现的代理方法1
 *  设置列表视图每一组的行数  
 */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 1;
}

/** 必须实现的代理方法2
 *  设置每一行里面具体的内容,返回一个cell
 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    tg *t = self.date[indexPath.section];
    static NSString *ID = @"Cell";
    TGCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell==nil) {
        cell = [[[NSBundle mainBundle] loadNibNamed:@"TGCell" owner:nil options:nil] lastObject];
    }
    cell.titleLabel.text = t.title;
    cell.priceLabel.text = [NSString stringWithFormat:@"¥%@",t.price];
    cell.buyCountLabel.text = [NSString stringWithFormat:@"购买人数:%@",t.buyCount];
    cell.iconView.image = [UIImage imageNamed:t.icon];
    return cell;
}
  • 可选代理
    一些可选择实现的代理方法,作用是为了让列表视图看起来更生动
/** 设置分组数 */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSLog(@"分组数为:%ld",_contacts.count);
    return _contacts.count;
}

/** 返回每组的标题 */
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    NSLog(@"生成组(组%li)名称",section);
    LYHSetGroup *group = _contacts[section];
    return group.groupName;
}

/** 返回每组尾部的说明 */
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
    NSLog(@"生成尾部(组%li)名称",section);
    LYHSetGroup *group = _contacts[section];
    return group.discription;
}

/** 返回每组标题的索引 */
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    NSLog(@"生成组索引");
    NSMutableArray *indexs = [NSMutableArray array];
    for (LYHSetGroup *group in _contacts) {
        [indexs addObject:group.groupName];
    }
    return indexs;
}

/** 设置分组标题内容的高度 */
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return 50;
    }
    return 40;
}

/** 设置每行高度(每行高度可以不一样) */
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 45;
}

/** 设置尾部说明内容高度 */
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return 40;
}

/** 点击行的代理方法 */
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    _selectedIndexPath = indexPath;
    LYHSetGroup *group = _contacts[indexPath.section];
    LYHSetPerson *person = group.contacts[indexPath.row];
    // 创建弹出窗口
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"修改号码" message:[person getName] delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    // 设置窗口内容样式
    alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    // 取得文本
    UITextField *textFileld = [alert textFieldAtIndex:0];
    // 设置文本框内容
    textFileld.text = person.phoneNum;
    // 显示窗口
    [alert show];
}

/** 窗口的代理方法,用户保存数据 */
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    // 当点击了第二个按钮(OK)
    if (buttonIndex == 1) {
        UITextField *textField = [alertView textFieldAtIndex:0];
        // 修改模型数据
        LYHSetGroup *group = _contacts[_selectedIndexPath.section];
        LYHSetPerson *person = group.contacts[_selectedIndexPath.row];
        person.phoneNum = textField.text;
        // 刷新表格
//        [self.myTableView reloadData]; 这样的方法会修改数据源里面的内容不可取
        // 需要局部刷新的单元格的组、行
        NSArray *indexPaths = @[_selectedIndexPath];
        [self.myTableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];
    }
}

/** 重写状态样式方法 */
- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}
  • 注意点:

    在创建cell的时候一般使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)

    • UITableViewCellStyle是一个枚举类型
    • reuseIdentifier传入的是一个缓存池的名字
      列表视图有一个属性叫做indexPath
    • indexPath有两个属性一个是section,一个是row
#pragma mark - 下面这个是摘自UITableView的头文件

@interface NSIndexPath (UITableView)
+ (NSIndexPath *)indexPathForRow:(NSInteger)row inSection:(NSInteger)section;
/** 存的是组数 */
@property(nonatomic,readonly) NSInteger section;
/** 存的是每组的行数 */
@property(nonatomic,readonly) NSInteger row;
@end

#pragma mark - UITableViewCellStyle 枚举类型,判断cell的类型

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    /** 左侧显示textLabel(不显示detailTextLabel),imageView可选(显示在最左边) */
    UITableViewCellStyleDefault,    
    /** 左侧显示textLabel、右侧显示detailTextLabel(默认蓝色),imageView可选(显示在最左边) */
    UITableViewCellStyleValue1, 
    /** 左侧依次显示textLabel(默认蓝色)和detailTextLabel,imageView可选(显示在最左边) */
    UITableViewCellStyleValue2, 
    /** 左上方显示textLabel,左下方显示detailTextLabel(默认灰色),imageView可选(显示在最左边) */
    UITableViewCellStyleSubtitle    
};  

#pragma mark - UITableViewCellAccessoryType 枚举类型,判断cell右边指示的类型
typedef NS_ENUM(NSInteger, UITableViewCellAccessoryType) {
    /** 不显示任何图标 */
    UITableViewCellAccessoryNone,
    /** 跳转指示图标 */
    UITableViewCellAccessoryDisclosureIndicator, 
    /** 内容详情图标和跳转指示图标 */
    UITableViewCellAccessoryDetailDisclosureButton,
    /** 勾选图标 */
    UITableViewCellAccessoryCheckmark,  
    /** 内容详情图标 */
    UITableViewCellAccessoryDetailButton NS_ENUM_AVAILABLE_IOS(7_0) 
};
  • 注意点
    性能优化:
    为了提高性能,tableview有一个缓存机制:在实现cell内容的代理方法中首先判断,缓存池有没有这个cell:如果有那就从缓存池取出来,如果没有那就重新创建一个。
    // 由于此方法调用比较频繁,cell的标志声明成静态常量有利于性能优化
    static NSString *cellIdentifier = @"UITableViewCellIdentifierKey1";
    static NSString *cellIdentifierForFirstRow = @"UITableViewCellIdentifierKeyWithSwitch";
    cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierForFirstRow];
    if(!cell){
        if (indexPath.row == 0) {

            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierForFirstRow];
            UISwitch *sw = [[UISwitch alloc]init];
            [sw addTarget:self  action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged];
            cell.accessoryView = sw;
        }else{
            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
            cell.accessoryType = UITableViewCellAccessoryDetailButton;
        }
    }

自定义cell

在正常的开发中,系统自带的UITableViewCell往往不能满足开发的需求,这就需要自定义cell,自定义cell有三种方式:
1.xib
2.纯代码
3.storyboard

  • xib实现
    xib
    1->创建一个xib文件,在xib文件创建cell样式
    2->创建一个与xib名字一样的模型类,将控件拖拽进去
    3->在viewController中加载xib的模型类,在代理方法中,给xib模型类对象赋值
#pragma mark - 自定义cell
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
    static NSString *ID = @"Cell";
    TGCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell==nil) {
        // 从xib中加载视图用到的方法
        cell = [[[NSBundle mainBundle] loadNibNamed:@"TGCell" owner:nil options:nil] lastObject];
    }
    return cell;
}
/** 通过setter方法在给视图赋值的时候就直接绑定值 */
- (void)setT:(tg *)t
{
    // setter方法中,第一句要赋值,否则在其他方法中无法访问到
    _t = t;
    self.titleLabel.text = t.title;
    self.priceLabel.text = [NSString stringWithFormat:@"¥%@",t.price];
    self.buyCountLabel.text = [NSString stringWithFormat:@"购买人数:%@",t.buyCount];
    self.iconView.image = [UIImage imageNamed:t.icon];
}

#pragma mark - 模板提供的方法
/** 
 *  初始化方法,使用代码创建cell的时候会被调用
 *  如果使用XIB或者stroyboard不会被调用
 */
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {

    }
    return self;
}
/** 
 *  从XIB被加载之后,会自动被调用
 *  如果使用纯代码,不会被执行
 */
- (void)awakeFromNib {
    // Initialization code
}
/**
 *  cell被选中或者取消选中时调用    
 */
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

#pragma mark - 控制器
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 创建cell
    TGCell *cell = [TGCell cellWithTableView:tableView];
    // 通过数据模型,设置cell内容,可以让视图控制器不需要了解cell内部的实现细节
    cell.t = self.date[indexPath.row];

    return cell;
}
这是我们自定义Cell这个例子的核心,自定义Cell分为两个步骤:首先要进行各种控件的初始化工作,这个过程中只要将控件放到Cell的View中同时设置控件显示内容的格式(字体大小、颜色等)即可;然后在数据对象设置方法中进行各个控件的布局(大小、位置)。在代码中有几点需要重点提示大家:
  • 对于单行文本数据的显示调用- (CGSize)sizeWithAttributes:(NSDictionary *)attrs;方法来得到文本宽度和高度。
  • 对于多行文本数据的显示调用- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary )attributes context:(NSStringDrawingContext )context ;方法来得到文本宽度和高度;同时注意在此之前需要设置文本控件的numberOfLines属性为0。
  • 通常我们会在自定义Cell中设置一个高度属性,用于外界方法调用,因为Cell内部设置Cell的高度是没有用的,UITableViewCell在初始化时会重新设置高度。

  • 纯代码实现

    纯代码
    建立数据模型类(M)
    控制器用懒加载的方式把值都取出来(C)
    自定义cell类,留一个属性接收数据(V),在cell类里面实现数据与视图的结合

数据模型类:

#import <Foundation/Foundation.h>

@interface KCStatus : NSObject

#pragma mark - 属性
@property (nonatomic,assign) long long Id;//微博id
@property (nonatomic,copy) NSString *profileImageUrl;//头像
@property (nonatomic,copy) NSString *userName;//发送用户
@property (nonatomic,copy) NSString *mbtype;//会员类型
@property (nonatomic,copy) NSString *createdAt;//创建时间
@property (nonatomic,copy) NSString *source;//设备来源
@property (nonatomic,copy) NSString *text;//微博内容



#pragma mark - 方法
#pragma mark 根据字典初始化微博对象
-(KCStatus *)initWithDictionary:(NSDictionary *)dic;

#pragma mark 初始化微博对象(静态方法)
+(KCStatus *)statusWithDictionary:(NSDictionary *)dic;
@end

#import "KCStatus.h"

@implementation KCStatus

#pragma mark 根据字典初始化微博对象
-(KCStatus *)initWithDictionary:(NSDictionary *)dic{
    if(self=[super init]){
        self.Id=[dic[@"Id"] longLongValue];
        self.profileImageUrl=dic[@"profileImageUrl"];
        self.userName=dic[@"userName"];
        self.mbtype=dic[@"mbtype"];
        self.createdAt=dic[@"createdAt"];
        self.source=dic[@"source"];
        self.text=dic[@"text"];
    }
    return self;
}

#pragma mark 初始化微博对象(静态方法)
+(KCStatus *)statusWithDictionary:(NSDictionary *)dic{
    KCStatus *status=[[KCStatus alloc]initWithDictionary:dic];
    return status;
}

-(NSString *)source{
    return [NSString stringWithFormat:@"来自 %@",_source];
}
@end

自定义cell

#import <UIKit/UIKit.h>
@class KCStatus;

@interface KCStatusTableViewCell : UITableViewCell

#pragma mark 微博对象
@property (nonatomic,strong) KCStatus *status;

#pragma mark 单元格高度
@property (assign,nonatomic) CGFloat height;

@end

#import "KCStatusTableViewCell.h"
#import "KCStatus.h"
#define KCColor(r,g,b) [UIColor colorWithHue:r/255.0 saturation:g/255.0 brightness:b/255.0 alpha:1] //颜色宏定义
#define kStatusTableViewCellControlSpacing 10 //控件间距
#define kStatusTableViewCellBackgroundColor KCColor(251,251,251)
#define kStatusGrayColor KCColor(50,50,50)
#define kStatusLightGrayColor KCColor(120,120,120)

#define kStatusTableViewCellAvatarWidth 40 //头像宽度
#define kStatusTableViewCellAvatarHeight kStatusTableViewCellAvatarWidth
#define kStatusTableViewCellUserNameFontSize 14
#define kStatusTableViewCellMbTypeWidth 13 //会员图标宽度
#define kStatusTableViewCellMbTypeHeight kStatusTableViewCellMbTypeWidth
#define kStatusTableViewCellCreateAtFontSize 12
#define kStatusTableViewCellSourceFontSize 12
#define kStatusTableViewCellTextFontSize 14


@interface KCStatusTableViewCell(){
    UIImageView *_avatar;//头像
    UIImageView *_mbType;//会员类型
    UILabel *_userName;
    UILabel *_createAt;
    UILabel *_source;
    UILabel *_text;
}

@end

@implementation KCStatusTableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self initSubView];
    }
    return self;
}

#pragma mark 初始化视图
-(void)initSubView{
    //头像控件
    _avatar=[[UIImageView alloc]init];
    [self.contentView addSubview:_avatar];
    //用户名
    _userName=[[UILabel alloc]init];
    _userName.textColor=kStatusGrayColor;
    _userName.font=[UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize];
    [self.contentView addSubview:_userName];
    //会员类型
    _mbType=[[UIImageView alloc]init];
    [self.contentView addSubview:_mbType];
    //日期
    _createAt=[[UILabel alloc]init];
    _createAt.textColor=kStatusLightGrayColor;
    _createAt.font=[UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize];
    [self.contentView addSubview:_createAt];
    //设备
    _source=[[UILabel alloc]init];
    _source.textColor=kStatusLightGrayColor;
    _source.font=[UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize];
    [self.contentView addSubview:_source];
    //内容
    _text=[[UILabel alloc]init];
    _text.textColor=kStatusGrayColor;
    _text.font=[UIFont systemFontOfSize:kStatusTableViewCellTextFontSize];
    _text.numberOfLines=0;
//    _text.lineBreakMode=NSLineBreakByWordWrapping;
    [self.contentView addSubview:_text];
}

#pragma mark 设置微博
-(void)setStatus:(KCStatus *)status{
    //设置头像大小和位置
    CGFloat avatarX=10,avatarY=10;
    CGRect avatarRect=CGRectMake(avatarX, avatarY, kStatusTableViewCellAvatarWidth, kStatusTableViewCellAvatarHeight);
    _avatar.image=[UIImage imageNamed:status.profileImageUrl];
    _avatar.frame=avatarRect;


    //设置会员图标大小和位置
    CGFloat userNameX= CGRectGetMaxX(_avatar.frame)+kStatusTableViewCellControlSpacing ;
    CGFloat userNameY=avatarY;
    //根据文本内容取得文本占用空间大小
    CGSize userNameSize=[status.userName sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize]}];
    CGRect userNameRect=CGRectMake(userNameX, userNameY, userNameSize.width,userNameSize.height);
    _userName.text=status.userName;
    _userName.frame=userNameRect;


    //设置会员图标大小和位置
    CGFloat mbTypeX=CGRectGetMaxX(_userName.frame)+kStatusTableViewCellControlSpacing;
    CGFloat mbTypeY=avatarY;
    CGRect mbTypeRect=CGRectMake(mbTypeX, mbTypeY, kStatusTableViewCellMbTypeWidth, kStatusTableViewCellMbTypeHeight);
    _mbType.image=[UIImage imageNamed:status.mbtype];
    _mbType.frame=mbTypeRect;


    //设置发布日期大小和位置
    CGSize createAtSize=[status.createdAt sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize]}];
    CGFloat createAtX=userNameX;
    CGFloat createAtY=CGRectGetMaxY(_avatar.frame)-createAtSize.height;
    CGRect createAtRect=CGRectMake(createAtX, createAtY, createAtSize.width, createAtSize.height);
    _createAt.text=status.createdAt;
    _createAt.frame=createAtRect;


    //设置设备信息大小和位置
    CGSize sourceSize=[status.source sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize]}];
    CGFloat sourceX=CGRectGetMaxX(_createAt.frame)+kStatusTableViewCellControlSpacing;
    CGFloat sourceY=createAtY;
    CGRect sourceRect=CGRectMake(sourceX, sourceY, sourceSize.width,sourceSize.height);
    _source.text=status.source;
    _source.frame=sourceRect;


    //设置微博内容大小和位置
    CGFloat textX=avatarX;
    CGFloat textY=CGRectGetMaxY(_avatar.frame)+kStatusTableViewCellControlSpacing;
    CGFloat textWidth=self.frame.size.width-kStatusTableViewCellControlSpacing*2;
    CGSize textSize=[status.text boundingRectWithSize:CGSizeMake(textWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellTextFontSize]} context:nil].size;
    CGRect textRect=CGRectMake(textX, textY, textSize.width, textSize.height);
    _text.text=status.text;
    _text.frame=textRect;

    _height=CGRectGetMaxY(_text.frame)+kStatusTableViewCellControlSpacing;
}

#pragma mark 重写选择事件,取消选中
-(void)setSelected:(BOOL)selected animated:(BOOL)animated{

}
@end

导航tips:

// 修改导航栏的背景颜色
self.rootNV.navigationBar.barTintColor = [UIColor colorWithRed:155.0/255.0 green:155.0/255.0 blue:155.0/255.0 alpha:1.0f];
// 修改导航栏返回按钮的颜色
self.navigationController.navigationBar.tintColor = [UIColor greenColor];
// 设置导航栏返回按钮的文字
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"返回" style:UIBarButtonItemStyleDone target:self action:nil];
// 自定义navigationbar需要把原来的隐藏,然后覆盖一个navigationbar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值