iOS中如何創建一個滑出式導航面板(2)

jopen 11年前發布 | 11K 次閱讀 IOS iOS開發 移動開發

iOS中如何創建一個滑出式導航面板(2)

_________________

本文由破船譯自:raywenderlich
轉載請注明出處:BeyondVincent的博客
_________________

接著上一篇如何創建一個滑出式導航面板(1)

現在靠向右邊

MainViewController.m文件中,將下面的import語句添加到文件頂部:

#import "RightPanelViewController.h"

然后添加下面的常量定義:

#define RIGHT_PANEL_TAG 3

接著在@interface里面添加如下屬性,這樣就容易獲取到right view和它的當前狀態:

@property (nonatomic, strong) RightPanelViewController *rightPanelViewController;
@property (nonatomic, assign) BOOL showingRightPanel;

然后是找到getRightView方法,并移除里面已有的代碼,然后添加下面的代碼進去:

// init view if it doesn't already exist
if (_rightPanelViewController == nil)
{
    // this is where you define the view for the right panel
    self.rightPanelViewController = [[RightPanelViewController alloc] initWithNibName:@"RightPanelViewController" bundle:nil];
    self.rightPanelViewController.view.tag = RIGHT_PANEL_TAG;
    self.rightPanelViewController.delegate = _centerViewController;

    [self.view addSubview:self.rightPanelViewController.view];

    [self addChildViewController:self.rightPanelViewController];
    [_rightPanelViewController didMoveToParentViewController:self];

    _rightPanelViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}

self.showingRightPanel = YES;

// set up view shadows
[self showCenterViewWithShadow:YES withOffset:2];

UIView *view = self.rightPanelViewController.view;
return view;

上面的代碼是拷貝getLeftView的,只不過其中的類和屬性不同而已。如果對上面的代碼有任何疑問,可以回頭看看之前的解釋。

跟之前的一樣,在xib文件中已經連接好了相關的IBAction和IBOutlet。下面是CenterViewController.xib文件的一個截圖,顯示出了puppies按鈕的連接關系:

如上圖所示,跟kitties按鈕類似,puppies按鈕連接到的IBOutlet是rightButton,IBAction是btnMovePanelLeft:。這個按鈕控制著center panel的滑動以顯示出右邊的panel。

下面我們就來讓panel移動起來吧。

打開CenterController.m文件,并將下面的代碼添加到btnMovePanelLeft:中:

UIButton *button = sender;    
switch (button.tag) {
    case 0: {
        [_delegate movePanelToOriginalPosition];
        break;
    }

    case 1: {
        [_delegate movePanelLeft];
        break;
    }

    default:
        break;
}

同樣,上面的代碼與btnMovePanelRight:方法的實現沒有什么不同。可以看到delegate的調用方法幾乎是一樣的。

因為之前已經實現了movePanelToOriginalPostion方法,所以剩下的任務只需要添加movePanelLeft 方法,并修改一下resetMainView以處理right panel即可。

 

將右邊顯示出來

打開MainViewController.m文件,并將下面的代碼添加到movePanelLeft:方法中:

UIView *childView = [self getRightView];
[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.rightButton.tag = 0;
                    }
                }];

上面的代碼與movePanelRight方法中的基本相同,這里就不再做過多的解釋。

接著找到resetMainView方法,并用下面的代碼替換已有的內容:

// remove left and right views, and reset variables, if needed
if (_leftPanelViewController != nil)
{
    [self.leftPanelViewController.view removeFromSuperview];
    self.leftPanelViewController = nil;

    _centerViewController.leftButton.tag = 1;
    self.showingLeftPanel = NO;
}

if (_rightPanelViewController != nil)
{
    [self.rightPanelViewController.view removeFromSuperview];
    self.rightPanelViewController = nil;

    _centerViewController.rightButton.tag = 1;
    self.showingRightPanel = NO;
}

// remove view shadows
[self showCenterViewWithShadow:NO withOffset:0];

上面代碼中唯一修改的地方是增加了一個if語句代碼塊:if(_rightPanelViewController != nil)。該語句判斷一下right panel view是否存在,這跟之前檢查left panel view一樣,并且對_rightPanelViewController做相同的處理!

現在編譯并運行程序,點擊puppies按鈕,將看到如下畫面:

看起來不錯吧?

在下面一節中,將介紹如何添加手勢功能。

來回移動你的手指

在程序中添加手勢處理非常簡單,不要以為太復雜,很容易就能實現的!

還是在MainViewController.m文件中,找到setupView方法,并在方法的尾部添加如下一行代碼:

[self setupGestures];

接著,需要讓MainViewController遵循UIGestureRecognizerDelegate協議——將UIGestureRecognizerDelegate添加到文件頂部的@interface中,添加后的代碼如下:

@interface MainViewController ()<UIGestureRecognizerDelegate, CenterViewControllerDelegate>

最后,找到setupGestures方法,并將下面的代碼塊添加進去:

UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(movePanel:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];

[_centerViewController.view addGestureRecognizer:panRecognizer];

上面的代碼定義了一個UIPanGestureRecognizer,并將movePanel:方法賦值給它,當有檢測到手勢時,就會調用這個方法。(稍后需要實現movePanel:方法。)

接著,配置一下panRecognizer:將觸摸的最大數目和最小數目設置為1,另外還設置了一下delegate。最后,將剛剛創建好的panRecognizer添加到_centerViewController.view中。

注意:更多關于UIGestureRecognizer類的信息, 請參考蘋果官方文檔

接著,再做一件事情就可以用手勢進行滑動了。

現在就來移動View吧

當識別到手勢之后會調用movePanel:方法。所以,本文最后一個任務就是來實現一下這個方法。

movePanel:方法使用到兩個屬性:showPanel 和 preVelocity。在MainViewController.m文件的@interface中添加上這兩個屬性:

@property (nonatomic, assign) BOOL showPanel;
@property (nonatomic, assign) CGPoint preVelocity;

找到movePanel: 并將下面這段代碼添加進去(很多哦!):

[[[(UITapGestureRecognizer*)sender view] layer] removeAllAnimations];

CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self.view];
CGPoint velocity = [(UIPanGestureRecognizer*)sender velocityInView:[sender view]];

if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
        UIView *childView = nil;

        if(velocity.x > 0) {
            if (!_showingRightPanel) {
                childView = [self getLeftView];
            }
        } else {
            if (!_showingLeftPanel) {
                childView = [self getRightView];
            }

        }
        // Make sure the view you're working with is front and center.
        [self.view sendSubviewToBack:childView];
        [[sender view] bringSubviewToFront:[(UIPanGestureRecognizer*)sender view]];
}

if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {

        if(velocity.x > 0) {
            // NSLog(@"gesture went right");
        } else {
            // NSLog(@"gesture went left");
        }

        if (!_showPanel) {
            [self movePanelToOriginalPosition];
        } else {
            if (_showingLeftPanel) {
                [self movePanelRight];
            }  else if (_showingRightPanel) {
                [self movePanelLeft];
            }
        }
}

if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateChanged) {
        if(velocity.x > 0) {
            // NSLog(@"gesture went right");
        } else {
            // NSLog(@"gesture went left");
        }

        // Are you more than halfway? If so, show the panel when done dragging by setting this value to YES (1).
        _showPanel = abs([sender view].center.x - _centerViewController.view.frame.size.width/2) > _centerViewController.view.frame.size.width/2;

        // Allow dragging only in x-coordinates by only updating the x-coordinate with translation position.
        [sender view].center = CGPointMake([sender view].center.x + translatedPoint.x, [sender view].center.y);
        [(UIPanGestureRecognizer*)sender setTranslation:CGPointMake(0,0) inView:self.view];

        // If you needed to check for a change in direction, you could use this code to do so.
        if(velocity.x*_preVelocity.x + velocity.y*_preVelocity.y > 0) {
            // NSLog(@"same direction");
        } else {
            // NSLog(@"opposite direction");
        }

        _preVelocity = velocity;
}

上面代碼中的注視已經有對功能做了不錯的解釋。下面是一些需要明白的關鍵信息:

  • 需要處理3個狀態:UIGestureRecognizerStateBegan, UIGestureRecognizerStateEnded和 UIGestureRecognizerStateChanged。
  • translationInView:返回某個位置在指定view的坐標系中的point,并將這個point賦值給translatedPoint變量, 該變量用來設置view的位置。
  • velocityInView: 返回每秒鐘手勢的移動速率。該變量有助于確定方向的改變。

你可以移動center,left和right view,并結合上面提到的3個狀態,就可以確定手勢的位置和速率/方向。

例如,如果手勢方向是向右的,那么就顯示出left panel。如果方向是向左,則顯示出right panel。通過查看代碼和相關的注釋,就可以知道每一種狀態都發生了什么。

再次編譯并運行程序。現在應該可以把center panel滑動到左邊或者右邊了,并顯示出center panel下面的panel。

 

何去何從

如果你完全按照本文介紹的方法來操作,那么恭喜你,你已經成為一名滑出式導航面板忍者了!

希望本文對你有用!這里是本文涉及到的完整示例工程:completed project file

之前我提到過,如果你更喜歡已經定義好了的庫,而不是DIY,那么請看SWRevealViewController. 看看這里的開發者相關介紹,很容易就能使用它了。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!