iOS中如何創建一個滑出式導航面板(1)
iOS中如何創建一個滑出式導航面板(1)
_________________
本文由破船譯自:raywenderlich
轉載請注明出處:BeyondVincent的博客
_________________
本文將介紹如何創建類似非死book和Path iOS程序中的滑出式導航面板。
滑出式設計模式可以讓開發者在程序中添加常用的導航功能,而又不會浪費屏幕上寶貴的空間。用戶可以在任意時間滑出導航面板,并且還可以看到當前屏幕上顯示的內容。
現在,互聯網上已經有一些庫已經內置滑出式設計模式,比如John-Lluch開發的SWRevealViewController。如果你在尋找更加快捷和簡單的方法,那么使用SWRevealViewController庫可能是一個很不錯的方法。
不過,如果你是一名DIY類型的程序員(像我),那么你可能希望自己理解這功能是如何實現的。
在本文中,你會看到該功能的實現并不復雜。通過少即是多的方法,并忽略掉復雜大的且不是必須的代碼,就可以輕松的在程序中集成滑出式導航面板技術。
下面,就開始學習如何做滑出式導航面板——附帶手勢滑出的功能!
開始
那么這里創建的滑出式導航面板的功能具體是什么呢?
iOS設計師和開發者Ken Yarmosh的解釋比較恰當:“滑出式導航面板擁有一個面板,這個面板從主畫面的左邊或者右邊滑出來,然后在面板中顯示一個垂直的、獨立的滾動視圖(Scroll view),把該視圖當作程序的主導航。”
注意: Ken在這里的文章中詳細的解釋了滑出式導航面板的設計模式,并介紹了該模式帶來的好處:新的iOS設計模式:滑出式導航面板。
首先下載本文的啟動工程。這是一個ZIP文件,只需要將其保存到本地,并解壓一下就可以得到工程。
接著在Xcode中打開這個工程,并看看工程的組織結構:
工程被分為3個主要的文件夾:
- Assets: 包含所有的圖片文件和其它非代碼資源(例如attribution文件)。
- Views: 包含本文涉及到的所有xib文件。
- Classes: 包含Objective-C代碼文件
不要擔心Assets中有許多文件,其實你并不需要修改這些內容,所有需要用到的資源文件都添加進來了。
在Views文件夾中有4個主要的view controller。下面是相關簡介:
- MainViewController: 這是主要的一個畫面!這個文件需要添加到你自己的工程中(需要一些小的改動)。
- CenterViewController: 這是正中間的面板。該view controller可以替換為你自己的view controller(記住按鈕的action也實現了)
- LeftPanelViewController: 左邊的面板。該view controller可以替換為你自己的view controller。
- RightPanelViewController: 右邊的面板。該view controller可以替換為你自己的view controller
現在打開AppDelegate.m文件。雖然你不需要對這個文件做任何改變,但是你應該知道MainViewContorller是左,中和右view controller的容器。這個controller的初始化在19行代碼中:
self.viewController = [[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil];
現在,你已經對工程的結構熟悉了, 下面我們就正在的開始啦——從正中間的面板開始。
找到中心
本小節中,我將在MainViewConroller中放置一個CenterViewController,將CenterViewController當做MainViewConroller的子view controller。
注意:本小節會用到iOS 5中的新增的一個概念:View Controller Containment。如果你還不熟悉這個概念,可以看看iOS 5 by Tutorials中的第22章“UIViewController Containment”。
打開MainViewController.m文件,并將下面的import語句添加到文件的頂部:
#import "CenterViewController.h"
接著,添加一個常量定義:
#define CENTER_TAG 1
接著在@interface中添加下面這個屬性,以方便控制center view。
@property (nonatomic, strong) CenterViewController *centerViewController;
找到setupView并在里面添加如下代碼塊:
self.centerViewController = [[CenterViewController alloc] initWithNibName:@"CenterViewController" bundle:nil]; self.centerViewController.view.tag = CENTER_TAG; self.centerViewController.delegate = self; [self.view addSubview:self.centerViewController.view]; [self addChildViewController:_centerViewController]; [_centerViewController didMoveToParentViewController:self];
上面的代碼分配了一個新的CenterViewController并將其賦值給centerViewController屬性。然后將這個view controller view的tag設置為CENTER_TAG。
接著將delegate設置為MainViewController。也就意味著你需要對MainViewController進行修改,以遵循 CenterViewControllerDelegate協議——只需要將文件頂部@interface代碼行替換為如下即可:
@interface MainViewController ()
最后,在setupView方法的代碼中,使用addSubview:方法將centerViewController的view添加到 MainViewController的view中,另外還調用了addChildViewContoller:將 _centerViewController添加為MainViewController的子view controller。最后調用了didMoveToParentViewController:方法。
現在就編譯并運行程序的話,可以看到類似如下的畫面:
在畫面頂部的按鈕可以讓你切換到小貓(kitties)和小狗(puppies)。有什么更好的理由需要在這里創建一個滑出式的導航面板呢?在這里要想看到不同的小動物,那就開始滑動吧。首先從左邊開始!
靠向左邊
現在已經添加好了center panel,不過要添加left view controller需要一些不同的操作。
回到MainViewController.m文件中,并將下面的import語句添加到文件頂部:
#import "LeftPanelViewController.h"
然后再定義一個常量:
#define LEFT_PANEL_TAG 2
接著在@interface中添加一些屬性,這跟center view類似:
@property (nonatomic, strong) LeftPanelViewController *leftPanelViewController; @property (nonatomic, assign) BOOL showingLeftPanel;
現在找到getLeftView方法,刪除掉已有的代碼并添加如下代碼:
// init view if it doesn't already exist
if (_leftPanelViewController == nil)
{
// this is where you define the view for the left panel
self.leftPanelViewController = [[LeftPanelViewController alloc] initWithNibName:@"LeftPanelViewController" bundle:nil];
self.leftPanelViewController.view.tag = LEFT_PANEL_TAG;
self.leftPanelViewController.delegate = _centerViewController;
[self.view addSubview:self.leftPanelViewController.view];
[self addChildViewController:_leftPanelViewController];
[_leftPanelViewController didMoveToParentViewController:self];
_leftPanelViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
self.showingLeftPanel = YES;
// set up view shadows
[self showCenterViewWithShadow:YES withOffset:-2];
UIView *view = self.leftPanelViewController.view;
return view; 上面的代碼首先檢查一下看看leftPanelViewController屬性是否為nil,如果是nil的話,就分配并初始化一個LeftPanelViewController給leftPanelViewController屬性。
接著是賦值一個tag和delegate——用于圖片的選擇,以及將新創建的view添加到main view中。
然后將showingLeftPanel屬性設置為YES,并添加了一些視覺上的處理,在下一節中將介紹相關內容。
最后將view返回給調用者。為什么要這樣操作——在后面小節中你將看到為什么。
下面,我們來處理一下陰影。
不要忘記陰影效果
在上面剛剛添加的代碼中,你已經看到調用了showCenterViewWithShow:withOffset:方法。該方法使用QuartzCore框架創建并添加一個陰影效果。
為了訪問該框架的提供的許多精彩功能,將下面的import語句添加到MainViewController.m文件頂部:
#import <QuartzCore/QuartzCore.h>
同樣,在文件頂部定義一個常量,代表圓角。這樣,如果你想要修改圓角的話,只需要在一個地方修改即可。
#define CORNER_RADIUS 4
現在找到showCenterViewWithShadow:withOffset: 方法,并將下面的代碼塊添加進去:
if (value)
{
[_centerViewController.view.layer setCornerRadius:CORNER_RADIUS];
[_centerViewController.view.layer setShadowColor:[UIColor blackColor].CGColor];
[_centerViewController.view.layer setShadowOpacity:0.8];
[_centerViewController.view.layer setShadowOffset:CGSizeMake(offset, offset)];
}
else
{
[_centerViewController.view.layer setCornerRadius:0.0f];
[_centerViewController.view.layer setShadowOffset:CGSizeMake(offset, offset)];
} 上面的代碼中,如果傳遞過進來的value是非零,就會給center view設置一個圓角和一個陰影。否則就將圓角設置為非圓形。
如果現在運行程序的話,還看不到效果,因為上面的代碼還沒有用到。
現在回到左邊
現在已經獲得了滑動導航面板所需的一些材料了,接著繼續完成left view controller。一旦完成之后,右邊如何移動你也會清楚了。
本文中,為了將注意力幾種在重要的地方,我已經把IB文件中涉及到的IBAction和IBOutlet連接好了。不過,為了實現你自己的DIY滑出式導航面板,你需要知道這些IB中的按鈕是如何配置的。
看看下面這個張關于截圖CenterViewController.xib文件的截圖,注意其中的連接:
如上圖中的kitties按鈕,已經連接到一個名為leftButton的IBOutlet上了,并且這個按鈕的Touch Up Inside事件連接到了一個名為btnMovePanelRight:的IBAction上。這個按鈕控制著center panel的滑動,以顯示出左邊的panel。
btnMovePanelRight:現在還是空的,下面我們就來看看如何實現:
打開CenterViewController.m文件,并將下面的代碼塊添加到btnMovePanelRight:方法中:
UIButton *button = sender;
switch (button.tag) {
case 0: {
[_delegate movePanelToOriginalPosition];
break;
}
case 1: {
[_delegate movePanelRight];
break;
}
default:
break;
} 上面的代碼使用了一個switch語句,通過判斷leftButton的tag屬性來確定center panel是需要移動到右邊,還是需要將其移動到原來的正中間位置。這里的leftButton是通過sender參數傳遞過來的。button的tag 設置為0表示center panel已經移動到右邊了,如果設置為1的話,表示center panel已經在原來的正中間位置。
如果你看一下CenterViewController.xib文件,會看到我已經將leftButton的tag默認值設置為1。
看到上面的代碼中調用了delegate方法嗎?如果你還記得的話,之前在配置CenterViewController示例時,已經將它的 delegate設置為MainViewController。因此這里的調用就涉及到了MainViewController中的相關方法。
在實現這些delegate方法之前,首先看看CenterViewController.h文件中協議CenterViewControllerDelegate的定義:
如下圖所示,協議中定義了兩個optional協議方法,以及一個required協議方法,分別是:movePanelLeft, movePanelRight 和 movePanelToOriginalPosition。
因為CenterViewController的delegate是MainViewController,所以我們在MainViewController中添加這些delegate方法。
打開MainViewController.m文件,并添加如下兩個常量定義:
#define SLIDE_TIMING .25 #define PANEL_WIDTH 60
接著找到movePanelRight方法,并將如下代碼塊添加到里面:
UIView *childView = [self getLeftView];
[self.view sendSubviewToBack:childView];
[UIView animateWithDuration:SLIDE_TIMING delay:0 options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
_centerViewController.view.frame = CGRectMake(self.view.frame.size.width - PANEL_WIDTH, 0, self.view.frame.size.width, self.view.frame.size.height);
}
completion:^(BOOL finished) {
if (finished) {
_centerViewController.leftButton.tag = 0;
}
}]; 注意:這個方法是由CenterViewController中的btnMovePanelRight:調用的。更多如何實現delegate相關的信息,請參考:蘋果開發者文檔。
上面的代碼就是奇跡發生的地方!:]
首先調用getLeftView方法,該方法返回一個view,然后將view推到背后,接著是進入動畫處理過程:使用一個 animateWithDuration:animations:completion: 塊。在動畫中使用到的SLIDE_TIMING和PANEL_WIDTH值可以隨意調整。其中SLIDE_TIMING是控制動畫的速度,而 PANEL_WIDTH是控制動畫過后,center view留在屏幕中的寬度。
另外,記住海的把leftButton的tag屬性設置為0。如果你還記得的話,這個tag屬性用來跟蹤記錄center view的當前位置。
現在編譯并運行一下程序,看看效果如何。
當程序啟動后,點擊kitties按鈕,center panel應該會滑動到右邊,并顯示出left panel。此時,屏幕上顯示的效果如下圖所示:
注意觀察center view左邊緣的圓角和陰影——這兩個效果是執行showCenterViewWithShadow:withOffset:(之前添加的方法)方法得到的結果。
再點擊一下kitties按鈕——什么事情都沒有發生。這是因為還沒有實現movePanelToOriginalPosition方法。
回到MainViewController.m文件,并將下面的代碼塊添加到movePanelToOriginalPosition方法中:
[UIView animateWithDuration:SLIDE_TIMING delay:0 options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
_centerViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
completion:^(BOOL finished) {
if (finished) {
[self resetMainView];
}
}]; 同樣,在上面的代碼中使用了一個animateWithDuration:animations:completion: 塊來處理動畫。不過這次是將center view的位置以動畫的方式設置為最初的位置。
當動畫完成的時候,調用了resetMainView方法。目前該方法還沒有具體的實現。在該方法中需要重置一下view,下面我們來實現一下吧!
找到resetMainView方法,并將下面的代碼添加到方法中:
// remove left view and reset variables, if needed
if (_leftPanelViewController != nil)
{
[self.leftPanelViewController.view removeFromSuperview];
self.leftPanelViewController = nil;
_centerViewController.leftButton.tag = 1;
self.showingLeftPanel = NO;
}
// remove view shadows
[self showCenterViewWithShadow:NO withOffset:0]; 上的代碼將left panel從view中移除,并將kitties按鈕重置為1(表示center view目前是在最初的位置),另外還移除了center view的圓角和陰影效果。
編譯并運行程序,當點擊kitties按鈕后,再次點擊kitties按鈕,center view會回到最初的位置,如下圖所示:
下面,在右邊添加相關的功能——小狗!——請閱讀如何創建一個滑出式導航面板(2)








