UIWindow
初始化:
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
self.window.backgroundColor = [UIColor whiteColor];
MyViewController *vc = [[MyViewController alloc]init];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
UIViewController
- (void)viewDidLoad;创建界面时自动执行,将构建界面的代码放在这个方法中即可
- (void)viewWillAppear:(BOOL)animated;界面即将显示前,方法自动执行
- (void)viewDidAppear:(BOOL)animated;界面显示完毕,方法自动执行
- (void)viewWillDisappear:(BOOL)animated;界面即将消失前,方法自动执行
- (void)viewDidDisappear:(BOOL)animated;界面已经消失,方法自动执行
- (void)removeFromSuperview;将某个控件移除
- (void)setNeedsLayout;界面信息发生改变后重新载入
UILabel标签
属性:
frame
—>坐标大小
text
—>文本内容
textAlignment
—>字体对齐方式
textColor
—>字体颜色
font [UIFont systemFontOfSize:40]
—>字体大小
numberOfLines
—>文本的行数,默认为1,设置为0时,行数可以任意
backgroundColor
—>背景色
font
—>字体
lineBreakMode
—>省略内容的方式
//1创建标签的实例
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(50, 50, 100, 100)];
//2设置标签的属性
label.text = @"This is a looooooooooooooooooog word";
label.backgroundColor = [UIColor lightGrayColor];
label.numberOfLines = 0;
label.font = [UIFont systemFontOfSize:22];
//设置换行后切断的字符...的位置
label.lineBreakMode = NSLineBreakByTruncatingHead;
//修改文字的颜色
label.textColor = [UIColor redColor];
//3将标签添加到视图中
[self.view addSubview:label];
UIButton按钮
selected
—>是否被选中
//1 创建Button
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
//2 设置按钮的属性
button.frame = CGRectMake(50, 50, 200, 100);
button.backgroundColor = [UIColor lightGrayColor];
//设置按钮在正常情况下的显示标题
[button setTitle:@"OK" forState:UIControlStateNormal];
//设置按钮在高亮状态下显示的标题
[button setTitle:@"KO" forState:UIControlStateHighlighted];
//设置按钮在正常状态下的背景图
//[button setBackgroundImage:[UIImage imageNamed:@"playing_btn_pause_h@2x.png"] forState:UIControlStateNormal];
//设置按钮在正常状态下的图片
[button setImage:[UIImage imageNamed:@"playing_btn_play_h@2x.png"] forState:UIControlStateNormal];
//设置按钮文字的对齐
[button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
//为按钮添加事件的响应
//参数1 点击按钮后触发的对象 参数2 触发的对象使用的方法 参数3 什么事件发生
[button addTarget:self action:@selector(aaa:) forControlEvents:UIControlEventTouchUpInside];
//3 将按钮添加到视图中
[self.view addSubview:button];
UIStepper步进控件
核心属性
value(为Double型,与label联用时需要用[NSString stringWithFormat:@"%.0f",self.stepper.value];进行转换)
重要事件:
valueChanged
第四检查器中 behavior中autorepeat勾上可以按住按钮持续增减
第四检查器中 behavior中continuous取消勾上,数值持续增减过程不显示
第四检查器中 behavior中wrap勾上,到边界数值之后会切换到另一个边界数值
//当stepper的数值被改变时将新的值显示到标签上
- (IBAction)stepper:(id)sender {
self.label.text = [NSString stringWithFormat:@"%.0f",self.stepper.value];
}
- (void)viewDidLoad {
[super viewDidLoad];
//设置初始化设置
self.stepper.maximumValue = 50;
self.stepper.minimumValue = -50;
self.stepper.value = 10;
self.stepper.stepValue = 5;
//显示
self.label.text = [NSString stringWithFormat:@"%.0f",self.stepper.value];
}
UISlider滑块控件
核心属性:
value(为Double型,与label联用时需要用[NSString stringWithFormat:@"%.0f",self.stepper.value];进行转换)
重要事件:
valueChanged
- (void)setThumbImage:(nullable UIImage *)image forState:(UIControlState)state; 修改按钮颜色
UISwitch开关控件
核心属性:
on(BOOL)
重要事件:
valueChanged
设置通过带动画效果控制switch:[self.switchs setOn:!self.switchs.on animated:YES];
UITextField文本框控件
borderstyle
—>外边框类型
leftview
—>文本框内部左侧视图
leftViewMode
—>左视图默认不显示,需要修改
background
—>设置背景图片还需要配合BorderStyle无边框使用
clearbutton
—>清空文本框按钮
capitalization
—>Words首字母大写—>Senternces句子首字母大写—>All Characters所有字母大写
correction/autocorrectionType
—>自动纠错
spell checking
—>拼写检测
keyboard type
—>键盘类型—>phone pad 阿拉伯数字
appearance
—>键盘颜色
return key
—>设置return键显示的内容
auto-enable return key
—>防止未输入内容就按return键
secure text entry
—>设置密码模式
如何关闭键盘
关闭的方法之一:让文本框放弃第一响应者身份即可
成为第一响应者:becomeFirstResponder
放弃第一响应者:resignFirstResponder
遵守UITextViewDelegate
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
if ([text isEqualToString:@"\n"]) {
[textView resignFirstResponder];
return NO;
}
return YES;
}
遵守UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
关闭的方法之二:文本框所在的父视图结束编辑状态即可(结束编辑状态:系统会自动遍历父视图下的所有文本框并且将所有文本框都设置为放弃第一响应者身份)
结束父视图的编辑状态:[view endEditing:YES];// 用于-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event方法中
关闭键盘时机:
时机1:点击键盘右下角按钮——为文本框连线一个事件,且事件种类为Did End On Exit事件
时机2:点击界面的空白处——实现控制器的touchesBegan:withEvent方法,配合[view endEditing:YES];方法
[self.view endEditing:YES];
两个文本框设置点击键盘右下角切换:
第一个文本框连线Did End Exit事件,在里面将第二个文本框设置为第一响应者
UIAlertController 警告框及操作表
创建新的警告界面
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"登录" message:@"输入用户名和密码" preferredStyle:UIAlertControllerStyleAlert];
UIAlertControllerStyleAlert
—>参数生成一个中间框
UIAlertControllerStyleActionSheet
—>参数生成一个底部框
底部框不允许生成text输入框,只能使用按钮
创建文本框
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField){
textField.placeholder = @"name";
textField.textColor = [UIColor blueColor];
textField.clearButtonMode = UITextFieldViewModeUnlessEditing ;
textField.borderStyle = UITextBorderStyleRoundedRect;
}];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField){
textField.placeholder = @"password";
textField.textColor = [UIColor blueColor];
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.borderStyle = UITextBorderStyleRoundedRect;
//设置不可见模式
textField.secureTextEntry = YES;
}];
placeholder
—>是提示输入
textColor
—>文字颜色
clearButtonMode
—>清除按钮出现方式:
UITextFieldViewModeNever
—>从不出现
UITextFieldViewModeWhileEditing
—>输入过程中出现
UITextFieldViewModeUnlessEditing
—>输入完毕后出现
UITextFieldViewModeAlways
—>总是出现
borderStyle文本框内框架格式:
UITextBorderStyleNone
—>无任何格式
UITextBorderStyleLine
—>加边框底部粗
UITextBorderStyleBezel
—>四周加细边框
UITextBorderStyleRoundedRect
—>浅淡边框
创建新的按钮
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
NSArray *textfields = alert.textFields;
UITextField *namefield = textfields[0];
UITextField *passwordfield = textfields[1];
NSLog(@"%@:%@",namefield.text, passwordfield.text);
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"Calcel" style:UIAlertActionStyleCancel handler:nil]];
//推出显示 参数1:要显示的控制器 参数2:是否使用动画 参数3:推出结束后执行的行动
[self presentViewController:alert animated:YES completion:nil];
UIAlertActionStyleDefault
—>参数生成一个默认的按钮格式,设置为此模式时在底部框模式中会自动合并附近按钮
UIAlertActionStyleCancel
—>参数生成一个退出按钮,在中间框模式中默认会在最左边生成,设置为此模式时会在底部框模式中独立分开
UIAlertActionStyleDestructive
—>参数生成一个有可能改变或数据,设置为此模式时在底部框模式中会自动合并附近按钮
通过block方式获得文本框中输入的内容,输入的内容会被放在系统生成的textFields数组中,使用一个数组来接收其数据,第一个文本框中的内容会放在数组[0]中,使用UITextField类型接收,以此类推,使用时通过接收名.text调用其内容
lazy loading懒加载(重写getter方法实现晚加载)
-(NSArray *)allStudent{
if (!_allStudent) {
_allStudent = [NSArray alloc];
}
return _allStudent;
}
多界面切换
方式一 present-dismiss方式推出返回
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion NS_AVAILABLE_IOS(5_0);
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^ __nullable)(void))completion NS_AVAILABLE_IOS(5_0);
方式二 使用UINavigationController
//1 创建bvc的实例
BViewController * bvc = [[BViewController alloc]initWithNibName:@"BViewController" bundle:nil];
//2 由正在管理着avc的那个导航来负责推出bvc
[self.navigationController pushViewController:bvc animated:YES];
//返回
[self.navigationController popViewControllerAnimated:YES];
多VC之间的传值
正向传值
step1:为B公开一个属性,用于接收要传入的数值
//通过bvc这个引用,给要推出的控制器公开的那个属性赋值
bvc.msg = self.textField.text ;
step2:A创建完B的实例之后,在推出B之前,为B公开这个属性赋值
step3:在B中,选择合适的时机,显示传入的数据
//显示接收的信息
self.label.text = self.msg;
反向传值(回调、回传)
方法一:
直接在B中添加了AViewController类型的属性,然后B在dismiss之前给AViewController发消息
准备:
1 AViewController为了接收回传的值,公开一个属性
2 BViewController为了存储推出它的那个avc,公开一个属性,类型为AviewController。
步骤:
step1:avc在推出B之前,将自己的引用赋给B公开的backReference属性。
step2:B在dismiss之前,通过存储的backReference引用A,返回的控制器空开的backString的赋值。
step3:在avc中,在viewWillAppear中完成返回的文本显示。
方法二:
直接在B中添加了id<xxxDelegate>类型的属性,然后B在dismiss之前给delegate发消息,方法名就是在协议中定义的指定的方法。
此种通过定义协议,规范另一个对象中的方法,并且给这个对象发消息的这种模式叫做代理模式,作用就是完成两个对象,一个给另一个主动发消息的过程。
主动方(委托方,发送消息者)
1> 定义协议
2> 增加delegate属性
3> 合适的时机给代理方发消息
//定义一个登陆的协议
@protocol UMLoginProtocol <NSObject>
- (void)loginSuccess;
- (void)loginFaild;
- (void)loginNetError;
@end
//代理属性***注意weak,防止循环引用***
@property (nonatomic, weak) id<UMLoginProtocol>delegate;
合适的时候使用 [self loginSuccess];等方法
被动方(代理方,接收消息者)
1> 遵守协议
2> 实现方法
3> 将自己设置为代理方
@interface UMLoginViewController ()<UMLoginProtocol>
实现loginSuccess等方法
//设置自己为代理
[UMXmppTool sharedUMXmppTool].delegate = self;
UINavigationController导航控制器
配置导航栏(NavigationBar)
高度:
—>算上状态栏(StatusBar 本来20个点)一共64个点
设置StatusBar颜色
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
内容:
—>通过navigationItem属性完成配置
左
—>leftBarButtonItem/s
中
—>title/titleView
右
—>rightBarButtonItem/s
topViewController
->附带的view
左和右都是类似于可点击的按钮,是UIBarButtonItem类型
取消系统默认的蓝色渲染
UIImage * leftImage = [[UIImage imageNamed:@"icon29.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
导航栏背景色
self.navigationController.navigationBar.barTintColor = [UIColor blackColor];
导航栏风格改为深色系
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
左右按钮的渲染色
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
配置工具栏(ToolBar)
位于导航控制器的底部
默认隐藏,通过设置 self.navigationController.toolbarHidden = NO;即可显示
toolBar中可包含的就是UIBarButtonItem类型的可点击的按钮,通过控制器的toolBarItems属性设置工具条中包含的按钮
高度:44个点
创建固定的填充按钮
UIBarButtonItem * fixItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
修改固定按钮长度
fixItem.width = 30;
创建可变的填充按钮
UIBarButtonItem * flexibleItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
使用可填充按钮
self.toolbarItems = @[fixItem,rewindItem,flexibleItem,playItem,flexibleItem,fastItem,fixItem];
设置在推出界面时隐藏底部各种
Bar vc.hidesBottomBarWhenPushed = YES;
常用设置的作用于范围
与内容有关的:只在当前vc中生效
navigationItem的左中右
toolbarItems
与控制器bar的显示隐藏有关的:在多个vc中都有效
navigationController.navigationBarHidden
navigationController.toolbarHidden
多导航控制器之间的切换
在A中推出B的时候,B创建导航控制器,然后A推出B的导航控制器
BViewController * bvc = [[BViewController alloc]init];
//推出BViewController,但BViewController也得有它的导航
UINavigationController * navi = [[UINavigationController alloc]initWithRootViewController:bvc];
//推出navi
[self.navigationController presentViewController:navi animated:YES completion:nil]
UIImageView图片视图
image
—>(类型UIImage)图片
contentMode
—>显示模式/居中/左/右
userInteractionEnabled
—>用户交互属性
NSData * __nullable UIImagePNGRepresentation(UIImage * __nonnull image);
—>将UIImage转换成NSData用于上传等
UIScrollView 滚动视图
核心属性:
frame:
—>视图的可见区间的大小
contentSize:
—>设置内容的大小
contentOffset:
—>记录可见区域的左顶点在全部内容区域中离内容左顶点的偏移量
contentInset:
—>设置内边距
bounces:
—>到达边界是否回弹
pagingEnabled:
—>一次滚动一个屏幕
automaticallyAdjustsScrollViewInsets:
—>关闭因为导航栏下移的64个点
//创建一张尺寸较大的图片视图
//使用initWithImage方法在创建iv的同时就指定图片的话,则不设置frame,那么图片有多大iv就有多大
UIImageView * iv = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"32.jpg"]];
//创建滚动视图
UIScrollView * sv = [[UIScrollView alloc]init];
//sv.frame = CGRectMake(50, 100, 250, 400);
//设置等屏幕大小
sv.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
//设置边的内边距(可以用于键盘弹出的时候用于缩起内容)
//sv.contentInset = UIEdgeInsetsMake(-64, 0, 0, 0);
//当使用滚动视图并搭配导航控制器时,系统为了防止延伸到导航栏下方的滚动视图在开始时,被遮盖上,所以系统检测到有导航时,就会把滚动视图的内容向下错64个点,有时不想使用该功能的话,则有两种方法取消掉该效果
//方法一:关闭控制器的该功能,不让控制器自动调整滚动视图的内边距
self.automaticallyAdjustsScrollViewInsets = NO;
//方法二:我们自己修改滚动视图的内边距,向上把那64个点移回去
//设置滚动边界
sv.contentSize = iv.frame.size;
[sv addSubview:iv];
//添加滚动视图到控制器上
[self.view addSubview:sv];
控制器响应滚动视图与用户的交互
step1:设置滚动视图的代理为当前控制器
step2:让控制器遵守UIScrollViewDelegate协议
step3:根据需求实现协议中的方法,用于响应滚动视图与用户的交互
UIPageControl页数的提醒(小圆点)
核心属性:
frame:
—>坐标大小
numberOfPages:
—>圆点的个数
currentPage:
—>当前被选中的是第几个圆点(下表从0开始算起)
pageIndicatorTintColor:
—>圆点的颜色
currentPageIndicatorTintColor:
—>被选中的圆点的颜色
userInterAction:
—>是否与用户交互
UIPageControl * pc = [[UIPageControl alloc]init];
self.pc = pc;
pc.frame = CGRectMake(0, self.view.bounds.size.height -60, self.view.bounds.size.width, 40);
pc.numberOfPages = self.welcomeName.count;
pc.pageIndicatorTintColor = [UIColor whiteColor];
pc.currentPageIndicatorTintColor = [UIColor blueColor];
pc.userInteractionEnabled = NO;
[self.view addSubview:pc];
#pragma mark - UIScrollViewDelegate协议
-(void) scrollViewDidScroll:(UIScrollView *)scrollView{
CGPoint offset = scrollView.contentOffset;
self.pc.currentPage = round(offset.x/scrollView.bounds.size.width);
}
UITableView表视图
表格的样式
行之间没有间距,普通样式Plain样式
可以将行分组(区),分组样式Group样式
heightForRowAtIndexPath
—>设置行高
separator
—>下划线
selection
—>选中阴影
表格的组成
tableView
+tableHeaderView
+section分区
+sectionHeader分区头
+UITableViewCell(单元格/行)
+sectionFooter分区尾
+tableFooterView
如何使用UITableView
-
创建实例
-
设置frame
UITableView * tableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
-
添加到控制器的view中
[self.view addSubview:tableView];
- 设置表视图的数据源代理(dataSource)
tableView.dataSource = self;tc
- 设置表视图的delegate代理
tableView.delegate = self;
- 当前控制器遵守UITableViewDataSource和UITableViewDelegate协议
- 三问一答
//1 有几个分区
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
//2 每个分区有几行(必答)
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 100;
}
//3 每行什么样(必答)
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell * cell = [[UITableViewCell alloc]init];
cell.textLabel.text = @"HelloWorld";
return cell;
}
//一答:点击某行后如何响应
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
}
通过Cell内的按钮点击等获得Cell的indexPath
- (IBAction)cellHeadImageButtonClick:(UIButton *)sender {
UIResponder *responder = sender;
long indexPath = 0;
while ((responder = [responder nextResponder])){
if ([responder isKindOfClass: [UITableViewCell class]]) {
indexPath = [self.tableView indexPathForCell:(UITableViewCell *)responder].row;
}
}
}
通过Cell内手势获得对应的Cell的indexPath
- (void)imLongPress:(NSNotification *)noti {
[self.msgTextField resignFirstResponder];
UIGestureRecognizer * gr = noti.userInfo[@"gr"];
CGPoint tmpPointTouch = [gr locationInView:self.tableView];
if (gr.state == UIGestureRecognizerStateBegan) {
//获取行数
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:tmpPointTouch];
if (indexPath == nil) {
NSLog(@"not tableView");
}else{
NSInteger focusRow = [indexPath row];
NSLog(@"%ld",(long)focusRow);
}
}
单元格重用
方法一:先取,没有,自己新建
//先尝试着从tableView中取,看有没有回收了的cell
static NSString * identifier = @"MyCell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell"];
//如果没有取到可重用的单元格,则新建
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MyCell"];
}
方法二:先取,没有,系统新建
step1:在viewDidLoad中,使用tableView的registerClass方法,提前注册系统帮我们创建的类型是什么样。
spet2:在回答第三问时,使用带有两个参数的dequeueReusableCell即可
注意:写完dequeue之后,再也不用判断了,一定能返回一个cell实例,因为就算取不到可重用,系统在dequeue方法中,会帮我们自动创建。
在单元格内添加了控件,重用表格内容可能会覆盖原有内容,在使用之前应该先进行判断
UILabel * label = [cell.contentView viewWithTag:1];
if (label == nil) {
label =[[UILabel alloc]init];
label.frame = CGRectMake(0, 0, cell.bounds.size.width, cell.bounds.size.height);
label.font = [UIFont italicSystemFontOfSize:35];
label.textColor = [UIColor redColor];
label.textAlignment = NSTextAlignmentCenter;
//为lebel添加一个tag值,做标记
label.tag = 1;
[cell.contentView addSubview:label];
}
UITableViewCell的组成
contentView内容视图
1>系统版
四种样式:
Default:imageView+textLabel (基本)
Value1:详情在右侧(右对齐)
Value2:textLabel+detailTextLabel(左对齐)
SubTitle:详情在下
2>自定义
step1:创建显示内容的控件实例
step2:将这些控件以子视图的形式,添加到cell.contentView中即可
accessoryView辅助视图
1>系统版
通过cell的accessoryType属性设置
四种类型:
checkmark:
->勾号
disclosureIndicator:
->大于号
detailButton:
->圆圈i
detailDisclosureButton:
->圆圈i+大于号
//有圆圈i时,点击i以外的响应
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
//有圆圈i时,点击i时的响应
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
2>自定义
step1:创建控件实例
step2:将实例赋值给cell.accessoryView即可
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if (indexPath.row == 1) {
UISwitch * mySwitch = [[UISwitch alloc]init];
mySwitch.on = self.myChoose;
[mySwitch addTarget:self action:@selector(clickSwitch:) forControlEvents:UIControlEventValueChanged];
cell.accessoryView = mySwitch;
}
else{
//清除非第二行的复用窗口
cell.accessoryView = nil;
}
注意:contentView由系统创建实例,我们直接拿来使用,添加子视图即可,但accessoryView系统没有创建实例,只能先创建好UIView或其之类的实例,然后赋给该属性。
分区头的特殊效果:
step1:tableView的style时plain样式
step2:实现titleForheaderInSection方法设置分区头
产生效果:分区头不会滚动出超出屏幕,会悬停在屏幕的顶部,
表格的刷新
方式一:全部刷新reloadData
[self.tableView reloadData];
方式二:只更新某一个部分,insertRowsAtIndexPath
NSIndexPath * newIndexPath = [NSIndexPath indexPathForRow:self.allCitys.count-1 inSection:0];
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
表格行高设置
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section == 0) {
return 100;
}
else{
return 44;
}
}
表头表尾高度设置
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 10;
}
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
return 10;
}
自定义单元格
方式一:
在回答第三问时,自己创建显示内容的控件,添加到contentView中,相当于单元格的设计工作是在第三问中完成的。
弊端:
1》给子视图加tag标记,然后重用时判断
2》如果一旦cell需要改变结构,那么就需要修改第三问的代码
方式二:
step1:编写一个类,继承自UITableViewCell
step2:通过设计该类,将单元格的样式重新进行设置
step3:回答第三问时,创建自定义的cell类的实例即可
表格的编辑模式
使得表格进入编辑模式(出现编辑的按钮):设置tableView的editing属性为YES,就会开启编辑模式
1》删除和增加功能——两问一答
问1:当前行是否可以编辑
问2:当前行的编辑样式时红色删除还是绿色添加
答1:点击了编辑按钮后,如何响应
#pragma mark - 表格的编辑功能
//问1:当前行是否可以编辑
//此方法默认返回YES;
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row == 0) {
return NO;
}
else{
return YES;
}
}
//问2:当前行是什么编辑样式
//此方法默认为UITableViewCellEditingStyleDelete
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row == (self.allCitys.count-1)) {
return UITableViewCellEditingStyleInsert;
}
else{
return UITableViewCellEditingStyleDelete;
}
}
//答1:提交编辑动作后,如何响应
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if (editingStyle == UITableViewCellEditingStyleDelete) {
//删除动作
//1 先改数据模型
[self.allCitys removeObjectAtIndex:indexPath.row];
//2 再刷新表格
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
else{
//增加动作
City * newCity = [[City alloc]init];
newCity.name = @"Test";
newCity.population = 1000;
//先改模型
[self.allCitys addObject:newCity];
//再刷新
NSIndexPath * newIndexPath = [NSIndexPath indexPathForRow:self.allCitys.count-1 inSection:0];
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic ];
}
}
2》行的移动功能——一问一答
问1:当前行是否可以移动
答1:真得移动后,如何响应
#pragma mark - 移动行
//问1:该行是否可以移动
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath{
return YES;
}
//答1:移动后做什么
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
//按照旧的位置找到模型,找到模型
City * city = self.allCitys[sourceIndexPath.row];
//在数组中移除该元素
[self.allCitys removeObjectAtIndex:sourceIndexPath.row];
//按照新的位置插入回数组
[self.allCitys insertObject:city atIndex:destinationIndexPath.row];
}
获得自定义cell中控件点击对应的indexPath
控件点击事件
- (IBAction)recordButtonClick:(UIButton *)sender {
NSIndexPath * indexPath = [self.tableView indexPathForCell:(UITableViewCell *)sender.superview];
}
手势点击
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//重用机制
static NSString * identifier = @"Cell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
//设置cell
UILongPressGestureRecognizer * longGr = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longP:)];
[cell addGestureRecognizer:longGr];
return cell;
}
- (void)longP:(UILongPressGestureRecognizer *)gr {
CGPoint tmpPointTouch = [gr locationInView:self.table];
if (gr.state == UIGestureRecognizerStateBegan) {
//获取行数
NSIndexPath *indexPath = [self.table indexPathForRowAtPoint:tmpPointTouch];
NSLog(@"%ld",(long)indexPath.row);
}
}
下拉刷新
步骤:
step1:创建UIRefreshControl的实例
step2:将实例赋给表视图控制器的refreshControl属性
step3:为RefreshControl控件添加valueChanged事件的监听
step4:检测到valueChanged事件后,判断是否正在刷新,则执行数据加载操作,等加载结束后,修改RefreshControl为结束刷新即可
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"MyCell"];
//1 创建UIRefreshControl控件实例
UIRefreshControl * rc = [[UIRefreshControl alloc]init];
//2 将控件赋给控制器的refreshControl属性
self.refreshControl = rc;
//3 添加valueChanged事件的监听
[rc addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];
}
-(void) refresh:(UIRefreshControl *)sender{
//判断控件是否处于转圈的状态
//如果处于状态,则说明用户有了下拉动作
//发网络请求,传输新的数据
//等传输结束后,设置刷新控件为结束刷新,停止旋转
if ([sender isRefreshing]) {
//发网络请求
//模拟网络请求3秒后,得到了“测试”数据
//在refreshOver方法中,将返回的“测试”数据保存到数据模型中,并更新界面
[self performSelector:@selector(refreshOver:) withObject:@"测试" afterDelay:3];
}
}
-(void)refreshOver:(NSString *)result{
//将数据保存到模型中
[self.allNames insertObject:result atIndex:0];
//更新界面
NSIndexPath * new = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:@[new] withRowAnimation:UITableViewRowAnimationTop];
//修改RefreshControl控件,停止旋转
[self.refreshControl endRefreshing];
}
UISearchController搜索框
遵循UISearchResultsUpdating,UISearchBarDelegate代理
//实现searchBarDelegate协议方法
-(void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope{
[self updateSearchResultsForSearchController:self.searchController];
}
//实现UISearchResultsupdating协议方法
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController{
//获得用户输入的搜索文本
NSString * searchText = searchController.searchBar.text;
//获取用户选择的类别
NSInteger * selectedButtonIndex = searchController.searchBar.selectedScopeButtonIndex;
//声明一个用于保存匹配比对后,数据一致的商品数组
NSMutableArray * resultArray = [NSMutableArray array];
//遍历所有商品,一次比对商品名种时候包含输入的文本及类别是否一致
for (Product * p in self.allProducts) {
NSRange range = [p.name rangeOfString:searchText];
//range.length 匹配上的长度
//range.location 匹配上的位置
//@"abcdef"——>@"def"
//length:3 location:3
if (range.length > 0 && p.type == selectedButtonIndex) {
//比对成功 记录到resultArray中
[resultArray addObject:p];
}
}
//将要显示的数据结果给showResultVC传过去
self.showResultVC.resultData = resultArray;
//更新表视图显示
[self.showResultVC.tableView reloadData];
}
UICollectionViewController
创建
//创建布局属性
UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init];
//水平布局
layout.scrollDirection=UICollectionViewScrollDirectionHorizontal;
//设置每个表情按钮的大小为30*30
layout.itemSize=CGSizeMake(30, 30);
//计算每个分区的左右边距
float xOffset = (SCREENWIDTH-7*30)/8;
//设置分区的内容偏移
layout.sectionInset=UIEdgeInsetsMake(10, xOffset, 10, xOffset);
//设置行列间距
layout.minimumLineSpacing = (SCREENWIDTH - 7*30)/8;
layout.minimumInteritemSpacing=5;
UICollectionView * collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 160) collectionViewLayout:layout];
//打开分页效果
collectionView.pagingEnabled = YES;
//设置代理属性
collectionView.delegate= self;
collectionView.dataSource=self;
//注册Cell
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"biaoqing"];
代理方法
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return (self.dataArray.count/28)+(self.dataArray.count%28==0?0:1);
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 28;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"biaoqing" forIndexPath:indexPath];
for (int i=(int)cell.contentView.subviews.count; i>0; i--) {
[cell.contentView.subviews[i-1] removeFromSuperview];
}
UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 30, 30)];
label.font = [UIFont systemFontOfSize:25];
if (indexPath.row+indexPath.section*28 < self.dataArray.count) {
label.text =self.dataArray[indexPath.row+indexPath.section*28] ;
} else {
label.text = @"";
}
[cell.contentView addSubview:label];
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row+indexPath.section*28 < self.dataArray.count) {
NSString * str = self.dataArray[indexPath.section*28+indexPath.row];
}
}
UITableBarController
创建
AViewController * avc = [[AViewController alloc]init];
avc.tabBarItem.title = @"AVC";
UINavigationController * navi1 = [[UINavigationController alloc]initWithRootViewController:avc];
BViewController * bvc = [[BViewController alloc]init];
bvc.tabBarItem.title = @"BVC";
UINavigationController * navi2 = [[UINavigationController alloc]initWithRootViewController:bvc];
UITabBarController * tb = [[UITabBarController alloc]init];
//改变tabBar默认渲染颜色
tb.tabBar.tintColor = [UIColor blackColor];
// tb.viewControllers = @[navi1,navi2];
CViewController * cvc = [[CViewController alloc]init];
cvc.tabBarItem.title = @"CVC";
UINavigationController * navi3 = [[UINavigationController alloc]initWithRootViewController:cvc];
[tb addChildViewController:navi1];
[tb addChildViewController:navi2];
[tb addChildViewController:navi3];
tintColor
特点:不分视图种类,只分父子关系。
设置父视图的tintColor,于是在该父视图中得所有子视图只要没有单独设置过tintColor,则都将使用父视图的tintColor,但是有些视图会有自己特定的tintColor,如导航条自己特有的barTintColor。这种特有的属性是不受标准的tintColor影响。
self.view.tintColor = [UIColor blackColor];
UIAppearance
特点:不分父子关系,只分种类
只针对程序中的某一类型的控件做统一风格的设置,如:希望整个应用中的所有按钮背景图都是某一颜色。
使用:
调用指定类型的appearance方法,返回这种类型的对象实例,针对这个实例做样式设定,系统会自动将该样式复制给应用中所有与此对象一致的对象身上,在AppDelegate.m中设置按钮背景
[[UIButton appearance] setBackgroundImage:[UIImage imageNamed:@"delete_btn"] forState:UIControlStateNormal];
自定义导航栏和TabBar
自定义导航栏
思路:
将导航栏的外观设置记录到一个独立的类中,需要使用该设置的导航控制器与这个类绑定即可完成外观的变化,而无需在故事版中针对每个导航栏重复的做同样的设置
继承自UINavigationController,在initital的类方法中,通过appearance将导航栏的外观进行了设置
/*第一次使用这个类或者这个类的的子类的时候调用*/
+(void)initialize
{
//使用Appearance对导航栏统一外观设置
UINavigationBar *bar = [UINavigationBar appearance];
// 设置导航条的背景色
//[bar setBarTintColor:[UIColor redColor]];
//1.设置背景图
[bar setBackgroundImage:[UIImage imageNamed:@"navibg"] forBarMetrics:UIBarMetricsDefault];
//2.设置导航栏的样式(设置为black色系时,影响状态栏为白色字)
[bar setBarStyle:UIBarStyleBlack];
//3.设置左右按钮的渲染颜色
[bar setTintColor:[UIColor whiteColor]];
//4.设置导航栏中标题文字的竖直方向位置
//[bar setTitleVerticalPositionAdjustment:-20 forBarMetrics:UIBarMetricsDefault];
//5.设置导航栏中标题文字的样式
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
//添加文字颜色的设置
attributes[NSForegroundColorAttributeName] = [UIColor yellowColor];
attributes[NSFontAttributeName] = [UIFont systemFontOfSize:20];
[bar setTitleTextAttributes:attributes];
//6.设置返回按钮的箭头
[bar setBackIndicatorImage:[UIImage imageNamed:@"back_btn"]];
[bar setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"back_btn"]];
}
自定义TabBar
继承自UITabBarController,做一个类,继承自UITabBarButton,将视图的修改写在这个类中,再使用kvc的方法将自定义的TabBar对象替换掉UITabBarController中原有的tabbar。
思路:
step1:建立一个类,继承自UITabBarController,在tabBar的viewDidLoad中,将外观的设置完成
step2:建立一个类,继承自UITabBar
step3:在这个类的initWithFrame方法中,手动创建一个需要显示异型图片还能响应点击动作的按钮,并以子视图的形式添加到TabBar中
step4:重写layoutSubView方法,在此方法中,将TabBar原有的按钮和新增的异形按钮手动重新布局,调整他们的显示位置
step5:创建此自定义的TabBar的实例,使用KVC的方法将自定义的bar,替换掉原有TabBarController中的bar
step6:使用代理的方法时,为新添加的按钮添加点击后的响应动作
**
继承自UIView的子类,在创建实例时,系统会都自动调用
initwithFrame方法,就算是使用时调用的是init方法,
系统最后也是调用initWithFrame,只不过参数frame为0
**
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//创建一个UIButton的实例
UIButton *centerButton = [[UIButton alloc]init];
[centerButton setImage:[UIImage imageNamed:@"sports"] forState:UIControlStateNormal];
centerButton.frame = CGRectMake(0, 0, centerButton.currentImage.size.width, centerButton.currentImage.size.height);
//以子视图的形式添加到TabBar中
[self addSubview:centerButton];
self.centerButton = centerButton;
}
return self;
}
**
UIView类中定义的一个方法
当视图的frame发生变化时,系统会自动调用该方法
对于该视图内部的子视图如何布局,就写在
这个方法中
使用此方法时一定要调用super,先保证父类中原本做的
布局操作先实现,然后我们再写代码调整各个子视图的位置
**
- (void)layoutSubviews
{
[super layoutSubviews];
//1.设置中间按钮的位置
self.centerButton.center = CGPointMake(self.bounds.size.width*0.5, self.bounds.size.height*0.5-12);
//计算每个UITabBarButton的宽
CGFloat tabbarButtonW = self.bounds.size.width/5;
CGFloat buttonIndex = 0;
//2.设置系统根据子vc创建的4个UITabBarButton的位置
for (UIView *child in self.subviews) {
//根据字符串做类名,找到该类型的类型信息
Class class = NSClassFromString(@"UITabBarButton");
//判断当前遍历到的子视图是否是class类型
if ([child isKindOfClass:class]) {
//先拿出button原有的frame
CGRect frame = child.frame;
//改子视图的宽
frame.size.width = tabbarButtonW;
//改子视图的x
frame.origin.x = buttonIndex*tabbarButtonW;
//再把改完的frame赋会给button
child.frame = frame;
buttonIndex++;
if (buttonIndex==2) {
buttonIndex++;
}
}
}
}
网友评论