攻略2 让启动画面的切换更有吸引力

攻略2 让启动画面的切换更有吸引力
2012-08-20 18:37:20      我来说两句 
收藏   我要投稿   

本文所属图书 > iOS应用开发攻略

本书收录了最新的iOS 软件开发的最佳做法,涵盖了应用开发及构建优雅解决方案的必备知识,包括:编写通用的启动画面和嵌入式Web 浏览器;构建复杂表视图;使app 或游戏活灵活现的填充、变换和动画;通过手势、...   立即去当当网订购
问题
简洁的启动画面切换很重要,但有时候除了基本的渐变之外,应用更多的技巧可以锦上添花。
解决方案
在攻略1中,我们讨论了启动画面切换的重要性,看到了它给用户带来的完全不同的体验。在第一个攻略里,我们的重点是如何建立清晰简洁的结构来实现切换。渐变切换虽然优雅,但在我们能够使用的切换中它只是最简单的一种。在保持切换平滑流畅的同时,通过结合蒙版(masking)技术与Core Animation还可制作出更有吸引力的效果。
如前面的例子一样,为了把默认图像从屏幕切换走,首先需要一个视图来显示默认图像,然后需要逐渐地移走这个视图,露出下面的主界面视图(如图5所示)。
攻略2 让启动画面的切换更有吸引力_第1张图片
图5 CircleFromCenter切换过程
本攻略会介绍多个示例,但这些示例使用的都是相同的基本蒙版技巧。我们使用一幅蒙版图像滤掉部分图像,然后对蒙版图像的scale做动画,直至整幅图像完全消失。
我们创建的每个视图都由一个图层(即由图形处理器直接绘制的图形元素)来支撑,图层起到图像存储器的作用,让我们不必重画就能对视图进行操作(移动、缩放或旋转)。我们可以直接修改图层的属性,这是一种进一步修改视图显示的手段。这些属性中有一个是mask属性,通过它可以设定第二图层,第二图层的alpha通道将与第一图层的图像作蒙版。图像的alpha通道指定了那些区域的透明程度,从0(透明)到1(不透明)。当图层蒙版添加到视图之后,蒙版图像的不透明部分将显示原始图像,但是透明或部分透明的区域会显示出它下面的视图(参见图6)。
攻略2 让启动画面的切换更有吸引力_第2张图片
图6 CircleFromCenter变换所用的蒙版
我们使用预先定义的图像来创建蒙版图层的内容,这些图像各自有不同的不透明区域,以产生所要的效果。然后进行增大蒙版图层比例的动画,实际上是增大它的尺寸,以充满整个视图并将其渲染为透明。
蒙版图层的anchorPoint(定位点)至关重要。当我们使用变换(transform)改变图层的比例时,拉伸效果将以anchorPoint为中心,所以anchorPoint要跟我们的蒙版图像的透明区域的中心相一致。这样会产生蒙版图像的透明区域在扩大的效果,导致逐渐露出下面的视图(参见图7)。



攻略2 让启动画面的切换更有吸引力_第3张图片
图7 ClearFromCenter变换所用的蒙版
在viewDidLoad方法中,我们增加了Default.png的副本,这会产生原来的启动画面没有消失的印象。为了避免使用UIImageView,我们直接填充视图图层的contents,同时设置缩放因子来匹配设备。把contentMode设为UIViewContentModeBottom以避免这幅替代图像被状态条抵消,这会让图像与屏幕下端对齐。
SplashScreenReveal/PRPSplashScreenViewController.m
- (void)viewDidLoad {
    self.view.layer.contentsScale = [[UIScreen mainScreen] scale];
    self.view.layer.contents = (id)self.splashImage.CGImage;
    self.view.contentMode = UIViewContentModeBottom;
    if (self.transition == 0) self.transition = ClearFromRight;
}
在viewDidAppear:方法中,我们使用了一个switch语句把枚举值Enum匹配到切换种类。每种切换只需要调整两个元素:蒙版图像和对应的anchorPoint。performSelector:withObject: afterDelay:方法在这里很有用,因为通过它可产生一个延迟,之后再激活animate方法,开始画面切换。
SplashScreenReveal/PRPSplashScreenViewController.m
- (void)viewDidAppear:(BOOL)animated {
    if ([self.delegate respondsToSelector:@selector(splashScreenDidAppear:)]) {
        [self.delegate splashScreenDidAppear:self];
    }
    switch (self.transition) {
        case CircleFromCenter:
            self.maskImageName = @" mask";
            self.anchor = CGPointMake(0.5, 0.5);
            break;
        case ClearFromCenter:
            self.maskImageName = @" wideMask";
            self.anchor = CGPointMake(0.5, 0.5);
            break;
        case ClearFromLeft:
            self.maskImageName = @" leftStripMask";
            self.anchor = CGPointMake(0.0, 0.5);
            break;
        case ClearFromRight:
            self.maskImageName = @" RightStripMask";
            self.anchor = CGPointMake(1.0, 0.5);
            break;
        case ClearFromTop:
            self.maskImageName = @" TopStripMask";
            self.anchor = CGPointMake(0.5, 0.0);
            break;
        case ClearFromBottom:
            self.maskImageName = @" BottomStripMask";
            self.anchor = CGPointMake(0.5, 1.0);
            break;
        default:
            return;
    }
    [self performSelector:@selector(animate) withObject:nil afterDelay:self.delay];
}
画面切换中唯一活动的部分是蒙版图层的动画。我们需要增大比例,实际是扩大图层,直到把蒙版的透明部分拉伸到覆盖整个视图。此处使用的toValue包含了一点儿容差系数,目的是为了让蒙版足够大,能够完成显露。如果打算对蒙版图像做较大修改,可能需要对计算作调整。
SplashScreenReveal/PRPSplashScreenViewController.m
- (void)animate {
    if ([self.delegate respondsToSelector:@selector(splashScreenWillDisappear:)]) {
        [self.delegate splashScreenWillDisappear:self];
    }
 
    [self setMaskLayerwithanchor];
 
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@" transform.scale"];
    anim.duration = DURATION;
    anim.toValue = [NSNumber numberWithInt:self.view.bounds.size.height/8];
    anim.fillMode = kCAFillModeBoth;
    anim.removedOnCompletion = NO;
    anim.delegate = self;
    [self.view.layer.mask addAnimation:anim forKey:@" scale" ];
 
}
为了产生所要的效果,我们需要在setMaskLayerwithanchor方法中创建蒙版图层,将其contents设置为适当的蒙版图像,并设置正确的定位点以保证蒙版的不透明区域的种子点与定位点一致。
SplashScreenReveal/PRPSplashScreenViewController.m
- (void)setMaskLayerwithanchor {
 
    CALayer *maskLayer = [CALayer layer];
    maskLayer.anchorPoint = self.anchor;
    maskLayer.frame = self.view.superview.frame;
    maskLayer.contents = (id)self.maskImage.CGImage;
    self.view.layer.mask = maskLayer;
}
我们需要根据选定的枚举值,为所需的切换取出正确的蒙版图像进行设定。
SplashScreenReveal/PRPSplashScreenViewController.m
- (UIImage *)maskImage {
    if (maskImage != nil) [maskImage release];
    NSString *defaultPath = [[NSBundle mainBundle]
                                pathForResource:self.maskImageName ofType:@" png"];
    maskImage = [[UIImage alloc] initWithContentsOfFile:defaultPath];
    return maskImage;
}
当动画过程完成了对蒙版图层的拉伸之后,animationDidStop委托会被调用。被切换的视图现在看上去已经消失了,所以我们要做的只是把它从SuperView中删除,并通知委托切换已经完成。
SplashScreenReveal/PRPSplashScreenViewController.m
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
 
    self.view.layer.mask = nil;
    [self.view removeFromSuperview];
    if ([self.delegate respondsToSelector:@selector(splashScreenDidDisappear:)]) {
        [self.delegate splashScreenDidDisappear:self];
    }
}
逐渐露出的切换为我们的应用程序的开场增色不少,而且易于扩展以提供更多选项。蒙版的透明区域的形状在缩放过程中保持不变,因此其他的形状(比如星形)会产生有趣的效果。我们甚至可以使用更为复杂的形状,比如脸状,但是可能需要添加额外的渐变动画来消除残留的可见部分。

你可能感兴趣的:(xcoder)