UI-2
目錄
- 多控制器處理
- 導(dǎo)航控制器UINavigationController
- 控制器(view)的生命周期
- 通訊錄
- 數(shù)據(jù)存儲
- UITabBarController
- MODAL跳轉(zhuǎn)
- 手勢&繪圖
- 對UIView的形變:transform
- IOS的事件
- 手勢案例 -- 抽屜效果
2
多控制器處理
為了方便管理控制器,ios提供了2種特殊的控制器來管理多控制器
- UINavigationController
- UITabBarController
導(dǎo)航控制器UINavigationController
- 凡是有導(dǎo)航條的,都是這個控制器
- 導(dǎo)航控制器有自己的view,還有一個導(dǎo)航條(y = 20),還有一個棧頂控制器view
- 添加就是pushViewController
凡是導(dǎo)航條下面的scrollView默認(rèn)都會有一個64的contentInset偏移量,如果不想默認(rèn),就需要設(shè)置self.automaticallyAdjustsScrollViewInset = NO表示不要自動設(shè)置偏移量。這樣下面的滾動表格就從0,0開始了。

- 當(dāng)一個控制器被添加到了導(dǎo)航控制器,它的navgationController屬性就有值了
- 導(dǎo)航控制器是以棧的形式添加控制器的,先進(jìn)后出,意味著被壓住的控制器是不會被銷毀的,只是被移走了,只有pop才會刪除控制器,當(dāng)pop跳躍移動的時(shí)候,那么這中間的控制器都會被銷毀
- 導(dǎo)航條內(nèi)容是由當(dāng)前棧頂控制器的UINavigationiItem模型屬性決定的。就是說你這個頁面想展示什么,就去這個頁面自己設(shè)置
- backBarButtonItem:返回按鈕
- titleView:中間標(biāo)題視圖
- title:中間文字
- leftBarButtonItem:左上角視圖(可以是文字,圖片,view)
- 自定義View的時(shí)候不需要設(shè)置位置,直接sizeToFit即可
- rightBarButtonItem:右上角視圖
- 設(shè)置Item內(nèi)容的時(shí)候會遇到渲染問題,可以單獨(dú)渲染圖片Origion,可以全局渲染
控制器(view)的生命周期
控制器View的生命周期方法:只要是控制器的生命周期方法,都是以view開頭.控制器View加載完成時(shí)調(diào)用 - (void)viewDidLoad { [super viewDidLoad]; } 控制器的View顯示完成時(shí)調(diào)用 -(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; } 控制器的View即將顯示的時(shí)候調(diào)用 -(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; } 控制器的View完全消失的時(shí)候調(diào)用 -(void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; } 控制器的View即將消失的時(shí)候調(diào)用. -(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; } 布局控制器View的子控件完成時(shí)調(diào)用 -(void)viewDidLayoutSubviews{ [super viewDidLayoutSubviews]; } 將要布局控制器的View里面子控件的時(shí)候就會調(diào)用. -(void)viewWillLayoutSubviews{ [super viewWillLayoutSubviews]; } ARC的生命周期 viewDidLoad->viewWillAppear->viewDidLayoutSubviews->viewDidLayoutSubviews->viewDidAppear-> viewWillDisappear->viewDidDisappear在非ARC當(dāng)中. 當(dāng)前控制器的View即將被銷毀的時(shí)候會調(diào)用 -(void)viewWillUnload{ [super viewWillUnload]; } 當(dāng)前控制器的View被銷毀的時(shí)候會調(diào)用 -(void)viewDidUnload{ [super viewDidUnload]; 清空界面上的數(shù)據(jù). self.dataList = nil; } viewDidLoad->viewWillAppear->viewDidLayoutSubviews->viewDidLayoutSubviews->viewDidAppear-> viewWillDisappear->viewDidDisappear->接收到內(nèi)存警告->viewWillUnload->釋放View->viewDidUnload通訊錄
數(shù)據(jù)存儲
ios常用的存儲
1. plist歸檔 2. Prference偏好設(shè)置 3. NSKeyedArchiver歸檔(NSCoding)--> 保存自定義對象 4. SQLite3 5. Core Date(對SQLite3的封裝,有一套庫來操作數(shù)據(jù)庫)每一個ios應(yīng)用都有自己的沙盒,并且每一個app都是文件隔離,獨(dú)立的沙盒,沙盒目錄如下

Documents存儲著應(yīng)用運(yùn)行時(shí)需要持久化的數(shù)據(jù),iTunes同步設(shè)備會備份該目錄,例如游戲文檔(網(wǎng)絡(luò)下載的存這里直接蘋果退回)
tmp是保存臨時(shí)數(shù)據(jù),不備份,系統(tǒng)可能會清除
library/Caches存儲持久化數(shù)據(jù),iTunes不會備份,一般存儲體積大不用備份的非重要數(shù)據(jù)
library/Preference保存應(yīng)用程序所有偏好設(shè)置,iTunes會備份,
這些數(shù)據(jù)如果存儲錯了,那么打包可能會被蘋果退回來的
- plist
- 偏好設(shè)置:一般用來保存用戶名,密碼,字體大小等設(shè)置。
- 歸檔:偏好設(shè)置和pilsh都是字典數(shù)組,存儲對象需要?dú)w檔
UITabBarController
- 也用于管理多控制器,也有一個子控制器view,底部有一個UITabBar。UITabBar的高度是49, selecyedIndex屬性控制當(dāng)前顯示控制器,并且也有一個數(shù)組childViewControllers,但是添加的時(shí)候不是棧的形式了,當(dāng)選中(顯示)別的控制器的時(shí)候,不顯示的控制器還是一直在的,因?yàn)槎荚跀?shù)組里,沒釋放的。
- UITabBar內(nèi)容:
- 如果UITabBarController有N個子控制器,那么UITabBar就有N個UITabBarButton。UITabBarButton里面的內(nèi)容由UITabBarItem 模型控制,其中有title,image,selectedImage,badgeValue等屬性。
MODAL跳轉(zhuǎn)
- 從地下鉆出來的控制器,就是modal。任何控制器都能modal出來,用present 和 dismiss來完成。push一般是有關(guān)系的兩個頁面,modal一般注冊啊這個那個都可以用。
手勢&繪圖
對UIView的形變:transform
在做動畫的時(shí)候,一般會對View做平移,旋轉(zhuǎn),縮放等操作,就用到transform
- CGAffineTransformTranslate - CGAffineTransformRotate - CGAffineTransformScaleIOS的事件
1.ios的事件分為三大類,觸摸,加速計(jì),遠(yuǎn)程控制事件,分別是觸摸,搖動手機(jī),控制耳機(jī)按鈕等。
觸摸:ios中不是任何對象都能處理事件,只有繼承了UIResponder的對象才能響應(yīng),稱為響應(yīng)者對象。UIApplication,UIViewController,UIView都繼承自UIResponder,都能接收并且處理事件。
//當(dāng)開始觸摸屏幕的時(shí)候調(diào)用 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{NSLog(@"%s",__func__); }//觸摸時(shí)開始移動時(shí)調(diào)用(移動時(shí)會持續(xù)調(diào)用) //NSSet:無序 //NSArray:有序 -(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{//NSLog(@"%s",__func__);//做UIView拖拽UITouch *touch = [touches anyObject];//求偏移量 = 手指當(dāng)前點(diǎn)的X - 手指上一個點(diǎn)的XCGPoint curP = [touch locationInView:self];CGPoint preP = [touch previousLocationInView:self];NSLog(@"curP====%@",NSStringFromCGPoint(curP));NSLog(@"preP====%@",NSStringFromCGPoint(preP));CGFloat offsetX = curP.x - preP.x;CGFloat offsetY = curP.y - preP.y;//平移self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);}//當(dāng)手指離開屏幕時(shí)調(diào)用 -(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{NSLog(@"%s",__func__); }//當(dāng)發(fā)生系統(tǒng)事件時(shí)就會調(diào)用該方法(電話打入,自動關(guān)機(jī)) -(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{NSLog(@"%s",__func__); }2.事件的傳遞:touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event方法中的touches記錄了你當(dāng)前觸摸的點(diǎn),上一次觸摸的點(diǎn),你觸摸的當(dāng)前控制器或者view,而event就保存著事件,里面保存著當(dāng)前發(fā)生的事件的時(shí)間,類型等。
- - -
當(dāng)發(fā)生一個觸摸事件,系統(tǒng)會將該事件加入一個由UIApplication管理事件的隊(duì)列(先進(jìn)先出),然后拿出最前面的事件(也就是先觸摸的),然后交給主窗口keyWindow,主窗口會根據(jù)視圖層次結(jié)構(gòu)找到一個最合適的視圖來處理觸摸事件,找到了就調(diào)用touch方法了。
UIAppcation -> UIWindow -> 父控件 -> 一層層到子控件。如果父控件無法接受觸摸,那么子控件也無法接收觸摸。如果父控件隱藏,子控件也隱藏。如果父控件aplha = 0,子控件也是0.
3.UIView不接收觸摸的三種情況
- userIntercationEnable = NO - hidden = YES - alpha = 0.0 ~ 0.01 - UIImageView默認(rèn)用戶交互是No4.如何尋找最適合View?
先看自己能否接收事件,再看觸摸點(diǎn)在不在自己身上,然后從后往前遍歷子控件,如果沒有合適的就是自己最合適處理。如果用代碼來尋找,就要調(diào)用hitTest方法。(開發(fā)中沒用過 )
//作用:去尋找最適合的View //什么時(shí)候調(diào)用:當(dāng)一個事件傳遞給當(dāng)前View,就會調(diào)用. -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{NSLog(@"%s",__func__);return [super hitTest:point withEvent:event]; }5 事件觸摸
在產(chǎn)生一個事件時(shí),系統(tǒng)會將該事件加入到一個由UIApplication管理的事件隊(duì)列中,
UIApplication會從事件隊(duì)列中取出最前面的事件,將它傳遞給先發(fā)送事件給應(yīng)用程序的主窗口.
主窗口會調(diào)用hitTest方法尋找最適合的視圖控件,找到后就會調(diào)用視圖控件的touches方法來做具體的事情.
當(dāng)調(diào)用touches方法,它的默認(rèn)做法, 就會將事件順著響應(yīng)者鏈條往上傳遞,
傳遞給上一個響應(yīng)者,接著就會調(diào)用上一個響應(yīng)者的touches方法
6.手勢識別
手勢識別器UIGrestreRecognizer是一個抽象類,使用它的子類才能處理手勢,有點(diǎn)按,長按,輕掃,拖動,旋轉(zhuǎn),捏合六種。
添加點(diǎn)按手勢 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)]; 手勢也可以設(shè)置代理 tap.delegate = self; 添加手勢 [self.imageV addGestureRecognizer:tap];代理方法: 是否允許接收手指 -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{讓圖片的左邊不可以點(diǎn)擊, 獲取當(dāng)前手指所在的點(diǎn).是在圖片的左邊還是在圖片的右邊. CGPoint curP = [touch locationInView:self.imageV];if (curP.x > self.imageV.bounds.size.width * 0.5) {在圖片的右側(cè)return YES;}else{在圖片的左側(cè)return NO;}return YES; }添加長按手勢 UILongPressGestureRecognizer *longP = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longP:)];?? [self.imageV addGestureRecognizer:longP];當(dāng)長按時(shí)調(diào)用. 這個方法會調(diào)用很多次, 當(dāng)手指長按在上面不松,來回移動時(shí),會持續(xù)調(diào)用. 所以要判斷它的狀態(tài). - (void)longP:(UILongPressGestureRecognizer *)longP{if(longP.state == UIGestureRecognizerStateBegan){NSLog(@"開始長按");}else if(longP.state == UIGestureRecognizerStateChanged){NSLog(@"長按時(shí)手指移動");}else if(longP.state == UIGestureRecognizerStateEnded){NSLog(@"手指離開屏幕");} }添加輕掃手勢 UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];輕掃手勢默認(rèn)是向右邊稱輕掃可以設(shè)置輕掃的方法.一個輕掃手勢只能設(shè)置一個方法的輕掃.想要讓它有多個方向的手勢,必須得要設(shè)置的swipe.direction =? UISwipeGestureRecognizerDirectionLeft;[self.imageV addGestureRecognizer:swipe];添加輕掃手勢 UISwipeGestureRecognizer *swipe2 = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)]; 輕掃手勢默認(rèn)是向右邊稱輕掃 可以設(shè)置輕掃的方法. 一個輕掃手勢只能設(shè)置一個方法的輕掃.想要讓它有多個方向的手勢,必須得要設(shè)置的swipe2.direction =? UISwipeGestureRecognizerDirectionUp;[self.imageV addGestureRecognizer:swipe2];- (void)swipe:(UISwipeGestureRecognizer *)swipe{判斷的輕掃的方向if (swipe.direction == UISwipeGestureRecognizerDirectionLeft) {NSLog(@"向左輕掃");}else if(swipe.direction == UISwipeGestureRecognizerDirectionUp){NSLog(@"向上輕掃");} }添加平移手勢UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];[self.imageV addGestureRecognizer:pan];當(dāng)手指拖動時(shí)調(diào)用 - (void)pan:(UIPanGestureRecognizer *)pan{拖動手勢也有狀態(tài) if(pan.state == UIGestureRecognizerStateBegan){開始拖動 ?}else if(pan.state == UIGestureRecognizerStateChanged){可能獲取不當(dāng)前手指移動的舉例 是相對于最原始的點(diǎn) CGPoint transP = [pan translationInView:self.imageV];會清空上一次的形變 self.imageV.transform = CGAffineTransformMakeTranslation(transP.x,transP.y); self.imageV.transform = CGAffineTransformTranslate(self.imageV.transform, transP.x, transP.y);復(fù)位,讓它相對于上一次. [pan setTranslation:CGPointZero inView:self.imageV];}else if(pan.state == UIGestureRecognizerStateEnded){結(jié)束拖動 ? ? ??} }添加捏合手勢 UIPinchGestureRecognizer *pinGes = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinGes:)]; 設(shè)置代理使其能夠同時(shí)支持多個手勢 pinGes.delegate = self; [self.imageV addGestureRecognizer:pinGes];旋轉(zhuǎn)時(shí)調(diào)用 - (void)pinGes:(UIPinchGestureRecognizer *)pin{self.imageV.transform = CGAffineTransformScale(self.imageV.transform, pin.scale, pin.scale);復(fù)位 [pin setScale:1];}添加旋轉(zhuǎn)手勢UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];設(shè)置代理使其能夠同時(shí)支持多個手勢rotation.delegate = self;[self.imageV addGestureRecognizer:rotation];當(dāng)手指開始旋轉(zhuǎn)時(shí)調(diào)用. - (void)rotation:(UIRotationGestureRecognizer *)rotation{ self.imageV.transform = CGAffineTransformRotate(self.imageV.transform, rotation.rotation);復(fù)位. [rotation setRotation:0]; }可以添加多個手勢,例如又旋轉(zhuǎn)又放大又捏合(支持代理,實(shí)現(xiàn)方法就行,要找一找,方法比較多,是一個允許支持多手勢的代理方法),
手勢案例 -- 抽屜效果
Make by:弓_雖_子 第一步:搭建界面- (void)viewDidLoad {[super viewDidLoad];搭建界面 [self setUpView]; }- (void)setUpView{添加左邊的View UIView *leftV = [[UIView alloc] initWithFrame:self.view.bounds]; 左邊藍(lán)色leftV.backgroundColor = [UIColor blueColor];[self.view addSubview:leftV];添加右邊的View UIView *rightV = [[UIView alloc] initWithFrame:self.view.bounds]; 右邊縁色?rightV.backgroundColor = [UIColor greenColor];self.rightV = rightV;[self.view addSubview:rightV];添加中間的View(中間一個最后添加,顯示到最外面.) UIView *mainV = [[UIView alloc] initWithFrame:self.view.bounds]; 中間紅色mainV.backgroundColor = [UIColor redColor];self.mainV = mainV;[self.view addSubview:mainV]; }第二步.添加手勢.能夠讓中間的紅色View左右移動,要在控制器View加載完成時(shí)就要添加View- (void)viewDidLoad {[super viewDidLoad];搭建界面 [self setUpView]; 拖動手勢 UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; 添加手勢 [self.mainV addGestureRecognizer:pan]; }實(shí)現(xiàn)手勢方法: 當(dāng)手指拖動時(shí)調(diào)用. -(void)pan:(UIPanGestureRecognizer *)pan{獲取手指在屏幕上面的偏移量 CGPoint transP = [pan translationInView:self.mainV];在這里為什么不用Transform,是因?yàn)槲覀円苿訒r(shí),要改變的尺寸大小.用Transform只能改變它的位置. self.mainV.transform? = CGAffineTransformTranslate(self.mainV.transform, transP.x, 0);計(jì)算mainV的Frame 單獨(dú)抽出一個方法來計(jì)算mainV的frame.因?yàn)橐?jì)算它的Y值和高度.代碼會很多.所以單獨(dú)抽出一個方法self.mainV.frame = [self frameWithOffsetX:transP.x]; 每次移動時(shí)判斷當(dāng)前MainV的x值是大于0還是小于0.如果是大于0 , 顯示左邊,小于0 顯示右邊 if (self.mainV.frame.origin.x > 0) {self.rightV.hidden = YES;}else if(self.mainV.frame.origin.x < 0){self.rightV.hidden = NO; }注意要做復(fù)位[pan setTranslation:CGPointZero inView:self.mainV];? ? }最大Y值為100 #define maxY 100 根據(jù)偏移量計(jì)算mainV的frame. - (CGRect)frameWithOffsetX:(CGFloat)offsetX{? ?取出最原始的Frame CGRect frame = self.mainV.frame; frame.origin.x += offsetX;獲取屏幕的寬度 (計(jì)算Y值如果下圖:找最大值.當(dāng)Main.x拖動最大的時(shí)候,Main.y值也最大.main.x最大為屏幕的寬度)設(shè)定一個最大Y值MaxY為100,正好.當(dāng)max.x為屏幕的寬度時(shí),最大Y等于100所以Y值等于 main.y = main.x * maxY / ScreenW;100 = 375 * 100 / 375;)?有可能frame.origin.x有可能是小于0,小于0的話, 得出的Y值就會小于0,小于0就會出現(xiàn), 紅色的View向上走. 對結(jié)果取絕對值.frame.origin.y =? fabs(frame.origin.x * maxY / screenW); 計(jì)算frame的高度 (當(dāng)前Main的高度等于屏幕的高度減去兩倍的Y值.)frame.size.height = screenH - 2 * frame.origin.y; 返回計(jì)算好的frame.return frame; }第三步:當(dāng)手指松開時(shí)做到自動定位.?MainV定位到右側(cè)的X值 #define targetR 275 MainV定位到右側(cè)的X值 #define targetL -275當(dāng)手指拖動時(shí)調(diào)用. -(void)pan:(UIPanGestureRecognizer *)pan{獲取手指在屏幕上面的偏移量 CGPoint transP = [pan translationInView:self.mainV];在這里為什么不用Transform,是因?yàn)槲覀円苿訒r(shí),要改變的尺寸大小.用Transform只能改變它的位置. self.mainV.transform? = CGAffineTransformTranslate(self.mainV.transform, transP.x, 0);計(jì)算mainV的Frame 單獨(dú)抽出一個方法來計(jì)算mainV的frame.因?yàn)橐?jì)算它的Y值和高度.代碼會很多.所以單獨(dú)抽出一個方法self.mainV.frame = [self frameWithOffsetX:transP.x]; 每次移動時(shí)判斷當(dāng)前MainV的x值是大于0還是小于0.如果是大于0 , 顯示左邊,小于0 顯示右邊 if (self.mainV.frame.origin.x > 0) {self.rightV.hidden = YES;}else if(self.mainV.frame.origin.x < 0){self.rightV.hidden = NO; }判斷手指的狀態(tài) if(pan.state == UIGestureRecognizerStateEnded){ 當(dāng)手指松開時(shí)進(jìn)入執(zhí)行?記錄最終判斷結(jié)果后.定位的值.CGFloat target = 0; 當(dāng)手指松開,要判斷MainV的x值是否大于屏幕的一半.如果大于屏幕一半時(shí), 自動定位到右邊一個位置. if (self.mainV.frame.origin.x > screenW * 0.5) {target = targetR; }else if(CGRectGetMaxX(self.mainV.frame) < screenW * 0.5){當(dāng)手指松開,要判斷MainV的最大的X值是否小于屏幕的一半.如果小于屏幕的一半時(shí), 自動定位到左邊的位置. target = targetL; }最終定位的x值 - 當(dāng)前的main.x的值. 求出便宜量.使其定位CGFloat offsetX = target - self.mainV.frame.origin.x; 根據(jù)便宜量設(shè)置mainV的frame值?CGRect frame = [self frameWithOffsetX:offsetX]; [UIView animateWithDuration:0.25 animations:^{ 伴隨動畫設(shè)置frameself.mainV.frame = frame; }];}注意要做復(fù)位[pan setTranslation:CGPointZero inView:self.mainV];? ? }轉(zhuǎn)載于:https://www.cnblogs.com/sgxx/p/7120092.html
總結(jié)
- 上一篇: 2 - 4 - 实例:X86的中断与异常
- 下一篇: Object类-try-catch-fi