UI-2

172.簡述視圖控制器的生命周期。

1)init函數(shù)(init;initWithFrame;initWithCoder;等)--初始化
2)awakeFromNib--在loadView之前的工作放在這里
3)viewDidLoad--注意,一個ViewController一個生命周期內這個函數(shù)只會調用一次
4)viewWillAppear--view將要出現(xiàn),每次View消失再出現(xiàn)都會調用
5)viewWillLayoutSubviews--簡要對子試圖進行布局
6)viewDidLayoutSubivews--完成對子試圖布局
7)viewDidAppear--視圖將要出現(xiàn)在屏幕上
---上述代碼不含部分
8)、viewWillDisappear--View將要消失
9)viewDidDisappear--View已經(jīng)消失

7.描述下viewWillAppear、layoutSubviews、viewDidAppear、viewDidLayoutSubviews、 viewWillLayoutSubviews、 viewDidLoad 的執(zhí)行順序。

答:UIViewController中l(wèi)oadView, viewDidLoad, viewWillUnload, viewDidUnload, viewWillAppear, viewDidAppear, viewWillLayoutSubviews,viewDidLayoutSubviews,viewWillDisappear, viewDidDisappear方法,按照調用順序說明如下:
當一個視圖顯示時:
1.initWithNibName:bundle:
2.loadView
3.viewDidLoad
4.viewWillAppear
5.viewDidAppear
6.viewWillLayoutSubviews
7.viewDidLayoutSubviews
8.viewWillDisappear
9.viewDidDisappear
10.viewWillUnload
11.viewDidUnload

當一個視圖被移除屏幕并且銷毀的時候的執(zhí)行順序,這個順序差不多和上面的相反
1、viewWillDisappear 視圖將被從屏幕上移除之前執(zhí)行
2、viewDidDisappear 視圖已經(jīng)被從屏幕上移除,用戶看不到這個視圖了
3、dealloc 視圖被銷毀,此處需要對你在init和viewDidLoad中創(chuàng)建的對象進行釋放

調試日志:
2013-07-14
12:15:49.048
VCTest[13412:907]
initWithNibName:bundle  /  initWithCoder
#如果使用的StoryBoard

2013-07-14
12:15:49.056
VCTest[13412:907]
loadView

2013-07-14
12:15:49.059
VCTest[13412:907]
viewDidLoad

2013-07-14
12:15:49.061
VCTest[13412:907]
viewWillAppear

2013-07-14
12:15:49.078
VCTest[13412:907]
viewWillLayoutSubviews

2013-07-14
12:15:49.083
VCTest[13412:907]
viewDidLayoutSubviews

2013-07-14
12:15:49.445
VCTest[13412:907]
viewDidAppear

2013-07-14
12:16:00.624
VCTest[13412:907]
viewWillDisappear

2013-07-14
12:16:00.997
VCTest[13412:907]
viewDidDisappear
  1. initWithNibName:bundle:
    初始化UIViewController,執(zhí)行關鍵數(shù)據(jù)初始化操作,注意這里不要做view相關操作,view在loadView方法中才初始化,這時loadView還未調用。如果使用StoryBoard進行視圖管理,程序不會直接初始化一個UIViewController,StoryBoard會自動初始化或在segue被觸發(fā)時自動初始化,因此方法initWithNibName:bundle:不會被調用。如果在代碼里面使用instantiateViewControllerWithIdentifier:方法顯示初始化一個UIViewController,則initWithCoder方法會被調用。

如果是通過調用initWithNibName:bundle指定nib文件名初始化的話,ViewController會根據(jù)此nib來創(chuàng)建View。如果name參數(shù)為nil,則ViewController會通過以下兩個步驟找到與其關聯(lián)的nib:
1)如果ViewController的類名以“Controller”結尾,例如ViewController的類名是MyViewController,則查找是否存在MyView.nib;
2)找跟ViewController類名一樣的文件,例如MyViewController,則查找是否存在MyViewController.nib

  1. loadView
    當訪問UIViewController的view屬性時,view如果此時是nil,那么VC會自動調用loadView方法來初始化一個UIView并賦值給view屬性。此方法用在初始化關鍵view,需要注意的是,在view初始化之前,不能先調用view的getter方法,否則將導致死循環(huán)(除非先調用了[supper loadView];)。
-(void)loadView{
    NSLog(@"loadView");
    //錯誤,將導致死循環(huán),因此此時view=nil,VC會再次調用loadView來初始化view
    self.view.backgroundColor = [UIColor greenColor];
}

-(void)loadView{
    NSLog(@"loadView");
    //正確,先初始化view
    self.view=[[MyView alloc] init];
    self.view.backgroundColor=[UIColor greenColor];
}

如果沒有重載loadView方法,則UIViewController會從nib或StoryBoard中查找默認的loadView,默認的loadView會返回一個空白的UIView對象。
  1. viewDidLoad
    當VC的view對象載入內存后調用,用于對view進行額外的初始化操作
  1. viewWillAppear
    在view即將添加到視圖層級中(顯示給用戶)且任意顯示動畫切換之前調用(這個時候supperView還是nil)。這個方法中完成任何與視圖顯示相關的任務,例如改變視圖方向、狀態(tài)欄方向、視圖顯示樣式等
  1. viewDidAppear
    在view被添加到視圖層級中,顯示動畫切換之后調用(這時view已經(jīng)添加到supperView中)。在這個方法中執(zhí)行視圖顯示相關附件任務,如果重載了這個方法,必須在方法中調用[supper viewDidAppear];
  1. viewWillLayoutSubviews
    view即將布局其Subviews。比如view的bounds改變了(例如狀態(tài)欄從不顯示到顯示,視圖方向變化),要調整Subviews的位置,在調整之前要做的一些工作就可以在該方法中實現(xiàn)。
  1. viewDidLayoutSubviews
    view已經(jīng)布局其Subviews。比如view的bounds改變了(例如狀態(tài)欄從不顯示到顯示,視圖方向變化),已經(jīng)調整Subviews的位置,在調整完成之后要做的一些工作就可以在該方法中實現(xiàn)。
  1. viewWillDisappear
    view即將從superView中移除且移除動畫切換之前,此時還沒有調用removeFromSuperview。
  1. viewDidDisappear
    view從superView中移除,移除動畫切換之后調用,此時已調用removeFromSuperview。
  1. viewWillUnload
    在VC的view對象從內存中釋放之前調用,可以在view被釋放前做一些資源清理操作。在iOS6.0開始就廢棄了,該方法不再會調用
  1. viewDidUnload
    在VC的view對象從內存中釋放之后調用,可以在view被釋放后做一些view相關的引用清理操作,此時view為nil。在iOS6.0開始就廢棄了,該方法不再會調用

當一個視圖被移除屏幕并且銷毀的時候的執(zhí)行順序,這個順序差不多和上面的相反
1、viewWillDisappear 視圖將被從屏幕上移除之前執(zhí)行
2、viewDidDisappear 視圖已經(jīng)被從屏幕上移除,用戶看不到這個視圖了
3、dealloc 視圖被銷毀,此處需要對你在init和viewDidLoad中創(chuàng)建的對象進行釋放

7、+(void)load; +(void)initialize;有什么用處?

答:
+(void)load;
當類對象被引入項目時, runtime 會向每一個類對象發(fā)送 load 消息,load 方法會在每一個類甚至分類被引入時僅調用一次,調用的順序:父類優(yōu)先于子類, 子類優(yōu)先于分類
load 方法不會被類自動繼承

+(void)initialize;
也是在第一次使用這個類的時候會調用這個方法。

8、實現(xiàn)一個第三方控件,可以在任何時候出現(xiàn)在APP界面最上層

1.將這個視圖添加在Window上
2.將這個控件做成一個新的window,顯示在最上層

3 int retVal = UIApplicationMain(argc, argv, nil, nil); 是什么意思?

答:對UIApplication對象進行了初始化,這個方法除了argc 和 argv 參數(shù)外,另外這個函數(shù)還有2個兩個字符串參數(shù)來識別UIApplication類和UIApplication代理類,在這里默認是2個nil,第一個參數(shù)為nil就默認把UIApplication類作為缺省值進行初始化,可以在這里不填nil而是使用自己定義的UIApplication子類。至于第二個參數(shù)nil就設置為nil就把模板生成的HelloWorldAppdelegate類作為默認值。

23 實例化一個UITableView對象 要求寫出關鍵語句

答:
UITableView *my = [[UITableView alloc] initWithFrame:<#(CGRect)frame#> style:<#(UITableViewStyle)style#>];
my.delegate = self;
my.dataSource = self;
首先需要分配空間 設置表格類型 然后需要設置兩個必須的委托對象。

9、下面代碼中obj2是否需要dealloc?

ClassA *obj1 = [[ClassA alloc] init];
ClassA *obj2= obj1
[obj1 hello]; //輸出 hello
[obj1 dealloc];
[obj1 hello]; //程序輸出能否執(zhí)行到這一行?
[obj2 dealloc];

不能,因為obj1和obj2只是指針,它們指向同一個對象,[obj1 dealloc]已經(jīng)銷毀這個對象了,不能再調用[obj2 hello]和[obj2 dealloc]。obj2實際上是個無效指針。

19、UIView的動畫效果有哪些?

UIViewAnimationOptionCurveEaseInOut
UIViewAnimationOptionCurveEaseIn
UIViewAnimationOptionCurveEaseOut
UIViewAnimationOptionTransitionFlipFromLeft
UIViewAnimationOptionTransitionFlipFromRight
UIViewAnimationOptionTransitionCurlUp
UIViewAnimationOptionTransitionCurlDown

4、簡述在一個App中間有一個button,在你手觸摸屏幕點擊后,到這個button收到點擊事件,中間發(fā)生了什么?

響應鏈大概有以下幾個步驟
1、設備將touch到的UITouch和UIEvent對象打包, 放到當前活動的Application的事件隊列中
2、單例的UIApplication會從事件隊列中取出觸摸事件并傳遞給單例UIWindow
3、UIWindow使用hitTest:withEvent:方法查找touch操作的所在的視圖view

RunLoop這邊我大概講一下
1、主線程的RunLoop被喚醒
2、通知Observer,處理Timer和Source 0
3、Springboard接受touch event之后轉給App進程
4、RunLoop處理Source 1,Source1 就會觸發(fā)回調,并調用_UIApplicationHandleEventQueue() 進行應用內部的分發(fā)。
5、RunLoop處理完畢進入睡眠,此前會釋放舊的autorelease pool并新建一個autorelease pool
深挖請去看此文深入理解RunLoop

5、如果UIView *view已經(jīng)實例化,在view僅添加了N個UIButton類的實例,這些button不是全局的,并且button已經(jīng)用tag區(qū)分開,如何快速找出其中指定的一個button改變它的某個屬性?

答:view中有一個方法可以根據(jù)tag值把他上面的子視圖找出來 [view subviewWithTag: ];

8、一個UITableView的實例,重新加載數(shù)據(jù)的方法是什么?

答:[tableView reloadData]方法

6、請問可以通過哪些方法在UIView里創(chuàng)建元素?

答:拖控件,xib,純代碼

1.簡述下UIViewController的生命周期?

當一個視圖控制器被創(chuàng)建,并在屏幕上顯示的時候。 代碼的執(zhí)行順序
1、alloc 創(chuàng)建對象,分配空間
2、init (initWithNibName) 初始化對象,初始化數(shù)據(jù)
3、loadView 加載視圖。
4、viewDidLoad 載入完成,可以進行自定義數(shù)據(jù)以及動態(tài)創(chuàng)建其他控件
5、viewWillAppear 視圖將出現(xiàn)在屏幕之前,馬上這個視圖就會被展現(xiàn)在屏幕上了
6、viewDidAppear 視圖已在屏幕上渲染完成

當一個視圖被移除屏幕并且銷毀的時候的執(zhí)行順序,這個順序差不多和上面的相反
1、viewWillDisappear 視圖將被從屏幕上移除之前執(zhí)行
2、viewDidDisappear 視圖已經(jīng)被從屏幕上移除,用戶看不到這個視圖了
3、dealloc 視圖被銷毀,此處需要對你在init和viewDidLoad中創(chuàng)建的對象進行釋放

當我們創(chuàng)建一個UIViewController類的對象時,通常系統(tǒng)會生成幾個默認的方法,這些方法大多與視圖的調用有關,但是在視圖調用時,這些方法的調用順序如何,需要整理下。
通常上述方法包括如下幾種,這些方法都是UIViewController類的方法:
-(void)loadView;
-(void)viewDidLoad;
-(void)viewWillAppear:(BOOL)animated;
-(void)viewDidAppear:(BOOL)animated;
-(void)viewWillDisappear:(BOOL)animated;
-(void)viewDidDisappear:(BOOL)animated;

下面我將講解一下APP在實際調用的過程中所運行的順序:
1.在第一次打開應用后,會立即加載四個方法他們分別是:
-(void)loadView;
-(void)viewDidLoad;
-(void)viewWillAppear:(BOOL)animated;
-(void)viewDidAppear:(BOOL)animated;
其中要注意的是:在視圖將要出現(xiàn)之前我們是不是應該將所有的控件鋪好呢,答案是肯定的,在用戶體驗的角度考慮當用戶在進入APP后應該立即就能看見所有的信息展示(在網(wǎng)絡較好的前提下),所以對于開發(fā)者來說應該在第二個方法中進行所有的空間及信息的載入等工作,這樣用戶在打開APP后立即就能看見所有的信息了.

當進入第二個頁面的時候其加載(push到新的界面)順序是:
(1)當前界面會走的方法
-(void)viewWillDisappear:(BOOL)animated;
(2)新加載的視圖走的方法
-(void)loadView;
-(void)viewDidLoad;
-(void)viewWillAppear:(BOOL)animated;
(3)同時走的方法:
當前界面
-(void)viewDidDisappear:(BOOL)animated;
新加載的方法
-(void)viewDidAppear:(BOOL)animated;

當返回第一個界面的時候(pop返回原界面)順序是:
(1)當前的界面會走的方法
-(void)viewWillDisappear:(BOOL)animated;
(2)要返回的視圖走的方法
-(void)loadView;(該方法可能走也可能不走,因為視圖已經(jīng)在之前加載完畢,但有時,程序員會在進入一個界面后清除數(shù)據(jù),因此根據(jù)具體情況而定)
-(void)viewDidLoad;(該方法可能走也肯能不走,因為視圖已經(jīng)在之前加載完畢,但有時,程序員會在進入一個界面后清除數(shù)據(jù),因此根據(jù)具體情況而定)
-(void)viewWillAppear:(BOOL)animated;
(3)同時走的方法:
當前界面
-(void)viewDidDisappear:(BOOL)animated;
新加載的方法
-(void)viewDidAppear:(BOOL)animated;

2.簡述ViewController的生命周期。

-(void)viewDidLoad;
-(void)viewDidUnload;
-(void)viewWillAppear:(BOOL)animated;
-(void)viewDidAppear:(BOOL)animated;
-(void)viewWillDisappear:(BOOL)animated;
-(void)viewDidDisappear:(BOOL)animated;

1.loadView 如果重寫了這個方法,則控制器的view按照loadView方法的描述去創(chuàng)建

2.viewDidLoad 只調用一次

3.viewWillAppear 在視圖顯示之前該函數(shù)可以被多次調用

4.viewDidAppear 視圖顯示完畢后調用

5.viewWillDisAppear 在視圖消失之前,該函數(shù)可以被多次調用

6.viewWillLayoutSubviews 布局變化前

7.viewDidLayoutSubviews 布局變化后

8.控制器還有三個需要注意的方法
viewWillUnload\viewDidUnload\didReceiveMemoryWarning
當程序內存不夠用時,最先拿到內存警告的是
UIApplication-Window-window.rootViewController一層層往下傳
當控制器收到內存警告時,如果要確定要銷毀view,則會調用viewWillUnload\viewDidUnload

9.當控制器銷毀后,又需要顯示,則控制器會調用loadView,又一步一步開始走一遍

12.談一下UITableViewCell的重用機制

TableView的重用機制,為了做到顯示和數(shù)據(jù)分離,UITableView的實現(xiàn)并且不是為每個數(shù)據(jù)項創(chuàng)建一個Cell。而是只創(chuàng)建屏幕可顯示最大個數(shù)的cell,然后重復使用這些cell,對cell做單獨的顯示配置,來達到既不影響顯示效果,又能充分節(jié)約內容的目的。下面簡要分析一下它的實現(xiàn)原理。

重用實現(xiàn)分析:

UITableView頭文件中,會找到NSMutableArray* visiableCells,和NSMutableDictnary* reusableTableCells兩個結構。visiableCells內保存當前顯示的cells,reusableTableCells保存可重用的cells。

TableView顯示之初,reusableTableCells為空,那么tableView dequeueReusableCellWithIdentifier:CellIdentifier返回nil。開始的cell都是通過[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]來創(chuàng)建,而且cellForRowAtIndexPath只是調用最大顯示cell數(shù)的次數(shù)。

比如:有100條數(shù)據(jù),iPhone一屏最多顯示10個cell。程序最開始顯示TableView的情況是:
1、用[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]創(chuàng)建10次cell,并給cell指定同樣的重用標識(當然,可以為不同顯示類型的cell指定不同的標識)。并且10個cell全部都加入到visiableCells數(shù)組,reusableTableCells為空。
2、向下拖動tableView,當cell1完全移出屏幕,并且cell11(它也是alloc出來的,原因同上)完全顯示出來的時候。cell11加入到visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。
3、接著向下拖動tableView,因為reusableTableCells中已經(jīng)有值,所以,當需要顯示新的cell,cellForRowAtIndexPath再次被調用的時候,tableView dequeueReusableCellWithIdentifier:CellIdentifier,返回cell1。cell1加入到visiableCells,cell1移出reusableTableCells;cell2移出visiableCells,cell2加入到reusableTableCells。之后再需要顯示的Cell就可以正常重用了。
所以整個過程并不難理解,但需要注意正是因為這樣的原因:配置Cell的時候一定要注意,對取出的重用的cell做重新賦值,不要遺留老數(shù)據(jù)。

一些情況:
  使用過程中,并不是只有拖動超出屏幕的時候才會更新reusableTableCells表,還有:
1、reloadData,這種情況比較特殊。一般是部分數(shù)據(jù)發(fā)生變化,需要重新刷新cell顯示的內容時調用。在cellForRowAtIndexPath調用中,所有cell都是重用的。我估計reloadData調用后,把visiableCells中所有cell移入reusableTableCells,visiableCells清空。cellForRowAtIndexPath調用后,再把reuse的cell從reusableTableCells取出來,放入到visiableCells。
2、reloadRowsAtIndex,刷新指定的IndexPath。如果調用時reusableTableCells為空,那么cellForRowAtIndexPath調用后,是新創(chuàng)建cell,新的cell加入到visiableCells。老的cell移出visiableCells,加入到reusableTableCells。于是,之后的刷新就有cell做reuse了。

注意:
1、重取出來的cell是有可能已經(jīng)捆綁過數(shù)據(jù)或者加過子視圖的,所以,如果有必要,要清除數(shù)據(jù)(比如textlabel的text)和remove掉add過的子視圖(使用tag)。
2、這樣設計的目的是為了避免頻繁的 alloc和delloc cell對象而已,沒有多復雜。
3、設計的關鍵是實現(xiàn)cell和數(shù)據(jù)的完全分離

重點:避免重用機制出錯
1、重用機制調用的就是dequeueReusableCellWithIdentifier這個方法,方法的意思就是“出列可重用的cell”,因而只要將它換為cellForRowAtIndexPath(只從要更新的cell的那一行取出cell),就可以不使用重用機制,因而問題就可以得到解決,但會浪費一些空間
2、為每個cell指定不同的重用標識符(reuseIdentifier)來解決。重用機制是根據(jù)相同的標識符來重用cell的,標識符不同的cell不能彼此重用。
NSString *identifier = [NSString stringWithFormat:@"TimeLineCell%d%d",indexPath.section,indexPath.row];
3、刪除重用的cell的所有子視圖,從而得到一個沒有特殊格式的cell,供其他cell重用。

if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
} else {
    //刪除cell的所有子視圖
    while ([cell.contentView.subviews lastObject] != nil)
    {
        [(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview];
    }
}

11.frame和bounds的區(qū)別

frame
該view在父view坐標系統(tǒng)中的位置和大小,它的參考坐標系是父view的坐標系
bounds
該view在本地坐標系統(tǒng)中的位置和大小,它的參考坐標系是自身的坐標系,原點始終為(0,0)

概括
frame.size == bounds.size
scrollView.bounds.origin == scrollView.contentOffset

11.為什么很多內置類如:UITableViewController的delegate屬性都是assign而不是retain的?

會引起循環(huán)引用
所有的引用計數(shù)系統(tǒng),都存在循環(huán)應用的問題。
例如下面的引用關系:
? 對象a創(chuàng)建并引用到了對象b.
? 對象b創(chuàng)建并引用到了對象c.
? 對象c創(chuàng)建并引用到了對象b.這時候b和c的引用計數(shù)分別是2和1。
當a不再使用b,調用release釋放對b的所有權,因為c還引用了b,所以b的引用計數(shù)為1,b不會被釋放。
b不釋放,c的引用計數(shù)就是1,c也不會被釋放。
從此,b和c永遠留在內存中。
這種情況,必須打斷循環(huán)引用,通過其他規(guī)則來維護引用關系。

我們常見的delegate往往是assign方式的屬性而不是retain方式 的屬性,賦值不會增加引用計數(shù),就是為了防止delegation兩端產(chǎn)生不必要的循環(huán)引用。如果一個UITableViewController 對象a通過retain獲取了UITableView對象b的所有權,這個UITableView對象b的delegate又是a, 如果這個delegate是retain方式的,那基本上就沒有機會釋放這兩個對象了。自己在設計使用delegate模式時,也要注意這點。

1.什么時候會報unrecognized selector的異常?

當使用某對象上的某個方法,而該對象上沒有實現(xiàn)這個方法的時候。
拉線,刪了方法,忘記刪線

簡單來說:
當調用該對象上某個方法,而該對象上沒有實現(xiàn)這個方法的時候,
可以通過“消息轉發(fā)”進行解決。

簡單的流程如下,在上一題中也提到過:
objc是動態(tài)語言,每個方法在運行時會被動態(tài)轉為消息發(fā)送,即:objc_msgSend(receiver, selector)。
objc在向一個對象發(fā)送消息時,runtime庫會根據(jù)對象的isa指針找到該對象實際所屬的類,然后在該類中的方法列表以及其父類方法列表中尋找方法運行,如果,在最頂層的父類中依然找不到相應的方法時,程序在運行時會掛掉并拋出異常unrecognized selector sent to XXX 。但是在這之前,objc的運行時會給出三次拯救程序崩潰的機會:
1、Method resolution
objc運行時會調用+resolveInstanceMethod:或者 +resolveClassMethod:,讓你有機會提供一個函數(shù)實現(xiàn)。如果你添加了函數(shù),那運行時系統(tǒng)就會重新啟動一次消息發(fā)送的過程,否則 ,運行時就會移到下一步,消息轉發(fā)(Message Forwarding)。
2、Fast forwarding
如果目標對象實現(xiàn)了-forwardingTargetForSelector:,Runtime 這時就會調用這個方法,給你把這個消息轉發(fā)給其他對象的機會。
只要這個方法返回的不是nil和self,整個消息發(fā)送的過程就會被重啟,當然發(fā)送的對象會變成你返回的那個對象。否則,就會繼續(xù)Normal Fowarding。
這里叫Fast,只是為了區(qū)別下一步的轉發(fā)機制。因為這一步不會創(chuàng)建任何新的對象,但下一步轉發(fā)會創(chuàng)建一個NSInvocation對象,所以相對更快點。
3、Normal forwarding
這一步是Runtime最后一次給你挽救的機會。首先它會發(fā)送-methodSignatureForSelector:消息獲得函數(shù)的參數(shù)和返回值類型。如果-methodSignatureForSelector:返回nil,Runtime則會發(fā)出-doesNotRecognizeSelector:消息,程序這時也就掛掉了。如果返回了一個函數(shù)簽名,Runtime就會創(chuàng)建一個NSInvocation對象并發(fā)送-forwardInvocation:消息給目標對象。

13.在一個UIV結尾中嵌入一個UIWebView(大小自適應完整顯示),UIView中的其他子控件和UIWebView的布局位置是相對的,請問怎樣才能保證在UIWebView的頁面動態(tài)變化是,其他控件能根據(jù)它的尺寸變化自適應?

有的網(wǎng)頁中會使用"<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">"這個標簽來設置網(wǎng)頁的寬度,不過帶來的問題是,如果展示這個webview的寬度不等于設備的寬度的時候,就會出現(xiàn)網(wǎng)頁內容過寬左右可以滑動或者網(wǎng)頁左右內容沒有占滿。找了一下,有兩個解決方法:

1. 利用webview中的scrollview的zoom特性,這個方法會讓網(wǎng)頁內容變小
-(void)webViewDidFinishLoad:(UIWebView *)theWebView {
        CGSize contentSize = theWebView.scrollView.contentSize;
        CGSize viewSize = self.view.bounds.size;
        float rw = viewSize.width / contentSize.width;
        theWebView.scrollView.minimumZoomScale = rw;
        theWebView.scrollView.maximumZoomScale = rw;
        theWebView.scrollView.zoomScale = rw;
}

2. 第二個方法,在客戶端使用js重寫meta標簽,這個也是在webview的delegate的webViewDidFinished回調中調用;我們使用的這種方法來操作,內容不會變小
javascript = [NSString stringWithFormat:@"var viewPortTag=document.createElement('meta');  \
                            viewPortTag.id='viewport';  \
                            [viewPortTag.name](http://viewPortTag.name) = 'viewport';  \
                            viewPortTag.content = 'width=%d; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;';  \
                            document.getElementsByTagName('head')[0].appendChild(viewPortTag);" , (int)authWebView.bounds.size.width];
[authWebView stringByEvaluatingJavaScriptFromString:javascript];

14.讓界面呈現(xiàn)動畫效果除了使用[UIView animateWithDuration:animations:]做簡單動畫之外,還有其他方式實現(xiàn)動畫嗎?

幀動畫,隱式動畫,核心動畫,動圖GIF



iOS的動畫效果一直都很棒很,給人的感覺就是很炫酷很流暢,起到增強用戶體驗的作用。在APP開發(fā)中實現(xiàn)動畫效果有很多種方式,對于簡單的應用場景,我們可以使用UIKit提供的動畫來實現(xiàn)。

UIView動畫簡介
UIView動畫實質上是對Core Animation的封裝,提供簡潔的動畫接口。

UIView動畫可以設置的動畫屬性有:
1、大小變化(frame)
2、拉伸變化(bounds)
3、中心位置(center)
4、旋轉(transform)
5、透明度(alpha)
6、背景顏色(backgroundColor)
7、拉伸內容(contentStretch)

一、UIview 類方法動畫
1、動畫的開始和結束方法
1.1 動畫開始標記
[UIView beginAnimations:(nullable NSString *) context:(nullable void *)];
第一個參數(shù):動畫標識
第二個參數(shù):附加參數(shù),在設置了代理的情況下,此參數(shù)將發(fā)送到setAnimationWillStartSelector和setAnimationDidStopSelector所指定的方法。大部分情況下,我們設置為nil即可。

1.2 結束動畫標記
[UIView commitAnimations];

2、動畫參數(shù)的設置方法
//動畫持續(xù)時間
[UIView setAnimationDuration:(NSTimeInterval)];
//動畫的代理對象
[UIView setAnimationDelegate:(nullable id)];
//設置動畫將開始時代理對象執(zhí)行的SEL
[UIView setAnimationWillStartSelector:(nullable SEL)];
//設置動畫結束時代理對象執(zhí)行的SEL
[UIView setAnimationDidStopSelector:(nullable SEL)];
//設置動畫延遲執(zhí)行的時間
[UIView setAnimationDelay:(NSTimeInterval)];
//設置動畫的重復次數(shù)
[UIView setAnimationRepeatCount:(float)];
//設置動畫的曲線
[UIView setAnimationCurve:(UIViewAnimationCurve)];
UIViewAnimationCurve的枚舉值如下:
UIViewAnimationCurveEaseInOut,         // 慢進慢出(默認值)
UIViewAnimationCurveEaseIn,            // 慢進
UIViewAnimationCurveEaseOut,           // 慢出
UIViewAnimationCurveLinear             // 勻速
//設置是否從當前狀態(tài)開始播放動畫
[UIView setAnimationBeginsFromCurrentState:YES];
假設上一個動畫正在播放,且尚未播放完畢,我們將要進行一個新的動畫:
當為YES時:動畫將從上一個動畫所在的狀態(tài)開始播放
當為NO時:動畫將從上一個動畫所指定的最終狀態(tài)開始播放(此時上一個動畫馬上結束)
//設置動畫是否繼續(xù)執(zhí)行相反的動畫
[UIView setAnimationRepeatAutoreverses:(BOOL)];
//是否禁用動畫效果(對象屬性依然會被改變,只是沒有動畫效果)
[UIView setAnimationsEnabled:(BOOL)];
//設置視圖的過渡效果
[UIView setAnimationTransition:(UIViewAnimationTransition) forView:(nonnull UIView *) cache:(BOOL)];
第一個參數(shù):UIViewAnimationTransition的枚舉值如下
UIViewAnimationTransitionNone,              //不使用動畫
UIViewAnimationTransitionFlipFromLeft,      //從左向右旋轉翻頁
UIViewAnimationTransitionFlipFromRight,     //從右向左旋轉翻頁
UIViewAnimationTransitionCurlUp,            //從下往上卷曲翻頁
UIViewAnimationTransitionCurlDown,          //從上往下卷曲翻頁
第二個參數(shù):需要過渡效果的View
第三個參數(shù):是否使用視圖緩存,YES:視圖在開始和結束時渲染一次;NO:視圖在每一幀都渲染

3、實例代碼:
1、屬性變化動畫(以frame變化為例)
- (void)changeFrame {
    [UIView beginAnimations:@"FrameAni" context:nil];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationWillStartSelector:@selector(startAni:)];
    [UIView setAnimationDidStopSelector:@selector(stopAni:)];
    [UIView setAnimationRepeatCount:1];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    self.cartCenter.frame = self.centerShow.frame;
    [UIView commitAnimations];
}

- (void)startAni:(NSString *)aniID {
    NSLog(@"%@ start",aniID);
}

- (void)stopAni:(NSString *)aniID {
    NSLog(@"%@ stop",aniID);
}
動畫效果:

NormalAni.gif

2、轉場效果動畫(以Flip效果為例)
- (void)flipAni {
    [UIView beginAnimations:@"FlipAni" context:nil];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationWillStartSelector:@selector(startAni:)];
    [UIView setAnimationDidStopSelector:@selector(stopAni:)];
    [UIView setAnimationRepeatCount:1];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.centerShow cache:YES];
    self.centerShow.image = [UIImage imageNamed:@"service"];
    [UIView commitAnimations];
}
動畫效果:

ScreenTransitionAni.gif

二、UIview Block動畫
iOS4.0以后,增加了Block動畫塊,提供更簡潔的方式來實現(xiàn)動畫。
1)Block動畫方法
1、最簡潔的Block動畫:包含時間和動畫
[UIView animateWithDuration:(NSTimeInterval)  //動畫持續(xù)時間

                 animations:^{

                     //執(zhí)行的動畫

                 }];

2、帶有動畫完成回調的Block動畫
[UIView animateWithDuration:(NSTimeInterval)  //動畫持續(xù)時間

                 animations:^{

                     //執(zhí)行的動畫

                 }                completion:^(BOOL finished) {

                     //動畫執(zhí)行完畢后的操作

                 }];

3、可設置延遲時間和過渡效果的Block動畫
[UIView animateWithDuration:(NSTimeInterval) //動畫持續(xù)時間
                      delay:(NSTimeInterval) //動畫延遲執(zhí)行的時間
                    options:(UIViewAnimationOptions) //動畫的過渡效果
                 animations:^{
                     //執(zhí)行的動畫
                 }                completion:^(BOOL finished) {
                     //動畫執(zhí)行完畢后的操作
                 }];

UIViewAnimationOptions的枚舉值如下,可組合使用:
UIViewAnimationOptionLayoutSubviews            //進行動畫時布局子控件
UIViewAnimationOptionAllowUserInteraction      //進行動畫時允許用戶交互
UIViewAnimationOptionBeginFromCurrentState     //從當前狀態(tài)開始動畫
UIViewAnimationOptionRepeat                    //無限重復執(zhí)行動畫
UIViewAnimationOptionAutoreverse               //執(zhí)行動畫回路
UIViewAnimationOptionOverrideInheritedDuration //忽略嵌套動畫的執(zhí)行時間設置
UIViewAnimationOptionOverrideInheritedCurve    //忽略嵌套動畫的曲線設置
UIViewAnimationOptionAllowAnimatedContent      //轉場:進行動畫時重繪視圖
UIViewAnimationOptionShowHideTransitionViews   //轉場:移除(添加和移除圖層的)動畫效果
UIViewAnimationOptionOverrideInheritedOptions  //不繼承父動畫設置

UIViewAnimationOptionCurveEaseInOut            //時間曲線,慢進慢出(默認值)
UIViewAnimationOptionCurveEaseIn               //時間曲線,慢進
UIViewAnimationOptionCurveEaseOut              //時間曲線,慢出
UIViewAnimationOptionCurveLinear               //時間曲線,勻速

UIViewAnimationOptionTransitionNone            //轉場,不使用動畫
UIViewAnimationOptionTransitionFlipFromLeft    //轉場,從左向右旋轉翻頁
UIViewAnimationOptionTransitionFlipFromRight   //轉場,從右向左旋轉翻頁
UIViewAnimationOptionTransitionCurlUp          //轉場,下往上卷曲翻頁
UIViewAnimationOptionTransitionCurlDown        //轉場,從上往下卷曲翻頁
UIViewAnimationOptionTransitionCrossDissolve   //轉場,交叉消失和出現(xiàn)
UIViewAnimationOptionTransitionFlipFromTop     //轉場,從上向下旋轉翻頁
UIViewAnimationOptionTransitionFlipFromBottom  //轉場,從下向上旋轉翻頁

4、spring動畫
iOS7.0后新增Spring動畫(ios系統(tǒng)動畫大部分采用Spring Animation,適用于所有可被添加動畫效果的屬性)
[UIView animateWithDuration:(NSTimeInterval)//動畫持續(xù)時間
                      delay:(NSTimeInterval)//動畫延遲執(zhí)行的時間
     usingSpringWithDamping:(CGFloat)//震動效果,范圍0~1,數(shù)值越小震動效果越明顯
      initialSpringVelocity:(CGFloat)//初始速度,數(shù)值越大初始速度越快
                    options:(UIViewAnimationOptions)//動畫的過渡效果
                 animations:^{
                     //執(zhí)行的動畫
                 }
                 completion:^(BOOL finished) {
                     //動畫執(zhí)行完畢后的操作
                 }];

5、Keyframes動畫
iOS7.0后新增關鍵幀動畫,支持屬性關鍵幀,不支持路徑關鍵幀
[UIView animateKeyframesWithDuration:(NSTimeInterval)//動畫持續(xù)時間
                               delay:(NSTimeInterval)//動畫延遲執(zhí)行的時間
                             options:(UIViewKeyframeAnimationOptions)//動畫的過渡效果
                          animations:^{
                              //執(zhí)行的關鍵幀動畫
                          }
                          completion:^(BOOL finished) {
                              //動畫執(zhí)行完畢后的操作
                          }];
UIViewKeyframeAnimationOptions的枚舉值如下,可組合使用:

UIViewAnimationOptionLayoutSubviews           //進行動畫時布局子控件
UIViewAnimationOptionAllowUserInteraction     //進行動畫時允許用戶交互
UIViewAnimationOptionBeginFromCurrentState    //從當前狀態(tài)開始動畫
UIViewAnimationOptionRepeat                   //無限重復執(zhí)行動畫
UIViewAnimationOptionAutoreverse              //執(zhí)行動畫回路
UIViewAnimationOptionOverrideInheritedDuration //忽略嵌套動畫的執(zhí)行時間設置
UIViewAnimationOptionOverrideInheritedOptions //不繼承父動畫設置

UIViewKeyframeAnimationOptionCalculationModeLinear     //運算模式 :連續(xù)
UIViewKeyframeAnimationOptionCalculationModeDiscrete   //運算模式 :離散
UIViewKeyframeAnimationOptionCalculationModePaced      //運算模式 :均勻執(zhí)行
UIViewKeyframeAnimationOptionCalculationModeCubic      //運算模式 :平滑
UIViewKeyframeAnimationOptionCalculationModeCubicPaced //運算模式 :平滑均勻
各種運算模式的直觀比較如下圖:

圖片來源網(wǎng)絡.png
增加關鍵幀的方法:

[UIView addKeyframeWithRelativeStartTime:(double)//動畫開始的時間(占總時間的比例)
                        relativeDuration:(double) //動畫持續(xù)時間(占總時間的比例)
                              animations:^{
                                  //執(zhí)行的動畫
                              }];

6、轉場動畫
6.1 從舊視圖轉到新視圖的動畫效果
[UIView transitionFromView:(nonnull UIView *)
                    toView:(nonnull UIView *)
                  duration:(NSTimeInterval)
                   options:(UIViewAnimationOptions)
                completion:^(BOOL finished) {
                    //動畫執(zhí)行完畢后的操作
                }];
在該動畫過程中,fromView 會從父視圖中移除,并講 toView 添加到父視圖中,注意轉場動畫的作用對象是父視圖(過渡效果體現(xiàn)在父視圖上)。
調用該方法相當于執(zhí)行下面兩句代碼:

[fromView.superview addSubview:toView];
[fromView removeFromSuperview];

6.2 單個視圖的過渡效果
[UIView transitionWithView:(nonnull UIView *)
                  duration:(NSTimeInterval)
                   options:(UIViewAnimationOptions)
                animations:^{
                    //執(zhí)行的動畫
                }
                completion:^(BOOL finished) {
                    //動畫執(zhí)行完畢后的操作
                }];

2)實例代碼:
1、普通動畫
下面三段代碼都實現(xiàn)了相同的視圖frame的變化,不同之處只在于其延遲時間、過渡效果和結束回調。
- (void)blockAni1 {
    [UIView animateWithDuration:1.0 animations:^{
        self.cartCenter.frame = self.centerShow.frame;
    }];
}
- (void)blockAni2 {
    [UIView animateWithDuration:1.0 animations:^{
        self.cartCenter.frame = self.centerShow.frame;
    } completion:^(BOOL finished) {
        NSLog(@"動畫結束");
    }];
}
- (void)blockAni3 {
    [UIView animateWithDuration:1.0 delay:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        self.cartCenter.frame = self.centerShow.frame;
    } completion:^(BOOL finished) {
        NSLog(@"動畫結束");
    }];
}
動畫效果:

NormalAni.gif

2、Spring動畫
- (void)blockAni4 {
    [UIView animateWithDuration:1.0 delay:0.f usingSpringWithDamping:0.5 initialSpringVelocity:5.0 options:UIViewAnimationOptionCurveLinear animations:^{
        self.cartCenter.frame = self.centerShow.frame;
    } completion:^(BOOL finished) {
        NSLog(@"動畫結束");
    }];
}
動畫效果:

SpringAni.gif

3、Keyframes動畫
這里以實現(xiàn)視圖背景顏色變化(紅-綠-藍-紫)的過程來演示關鍵幀動畫。
- (void)blockAni5 {
    self.centerShow.image = nil;
    [UIView animateKeyframesWithDuration:9.0 delay:0.f options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
        [UIView addKeyframeWithRelativeStartTime:0.f relativeDuration:1.0 / 4 animations:^{
            self.centerShow.backgroundColor = [UIColor colorWithRed:0.9475 green:0.1921 blue:0.1746 alpha:1.0];
        }];
        [UIView addKeyframeWithRelativeStartTime:1.0 / 4 relativeDuration:1.0 / 4 animations:^{
            self.centerShow.backgroundColor = [UIColor colorWithRed:0.1064 green:0.6052 blue:0.0334 alpha:1.0];
        }];
        [UIView addKeyframeWithRelativeStartTime:2.0 / 4 relativeDuration:1.0 / 4 animations:^{
            self.centerShow.backgroundColor = [UIColor colorWithRed:0.1366 green:0.3017 blue:0.8411 alpha:1.0];
        }];
        [UIView addKeyframeWithRelativeStartTime:3.0 / 4 relativeDuration:1.0 / 4 animations:^{
            self.centerShow.backgroundColor = [UIColor colorWithRed:0.619 green:0.037 blue:0.6719 alpha:1.0];
        }];
    } completion:^(BOOL finished) {
        NSLog(@"動畫結束");
    }];
}
動畫效果:

KeyFramesAni.gif

4、轉場動畫
4.1 單個視圖的過渡效果
- (void)blockAni6 {
    [UIView transitionWithView:self.centerShow duration:1.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
        self.centerShow.image = [UIImage imageNamed:@"Service"];
    } completion:^(BOOL finished) {
        NSLog(@"動畫結束");
    }];
}
動畫效果:

TransitionAni.gif

4.2 從舊視圖轉到新視圖的動畫效果
- (void)blockAni7 {
    UIImageView * newCenterShow = [[UIImageView alloc]initWithFrame:self.centerShow.frame];
    newCenterShow.image = [UIImage imageNamed:@"Service"];
    [UIView transitionFromView:self.centerShow toView:newCenterShow duration:1.0 options:UIViewAnimationOptionTransitionFlipFromLeft completion:^(BOOL finished) {
        NSLog(@"動畫結束");
    }];
}
動畫效果:

ScreenTransitionAni.gif
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 廢話不多說,直接上干貨 ---------------------------------------------...
    小小趙紙農(nóng)閱讀 3,687評論 0 15
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,656評論 30 472
  • /* UIViewController is a generic controller base class th...
    DanDanC閱讀 2,061評論 0 2
  • 離期末考試就剩一個多月了,給寶貝們準備了兩份禮物。如果新的學期,我還會教他們,那這兩份禮物就當作激勵,給進步最...
    簡單讀書胡亂唱歌閱讀 158評論 0 1
  • 我是通過一個很好很好的朋友,遇見了純天然。我喜歡純天然的東西,衣服喜歡森女系,蔬菜自家種的才放心,喝的水同樣喜歡鄉(xiāng)...
    安小鼠閱讀 318評論 0 0

友情鏈接更多精彩內容