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