你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> View Programming Guide for iOS 視圖編程指南 - iOS

View Programming Guide for iOS 視圖編程指南 - iOS

編輯:IOS開發綜合

1 有關 Windows and Views

每個應用都至少有一個 window 和一個 view。

1.1 添加額外的 Window

一般在有外界顯示設備的時候才需要添加額外的 window

下面的代碼舉了一個例子,這裡假定對象實現了方法 externalWindow,externalWindow 存儲一個 window 的引用

- (void)configureExternalDisplayAndShowWithContent:(UIViewController*)rootVC
{
   // Configure the content only if a second screen is available.
   if ([[UIScreen screens] count] > 1) {
      UIScreen* externalScreen = [[UIScreen screens] objectAtIndex:1];
      CGRect screenBounds = externalScreen.bounds;

      // Configure the window
      self.externalWindow = [[UIWindow alloc] initWithFrame:screenBounds];
      self.externalWindow.windowLevel = UIWindowLevelNormal;
      self.externalWindow.screen = externalScreen;

      // Install the root view controller
      self.externalWindow.rootViewController = rootVC;

      // Show the window, but do not make it key.
      self.externalWindow.hidden = NO;
   }
   else {
        // No external display available for configuration.
   }
}

2 View 和 Window 層級

2.1 View 層級原理

UIKit中的每個 view,底層都擁有一個 layer 對象,通常都是CALayer。大多數情況下都直接通過 UIView 操作;當需要更多控制的時候可以通過 layer 執行操作。

注意:bar button item 不是 view,所以不能直接訪問它的 layer。實際上 bar button item 是直接繼承自 NSObject,而 layer 是 UIView 中定義的,所以bar button item沒有。

 


\

 <喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPrrL0MS2r7utsuO74bbUIHZpZXe21M/zu+bWxrT6wuu1xMTayN29+NDQu7q05tbY08OjrNPIxuTKx9Ta09C2r7uttcTH6b/2z8KjrNbY08OxyNbY0MK0tL2o0ru49tDCtcTE2sjd18rUtM/7usTQobrctuChozwvcD4NCjxoMyBpZD0="211-視圖層級和子視圖管理">2.1.1 視圖層級和子視圖管理

如果子視圖是完全不透明的話,會遮蓋父視圖的內容。父視圖將子視圖存放在一個有序的數組中,所以後添加的(子視圖數組最後的)會在最上面顯示。

父視圖改變大小會引起子視圖的大小隨之變化,可以自定義這種變化。還有父視圖被隱藏、改變父視圖的透明度(alpha),或者對父視圖的坐標系統應用數學轉換等,都會影響到子視圖。

UIResponder 和它的子類可以響應事件,並處理事件,UIView就是繼承自 UIResponder。

 


\

 

點擊事件的響應是從上到下一層一層判斷的,如果最後沒有任何對象做出響應,通常就丟棄了。

2.1.2 視圖繪圖周期

第一次繪圖的時候系統保存一個繪圖內容的快拍(snapshot),如果之後再沒有對內容改動,那麼不會再調用繪圖代碼,都直接使用這個快拍;如果有了改動,就重新生成一個快拍,周而復始。

當視圖的內容或者外觀發生變化的時候可以使用 setNeedsDisplay 和 setNeedsDisplayInRect 方法進行重繪;注意如果改變了視圖的幾何形狀,這個方法就失效了。這兩個方法是等待當前 run loop 執行到最後的時候,再將剛才設置的所有重繪操作一次執行完成。

有關幾何形狀的變化,需要看下面的 Content Modes

UIView 的子類,通常重寫 drawRect: 方法,在這個方法裡面寫繪圖代碼。這個方法不需要自己調用。

2.1.3 Content Modes 內容模式

當發生下列兩種情況時,內容模式就會應用:

改變視圖的 frame 或者 bounds 矩形的寬或高。 指定一個轉換,比如視圖的 transform 屬性的縮放比例
@property(nonatomic)                 UIViewContentMode contentMode;                // default is UIViewContentModeScaleToFill
typedef NS_ENUM(NSInteger, UIViewContentMode) {
    UIViewContentModeScaleToFill,
    UIViewContentModeScaleAspectFit,      // contents scaled to fit with fixed aspect. remainder is transparent
    UIViewContentModeScaleAspectFill,     // contents scaled to fill with fixed aspect. some portion of content may be clipped.
    UIViewContentModeRedraw,              // redraw on bounds change (calls -setNeedsDisplay)
    UIViewContentModeCenter,              // contents remain same size. positioned adjusted.
    UIViewContentModeTop,
    UIViewContentModeBottom,
    UIViewContentModeLeft,
    UIViewContentModeRight,
    UIViewContentModeTopLeft,
    UIViewContentModeTopRight,
    UIViewContentModeBottomLeft,
    UIViewContentModeBottomRight,
};

 


\

 

UIViewContentModeRedraw 通常都不需要使用這個值,尤其在標准系統視圖中不要使用。

2.1.4 可伸縮的視圖

可以指定一個區域為可伸縮的,可以沿著一個軸或者兩個軸伸縮。下圖顯示了視圖自身顯示的失真

 


\

 

contentStretch 屬性用來指定可伸縮的區域。但是這個屬性iOS6之後被廢棄了,通常這個屬性都是用在 view 的背景 UIImage 對象,所以現在用 [UIImage resizableImageWithCapInsets:] 達到相同效果。

2.1.5 內嵌動畫的支持

執行動畫需要做兩件事:

告訴UIKit 你想要執行動畫 改變屬性的值

下面這些 UIView 對象的屬性都可以用作動畫:

frame 以動畫形式改變視圖的位置和大小 bounds 以動畫形式改變視圖的大小 center 以動畫形式改變視圖的位置 transform 旋轉或者伸縮視圖 alpha 改變視圖的透明度 backgroundColor 改變視圖的背景顏色

比如通常可以用導航欄控制器控制兩個視圖的轉換動畫,這是提供的標准動畫,當覺得達不到想要效果,就可以自定義。

還可以直接使用 Core Animation layers創建動畫。

2.2 視圖的幾何(Geometry)和坐標(Coordinate)系統

 


\

 

每個視圖和窗口都定義了自己的局部坐標系統。

2.2.1 Frame,Bounds 和 Center 屬性的關系

frame 屬性包含矩形框架,指定視圖的大小和在父視圖坐標系中的位置 bounds 屬性包含了矩形邊界,指定了在視圖自己局部的坐標系中視圖的大小(以及內容的邊界) center 屬性包含了父視圖坐標系中視圖的中點

 


\

 

下面3種情況,改變會有連鎖反應:

改變frame 屬性,bounds、center 屬性也會隨著改變 改變center 屬性,frame 的原點會改變 bounds 屬性的大小改變,frame 屬性也會改變

2.2.2 坐標系變換

利用仿射變換可以改變整個視圖的大小、位置或者方向。

transform 屬性可以修改變換方式,並且有動畫。

2.2.3 點像素

One point does not necessarily correspond to one pixel on the screen.

一個 point 並不一定和 一個像素相等,千萬不要有相等的假設。

2.2.4 視圖的運行交互模式

 


\

 

考慮下面幾種情況:

1.用戶觸摸屏幕

2.硬件給UIKit框架報告觸摸事件

3.UIKit 框架把觸摸事件包裝為一個 UIEvent 對象,並且分配給適當的視圖。

4.視圖的 event-handling 代碼響應事件。比如,你的代碼可以:

改變視圖或者子視圖屬性(frame,bounds,alpha 等等) 調用 setNeedsLayout 方法來標記需要布局更新的視圖或者子視圖。 調用 setNeedsDisplay 或者 setNeedsDisplayInRect: 方法來標記需要重繪的視圖或它的子視圖。 通知 controller 有關一些數據塊的修改

上面這都是由你來決定做哪些事情。

如果使用了手勢識別來處理事件,就不要重寫任何手勢識別的方法;同樣,如果視圖不包含任何子視圖或者它的大小沒有改變,不要重寫 layoutSubviews 方法;當你的視圖內容在運行時候需要改變,或者你正在使用比如Uikit或者Core Graphics的原生技術來進行繪圖時,才需要重寫 drawRect:

2.3 有效使用視圖的要點

自定義視圖需要考慮性能問題;優化繪圖代碼之前,先測量性能,然後定個性能標准再優化。

2.3.1 視圖並不需要總是對應一個試圖控制器

視圖控制器提供的功能比如:協調視圖在屏幕上的顯示,協調視圖在屏幕上的移動,釋放內存,旋轉視圖等。

2.3.2 盡可能少的進行自定義繪圖

2.3.3 內容模型的優勢

應該避免使用 UIViewContentModeRedraw。總是使用 setNeedsDisplay 或者 setNeedsDisplayInRect:

2.3.4 盡可能的將視圖聲明為不透明的

對於透明的渲染會增加性能的損耗。

2.3.5 當滾動的時候調整視圖的繪制行為

滾動的時候非常損耗性能,所以可以考慮在滾動的時候暫時降低內容的渲染質量。滾動停止的時候再恢復。

2.3.6 不同通過嵌入子視圖來自定義控件

永遠不要給系統控件自行添加視圖,這樣會導致很多錯誤發生。

3 Windows 窗口

這章節涉及內容不常用,用時再看 - Windows

窗口職責:

包含應用的可視化內容 在視圖觸摸事件和其他應用對象之間扮演遞送者 通常和視圖控制器協作,來適應方向的變化

3.1 涉及窗口的任務

Use the window object to convert points and rectangles to or from the window’s local coordinate system. Use window notifications to track window-related changes.

3.2 創建和配置窗口

3.2.1 用IB創建窗口

3.2.2 代碼創建窗口

3.2.3 給窗口添加內容

3.2.4 改變窗口層級

3.3 監視窗口的改變

UIWindowDidBecomeVisibleNotification UIWindowDidBecomeHiddenNotification UIWindowDidBecomeKeyNotification UIWindowDidResignKeyNotification

3.4 在額外的設備上顯示內容

3.4.1 處理屏幕連接和斷開通知

3.4.2 為額外的設備配置一個窗口

3.4.3為額外的設備配置屏幕模式

4 Views 視圖

view 的職責:

布局和子視圖管理:

view 定義它對於父視圖的默認 resize 行為 視圖可以管理一系列子視圖 視圖可以根據需要調整子視圖的大小和位置 視圖可以將它的坐標系轉化為其他視圖或者窗口的坐標系

繪制和動畫:

視圖在它的矩形區域繪制內容 view 的某些屬性可以以動畫的形式變換到新值

事件處理:

視圖可以收到觸摸事件 視圖可以參與到響應鏈

4.1 創建和配置視圖對象

4.1.1 使用IB創建視圖對象

可以查看 Resource Programming Guide

4.1.2 代碼創建view對象

CGRect  viewRect = CGRectMake(0, 0, 100, 100);
UIView* myView = [[UIView alloc] initWithFrame:viewRect];

4.1.3 設置view 的屬性

view 的一些關鍵屬性的用法

屬性 用法 aplha, hidden, opaque 這些屬性影響view 的透明度,alpha 和 hidden 屬性直接改變 view 透明度;opaque 屬性告訴系統是否應該混合視圖的顯示。設置為YES 可以提升性能。 bounds, frame, center, transform center 和 frame 屬性都和父視圖相關,而bounds屬性在自己的坐標系中定義了可視化內容區域。transform 屬性常用語動畫或者用復雜的方式移動 view。 autoresizingMask, autoresizesSubviews 這些屬性影響視圖和子視圖的自動 resieze 行為。autoresizingMask 屬性控制視圖在父視圖中如何響應變化。autoresizesSubviews 屬性控制是否當前視圖的子視圖要完全被 resize。 contentMode, contentStretch, contentScaleFactor 這些屬性影響 view 裡面內容的渲染行為。 gestureRecognizers, userInteractionEnabled, multipleTouchEnabled, exclusiveTouch 這些屬性影響 view 如何處理觸摸事件。 backgroundColor, subviews, drawRect:方法, layer, (layerClass 方法) 這些屬性和方法幫你管理 view 中的實際內容。

4.1.4 為以後的驗證標記 view

tag 可以用一個整數值來標記特定的 view。默認這個屬性為 0。

找到標記的view,可以使用 viewWithTag: 方法。

4.2 創建和管理 view 層級

4.2.1 添加和移除子視圖

addSubview: 方法直接添加到最上面。

- (void)removeFromSuperview;
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;
- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2;

- (void)addSubview:(UIView *)view;
- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview;
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;

- (void)bringSubviewToFront:(UIView *)view;
- (void)sendSubviewToBack:(UIView *)view;

4.2.2 隱藏 view

設置 hidden 屬性為 YES,或者將alpha 屬性設置為 0.0。隱藏view 之後就不能收到觸摸事件了。

如果要以動畫形式將view 從可視化到隱藏,必須使用 alpha 屬性。hidden 屬性不是可動畫的

4.2.3 從 view 層級中找出視圖

兩種方式:

存儲相應視圖的指針,比如 view controller 擁有視圖的方式 給 view 的 tag 屬性賦值,但數字要獨一無二;然後用 viewWithTag: 方法拿到

4.2.4 轉變,伸縮,旋轉 view

// M_PI/4.0 is one quarter of a half circle, or 45 degrees.
CGAffineTransform xform = CGAffineTransformMakeRotation(M_PI/4.0);
self.view.transform = xform;

 


\

 

4.2.5 在視圖層級中轉換坐標

UIView 定義了下面幾種方法在view 的局部坐標系中轉換坐標

convertPoint:fromView: convertRect:fromView: convertPoint:toView: convertRect:toView:

類似,UIWindow也定義了幾個轉換方法:

convertPoint:fromWindow: convertRect:fromWindow: convertPoint:toWindow: convertRect:toWindow:

 


\

 

4.3 在運行時調整 view 的大小和位置

UIView 支持自動和手動布局

4.3.1 為布局改變做准備

當 view 中有下面幾種事件發生的時候,布局需要改變:

view 的 bound 矩形大小發生變化 界面的方法發生變化,這通常會觸發根視圖的 bound 矩形變化 與 view layer相關的 Core Animation sublayer 的集合發生變化,並要求 layout 調用view 的 setNeedsLayout 或者 layoutIfNeeded 方法,讓應用強制布局 調用view的 layer對象的 setNeedsLayout 方法,讓應用強制布局

4.3.2 使用自動調整大小規則讓布局自動變化

設置父視圖 autoresizesSubviews 屬性來決定子視圖是否需要調整大小。如果這個屬性為 YES,每個子視圖的 autoresizingMask 屬性決定如何變化。

Autoresizing mask 描述 UIViewAutoresizingNone 默認值,view不會自動調整大小 UIViewAutoresizingFlexibleHeight 當父視圖的高變化的時候,視圖的高也會變化。如果沒有包含這個常量,視圖的高不變 UIViewAutoresizingFlexibleWidth 當父視圖的寬變化的時候,視圖的寬也會變化。如果沒有包含這個常量,視圖的寬不變 UIViewAutoresizingFlexibleLeftMargin 視圖左邊界與父視圖左邊界的距離會按需要增大或減小。如果沒有包含這個常量,將維持固定的距離 UIViewAutoresizingFlexibleRightMargin 視圖右邊界與父視圖右邊界的距離會按需要增大或減小。如果沒有包含這個常量,將維持固定的距離 UIViewAutoresizingFlexibleBottomMargin 視圖下邊界與父視圖下邊界的距離會按需要增大或減小。如果沒有包含這個常量,將維持固定的距離 UIViewAutoresizingFlexibleTopMargin 視圖上邊界與父視圖上邊界的距離會按需要增大或減小。如果沒有包含這個常量,將維持固定的距離

 


\

 

4.3.3 手動調整視圖布局

在自定義 view 中,如果自動布局行為沒有達到期望要求,可以實現 layoutSubviews ,可以下面幾件事:

調整任何當前子視圖的大小和位置 添加移除子視圖或者核心動畫層(Core Animation layers) 調用 setNeedsDisplay 或者 setNeedsDisplayInRect: 方法強制子視圖重繪

有大片滾動區域的時候應用會經常手動布局子視圖。

寫布局代碼的時候測試代碼對於下面情況是否完善:

view方向改變的時候,確保布局對於所有支持方向都是正確的 確保你的代碼對於 status bar高度的變化有適當的響應。

4.4 運行時修改視圖

在 view controller 中:

view controller 在顯示 view 之前創建它們,可以從 nib 文件 load view 或者用代碼創建它們。但這些views 不在需要的時候,銷毀它們 當設備方向改變的時候, view controller 可能調整view 的大小和位置來匹配。對於新的方向,可能會隱藏一些view並且顯示另外一些view view controller 管理可編輯的內容,可能添加一下額外的按鈕,使得編輯更加的方便

4.5 與 Core Animation Layers 交互

每個 view 的專屬 layer 屬性。

4.5.1 改變 Layer 類關聯的視圖

view 被創建之後 layer關聯view 的類型就不能改變了,每個 view 使用 layerClass 類方法指定 layer 對象的類,這個方法默認實現返回的是 CALayer 類,只能在子類中改變這個值,重寫方法,返回一個不同的值。

view 將自己設置為它的layer對象的代理;view 擁有它的layer。view 和 layer 之間的關系不能改變。

4.5.2 在 view 中 嵌入 Layer 對象

自定義 layer 對象可以是任何 CALayer 的實例,不被任何 view擁有。自定義 layer 不能接收時間,或者參與到響應鏈中,但是可以繪制自己,並且可以響應父視圖的大小變化或者根據核心動畫層規則響應。

給 view 添加自定義 layer 的實例代碼:

- (void)viewDidLoad {
    [super viewDidLoad];

    // Create the layer.
    CALayer* myLayer = [[CALayer alloc] init];

    // Set the contents of the layer to a fixed image. And set
    // the size of the layer to match the image size.
    UIImage layerContents = [[UIImage imageNamed:@"myImage"] retain];
    CGSize imageSize = layerContents.size;

    myLayer.bounds = CGRectMake(0, 0, imageSize.width, imageSize.height);
    myLayer = layerContents.CGImage;

    // Add the layer to the view.
    CALayer*    viewLayer = self.view.layer;
    [viewLayer addSublayer:myLayer];

    // Center the layer in the view.
    CGRect        viewBounds = backingView.bounds;
    myLayer.position = CGPointMake(CGRectGetMidX(viewBounds), CGRectGetMidY(viewBounds));

    // Release the layer, since it is retained by the view's layer
    [myLayer release];
}

4.6 定義自定義 view

4.6.1 自定義視圖的實現清單

自定義視圖需要注意下面這些情況:

為 view 定義適當的初始化方法:
對於想要用代碼創建 view,需要重寫 initWithFrame: 方法或者定義一個自定義初始化方法 對於想要從 nib 文件中 加載view,需要重寫 initWithCoder: 方法。使用這個方法初始化你的view並把它放入一個已知狀態。 實現dealloc 方法,來處理自定義數據的清理 為了處理自定義的繪制,重寫 drawRect: 方法並且在方法中進行繪制 設置視圖 autoresizingMask 屬性來定義它的自動調整大小行為。 如果你的 view class 管理一個或多個必需的子視圖:
視圖的初始化過程中創建這些子視圖。 創建的時候設置每個子視圖的 autoresizingMask 屬性 如果子視圖要求自定義布局,重寫 layoutSubviews 方法,並實現你的布局 為了處理基於觸摸的事件:
使用 addGestureRecognizer 方法給view添加合適的手勢識別 為了處理觸摸事件,重寫 touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:, touchesCancelled:withEvent: 方法。(不管有沒有重寫其他觸摸方法,應該總是要重寫 touchesCancelled:withEvent: 方法) 如果想要view 的打印版本再不同的屏幕版本上看起來不同,需要實現 drawRect:forViewPrintFormatter: 方法。詳情看 Drawing and Printing Guide for iOS.

4.6.2 初始化自定義 view

view 應該包含 initWithFrame: 方法。

- (id)initWithFrame:(CGRect)aRect {
    self = [super initWithFrame:aRect];
    if (self) {
          // setup the initial properties of the view
          ...
       }
    return self;
}

4.6.3 實現自己的繪圖代碼

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect    myFrame = self.bounds;

    // Set the line width to 10 and inset the rectangle by
    // 5 pixels on all sides to compensate for the wider line.
    CGContextSetLineWidth(context, 10);
    CGRectInset(myFrame, 5, 5);

    [[UIColor redColor] set];
    UIRectFrame(myFrame);
}

4.6.4 響應事件

4.6.5 使用view 之後清理

5 Animations 動畫

5.1 什麼可以變為動畫?

下面是UIView中可以用於動畫的一些屬性:

frame bounds center transform alpha backgroundColor contentStretch

使用 Core Animation 可以對view 的layer 做下面類型的變化:

layer 大小和位置 當執行過渡時候,使用的中點 在 3D 空間中 layer或者 sublayer 的變化 從 layer 層級中添加或者移除 layer 對於其他同級layer 的Z軸順序 layer 的陰影 layer 的邊界(包含邊角是否是圓角) resize操作時候 layer 的部分伸縮 layer 的不透明度 在 layer邊界外面部分的裁剪行為 layer 的當前內容 layer 的光柵線

5.2 視圖中的動畫屬性變化

5.2.1 使用基於 block 的方法開始動畫

下面有3個類方法:

animateWithDuration:animations: animateWithDuration:animations:completion: animateWithDuration:delay:options:animations:completion:

這些方法都是開了新線程執行動畫,以防阻塞當前線程或者主線程。

[UIView animateWithDuration:1.0 animations:^{
        firstView.alpha = 0.0;
        secondView.alpha = 1.0;
}];

上面方法只是慢進慢出的單一動畫形式,想要復雜的,必須使用 animateWithDuration:delay:options:animations:completion: 方法,可以自定義下面動畫參數:

開始動畫前的延遲 動畫期間所使用的時序曲線類型 動畫應該重復的次數 動畫達到末尾的時候是否應該自動反轉 動畫進行的時候時候view 是否接收觸摸事件 當前動畫是否可以中斷正在進行的任何其他動畫,或者是等到其他都完成再開始

下面代碼設置了漸隱動畫,並且使用 completion handler,這是連接多個動畫的基本方式

- (IBAction)showHideView:(id)sender
{
    // Fade out the view right away
    [UIView animateWithDuration:1.0
        delay: 0.0
        options: UIViewAnimationOptionCurveEaseIn
        animations:^{
             thirdView.alpha = 0.0;
        }
        completion:^(BOOL finished){
            // Wait one second and then fade in the view
            [UIView animateWithDuration:1.0
                 delay: 1.0
                 options:UIViewAnimationOptionCurveEaseOut
                 animations:^{
                    thirdView.alpha = 1.0;
                 }
                 completion:nil];
        }];
}

5.2.2 使用 Begin/Commit 方法開始動畫

這是 iOS 3.2 之前使用的方法。。。

執行簡單的 begin/commit 動畫

    [UIView beginAnimations:@"ToggleViews" context:nil];
    [UIView setAnimationDuration:1.0];

    // Make the animatable changes.
    firstView.alpha = 0.0;
    secondView.alpha = 1.0;

    // Commit the changes and perform the animation.
    [UIView commitAnimations];

配置動畫參數:

// This method begins the first animation.
- (IBAction)showHideView:(id)sender
{
    [UIView beginAnimations:@"ShowHideView" context:nil];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(showHideDidStop:finished:context:)];

    // Make the animatable changes.
    thirdView.alpha = 0.0;

    // Commit the changes and perform the animation.
    [UIView commitAnimations];
}

// Called at the end of the preceding animation.
- (void)showHideDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
    [UIView beginAnimations:@"ShowHideView2" context:nil];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationDelay:1.0];

    thirdView.alpha = 1.0;

    [UIView commitAnimations];
}

5.2.3 配置動畫代理

如果想要在動畫開始前或者結束後立即執行代碼,就需要將代理對象和 start or stop selector,與 begin/commit 動畫塊聯結起來。使用UIView的類方法 setAnimationDelegate: 設置代理對象。使用 setAnimationWillStartSelector: 和 setAnimationDidStopSelector: 類方法設置開始和結束的 selector。

類似下面的代碼:

- (void)animationWillStart:(NSString *)animationID context:(void *)context;

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context;

在基於 block 的動畫方法中不需要使用上面這種形式。直接在動畫block之前放置想要在動畫前執行的代碼,在 completion handler 裡面放置想要在動畫結束後執行的代碼。

5.2.4 嵌套動畫 block

被嵌套的動畫與父動畫同一時間開始,但可以以自己的配置選項運行。默認被嵌套的動畫繼承了父動畫的持續時間和動畫曲線。

有不同配置的嵌套動畫

[UIView animateWithDuration:1.0
        delay: 1.0
        options:UIViewAnimationOptionCurveEaseOut
        animations:^{
            aView.alpha = 0.0;

            // Create a nested animation that has a different
            // duration, timing curve, and configuration.
            [UIView animateWithDuration:0.2
                 delay:0.0
                 options: UIViewAnimationOptionOverrideInheritedCurve |
                          UIViewAnimationOptionCurveLinear |
                          UIViewAnimationOptionOverrideInheritedDuration |
                          UIViewAnimationOptionRepeat |
                          UIViewAnimationOptionAutoreverse
                 animations:^{
                      [UIView setAnimationRepeatCount:2.5];
                      anotherView.alpha = 0.0;
                 }
                 completion:nil];

        }
        completion:nil];

5.2.5 實現動畫的逆行

5.3 在view 之間創建動畫過渡

不要把 view transition 和 view controller 的變換搞混,view transition 只是影響 view 層級

5.3.1 改變視圖的子視圖

transitionWithView:duration:options:animations:completion: 方法。UIViewAnimationOptionAllowAnimatedContent 設置選項。

將空的文本視圖與現有的進行交換

- (IBAction)displayNewPage:(id)sender
{
    [UIView transitionWithView:self.view
        duration:1.0
        options:UIViewAnimationOptionTransitionCurlUp
        animations:^{
            currentTextView.hidden = YES;
            swapTextView.hidden = NO;
        }
        completion:^(BOOL finished){
            // Save the old text and then swap the views.
            [self saveNotes:temp];

            UIView*    temp = currentTextView;
            currentTextView = swapTextView;
            swapTextView = temp;
        }];
}

5.3.2 替換view

只是交換兩個 view,不是 view controllers。

一個 view controller 中兩個 view 之間的開關

- (IBAction)toggleMainViews:(id)sender {
    [UIView transitionFromView:(displayingPrimary ? primaryView : secondaryView)
        toView:(displayingPrimary ? secondaryView : primaryView)
        duration:1.0
        options:(displayingPrimary ? UIViewAnimationOptionTransitionFlipFromRight :
                    UIViewAnimationOptionTransitionFlipFromLeft)
        completion:^(BOOL finished) {
            if (finished) {
                displayingPrimary = !displayingPrimary;
            }
    }];
}

5.4 將多個動畫連接在一起

5.5 Animating View and Layer Changes Together

下面代碼顯示了同時修改view 和 自定義 layer 的動畫。例子中的 view 包含了一個自定義 CALayer ,在view 的 bounds 中央。當順時針旋轉 layer 時,逆時針旋轉 view。

Mixing view and layer animations

[UIView animateWithDuration:1.0
    delay:0.0
    options: UIViewAnimationOptionCurveLinear
    animations:^{
        // Animate the first half of the view rotation.
        CGAffineTransform  xform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-180));
        backingView.transform = xform;

        // Rotate the embedded CALayer in the opposite direction.
        CABasicAnimation*    layerAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
        layerAnimation.duration = 2.0;
        layerAnimation.beginTime = 0; //CACurrentMediaTime() + 1;
        layerAnimation.valueFunction = [CAValueFunction functionWithName:kCAValueFunctionRotateZ];
        layerAnimation.timingFunction = [CAMediaTimingFunction
                        functionWithName:kCAMediaTimingFunctionLinear];
        layerAnimation.fromValue = [NSNumber numberWithFloat:0.0];
        layerAnimation.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(360.0)];
        layerAnimation.byValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(180.0)];
        [manLayer addAnimation:layerAnimation forKey:@"layerAnimation"];
    }
    completion:^(BOOL finished){
        // Now do the second half of the view rotation.
        [UIView animateWithDuration:1.0
             delay: 0.0
             options: UIViewAnimationOptionCurveLinear
             animations:^{
                 CGAffineTransform  xform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-359));
                 backingView.transform = xform;
             }
             completion:^(BOOL finished){
                 backingView.transform = CGAffineTransformIdentity;
         }];
}];

蘋果官方文檔地址:View Programming Guide for iOS

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved