Core Animation教学:使用Transitions制作带动画效果的向导对话框

我这两天有时候会想做一个向导对话框(就是那种上一步、下一步可以前进后退的玩意)。琢磨了一下,如果用Core Animation做出动画效果,那可就更好玩了。

基本上,这个例子做不了任何事。就是给你看看,一个窗口,里面有两个按钮:上一步、下一步,这样你可以通过前进后退的方式修改一些设置之类的东西。我做了几个NSView放在里面,它们按照不同顺序显示出来,就是这么个玩意。(就像安装向导一样,但是不同的是,我们要做的是一个有动画效果的向导对话框)

原文作者:Marcus Zarra

原文地址:

http://www.cimgf.com/2008/03/03/core-animation-tutorial-wizard-dialog-with-transitions/

 

 

做事不能费力气,我们用一些简单的方式去实现它。我写了一个NSView的子类,叫做MSZLinkedView。这里面我写了一些代码,包括“上一步”、“下一步”的视图连接和两个按钮。我直接在Interface Builder里面做了连接,这样就不需要什么代码了。

你可以在这里下载这个例子: Core Animation Wizard Tutorial Project.

MSZLinkedView.h

1

2

3

4

5

6

7

8

9

10

11

@interface MSZLinkedView : NSView {

    IBOutlet MSZLinkedView *previousView;

    IBOutlet MSZLinkedView *nextView;

 

    IBOutlet NSButton *nextButton;

    IBOutlet NSButton *previousButton;

}

 

@property(retain)MSZLinkedView *previousView, *nextView;

 

@end

MSZLinkedView.m

1

2

3

4

5

6

7

8

9

10

11

12

@implementation MSZLinkedView

 

@synthesize  previousView, nextView;

 

- (void)awakeFromNib

{

    [self setWantsLayer:YES];

    [previousButton setEnabled:(previousView != nil)];

    [nextButton setEnabled:(nextView != nil)];

}

 

@end

 

对于这个类来说,这些工作还不够。首先我用setWantsLayer:这个方法打开了视图的Core Animation支持。同时我在这里保留了两个视图, nextView和previousView,这样我就可以通过检查他们是否存在,而去禁用不需要的按钮。比如我走到最后一步的时候,那个“下一步”的按钮就不能按了,对吧?

创建 XIB/NIB

Core Animation教学:使用Transitions制作带动画效果的向导对话框_第1张图片

 

建立向导的下一个步骤是在Interface Builder里把用户需要看到的样子画出来。在这个例子里,我建了三个视图:1、2、3页(图里画的很清楚,三个窗口)。这三个页面每一个都有一个“上一步”、“下一步”按钮,和一个不同颜色的方框。如果你执行这个项目,你会看到,这三个窗口会以动画的形式滚动,而不需要的按钮将被禁用。

在Interface Builder里面给每一个视图里都连接了上一步、下一步两个视图和自带的两个按钮。这样的好处是在awakeFromNib执行之前,这些连接就会被启用,这样,不需要的按钮走到相应的步骤自然而然就会被禁用。

 

如果是一个真正的应用程序,我会在向导里的每页加入文字框、单选框、图片等等,但是在这个例子中我只是放了三个不同颜色的框做为演示用。就是让你在使用这个向导的时候看到页面的确改变了。

在这个例子里,应用程序托管保留了对于主窗口的参考,还仅仅保留了第一个选中的视图。因为这些视图是保存在列表中。AppDelegate完全不去管未被选中的视图,那是列表的任务。当nib文件被读取的时候,当前的view在awakeFromNib调用之前就会被留作参考。为了让这个视图做为一个子视图,我需要在awakeFromNib中加入它。(这段翻译的有点脑残,看不明白就请参考下面的代码)

Core Animation教学:使用Transitions制作带动画效果的向导对话框_第2张图片AppDelegate.h

1

2

3

4

5

6

7

8

9

10

11

12

13

14

@interface AppDelegate : NSObject {

    IBOutlet NSWindow *window;

    IBOutlet MSZLinkedView *currentView;

 

    CATransition *transition;

}

 

@property(retain)NSWindow *window;

@property(retain)MSZLinkedView *currentView;

 

- (IBAction)nextView:(id)sender;

- (IBAction)previousView:(id)sender;

 

@end

Method breakdown of the AppDelegate

1

2

3

4

5

6

7

8

9

10

11

12

13

14

- (void)awakeFromNib

{

    NSView *contentView = [[self window] contentView];

    [contentView setWantsLayer:YES];

    [contentView addSubview:[self currentView]];

 

    transition = [CATransition animation];

    [transition setType:kCATransitionPush];

    [transition setSubtype:kCATransitionFromLeft];

 

    NSDictionary *ani = [NSDictionary dictionaryWithObject:transition 

                                                    forKey:@"subviews"];

    [contentView setAnimations:ani];

}

awakeFromNib

 

awakeFromNib首先打开Core Animation支持(就是setWantsLayer这行)。然后把当前的参考视图currentView做为子视图加入到contentView中。由于我们已经将currentView的frameOrigin属性设置为0,0,因此不需要考虑subview的位置。

接下来我建立了一个CATransition的动画。注意我在AppDelegate中将这个动画保留为ivar。原因很明显,当动画建立时,我将它做为transition动画加入content view,key是“subviews”。这个transition动画无论在一个subview添加、删除或者替换的时候都会触发。

1

2

3

4

5

6

7

8

9

10

- (void)setCurrentView:(MSZLinkedView*)newView

{

    if (!currentView) {

        currentView = newView;

        return;

    }

    NSView *contentView = [[self window] contentView];

    [[contentView animator] replaceSubview:currentView with:newView];

    currentView = newView;

}

setCurrentView:(MSZLinkedView*)view

 

我重载这个方法的原因是为了方便。因为我只希望任何时候,当前屏幕上只有一个view,无论任何时候,当"currentView"的设置方法被调用时,我都可以轻松地切换。我可以用别的办法实现这个动画效果,但是由于我希望跟踪当前的view,这个是最好的办法。而且无论何时我希望切换窗口,我只需要把一个新的view传递到setCurrentView方法中就可以了。

1

2

3

4

5

6

7

8

9

10

11

12

13

- (IBAction)nextView:(id)sender;

{

    if (![[self currentView] nextView]) return;

    [transition setSubtype:kCATransitionFromRight];

    [self setCurrentView:[[self currentView] nextView]];

}

 

- (IBAction)previousView:(id)sender;

{

    if (![[self currentView] previousView]) return;

    [transition setSubtype:kCATransitionFromLeft];

    [self setCurrentView:[[self currentView] previousView]];

}

nextView:(id)sender previousView:(id)sender

 

这两个方法调用的方式是完全一样的。在这两个方法中,我把当前的view放入reference,同时检查上页、下页是否为空,目的仅仅是保护性的,因为我已经禁用了不需要的按钮。

检查完毕后,我调用了setCurrentView:,给它传递适当的view:或者是“上一步”,或者是“下一步”的页面。setCurrentView:方法上文中已经讨论过,用来切换视图。在我切换视图之前,我改变了transition的子类型,而这是我保留reference的原因。这样以来前进后退的动画效果才看上去是那么回事。上一页往左边移动,下一页往右边移动。这并不必要但是感觉会更好。

结论

Core Animationtransition在什么时候发生的呢?完全就在AppDelegateawakeFromNib中。只需要简单的设置content view的CATransition,动画就出来了。其他的代码都是用来处理切换的,你只需要修改awakeFromNib中transition的类别和子类,就可以看到其他动画效果。

你可能感兴趣的:(Core Animation教学:使用Transitions制作带动画效果的向导对话框)