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++;
}
}
}
}