ios iPhone“滑动解锁”动画

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/438046/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:32:10  来源:igfitidea点击:

iPhone "slide to unlock" animation

iosobjective-ccocoa-touchcore-animation

提问by

Any ideas as to how Apple implemented the "slide to unlock" (also, "slide to power off" is another identical example) animation?

关于 Apple 如何实现“滑动解锁”(同样,“滑动关闭电源”是另一个相同的例子)动画的任何想法?

I thought about some sort of animating mask - but masking is not available on the iPhone OS for performance reasons.

我想过某种动画蒙版 - 但出于性能原因,iPhone OS 上不提供蒙版。

Is there some private API effect (like SuckEffect) that they might have used? A spotlight type of effect? Some Core Animation thing?

是否有一些他们可能使用过的私有 API 效果(如 SuckEffect)?聚光灯类型的效果?一些核心动画的东西?

Edit: It's definitely not a series of stills. I've seen examples of being edit a plist value or something and customize the string on jailbroken iphones.

编辑:这绝对不是一系列剧照。我见过编辑 plist 值或其他东西并在越狱的 iphone 上自定义字符串的示例。

回答by Pascal Bourque

It can be easilly done by using Core Animation, animating a mask layer on the layer displaying the text.

可以通过使用 Core Animation 轻松完成,在显示文本的图层上为蒙版图层设置动画。

Try this in any plain UIViewController (you can start with a new Xcode project based on the View-based applicationproject template), or grab my Xcode project here:

在任何普通的 UIViewController 中尝试此操作(您可以从基于基于视图的应用程序项目模板的新 Xcode 项目开始),或在此处获取我的 Xcode 项目:

Note that the CALayer.maskproperty is only available in iPhone OS 3.0 and later.

请注意,该CALayer.mask属性仅在 iPhone OS 3.0 及更高版本中可用。

- (void)viewDidLoad 
{
  self.view.layer.backgroundColor = [[UIColor blackColor] CGColor];

  UIImage *textImage = [UIImage imageNamed:@"SlideToUnlock.png"];
  CGFloat textWidth = textImage.size.width;
  CGFloat textHeight = textImage.size.height;

  CALayer *textLayer = [CALayer layer];
  textLayer.contents = (id)[textImage CGImage];
  textLayer.frame = CGRectMake(10.0f, 215.0f, textWidth, textHeight);

  CALayer *maskLayer = [CALayer layer];

  // Mask image ends with 0.15 opacity on both sides. Set the background color of the layer
  // to the same value so the layer can extend the mask image.
  maskLayer.backgroundColor = [[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.15f] CGColor];
  maskLayer.contents = (id)[[UIImage imageNamed:@"Mask.png"] CGImage];

  // Center the mask image on twice the width of the text layer, so it starts to the left
  // of the text layer and moves to its right when we translate it by width.
  maskLayer.contentsGravity = kCAGravityCenter;
  maskLayer.frame = CGRectMake(-textWidth, 0.0f, textWidth * 2, textHeight);

  // Animate the mask layer's horizontal position
  CABasicAnimation *maskAnim = [CABasicAnimation animationWithKeyPath:@"position.x"];
  maskAnim.byValue = [NSNumber numberWithFloat:textWidth];
  maskAnim.repeatCount = HUGE_VALF;
  maskAnim.duration = 1.0f;
  [maskLayer addAnimation:maskAnim forKey:@"slideAnim"];

  textLayer.mask = maskLayer;
  [self.view.layer addSublayer:textLayer];

  [super viewDidLoad];
}

The images used by this code are:

此代码使用的图像是:

Mask LayerText Layer

遮罩层文字层

回答by Samsinite

Yet another solution using a layer mask, but instead draws the gradient by hand and does not require images. View is the view with the animation, transparency is a float from 0 - 1 defining the amount of transparency (1 = no transparency which is pointless), and gradientWidth is the desired width of the gradient.

另一个使用图层蒙版的解决方案,而是手动绘制渐变并且不需要图像。视图是带有动画的视图,透明度是 0 - 1 之间的浮点数,定义了透明度(1 = 无透明度,这是毫无意义的),而 gradientWidth 是所需的渐变宽度。

CAGradientLayer *gradientMask = [CAGradientLayer layer];
 gradientMask.frame = view.bounds;
CGFloat gradientSize = gradientWidth / view.frame.size.width;
UIColor *gradient = [UIColor colorWithWhite:1.0f alpha:transparency];
NSArray *startLocations = @[[NSNumber numberWithFloat:0.0f], [NSNumber numberWithFloat:(gradientSize / 2)], [NSNumber numberWithFloat:gradientSize]];
NSArray *endLocations = @[[NSNumber numberWithFloat:(1.0f - gradientSize)], [NSNumber numberWithFloat:(1.0f -(gradientSize / 2))], [NSNumber numberWithFloat:1.0f]];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"locations"];

gradientMask.colors = @[(id)gradient.CGColor, (id)[UIColor whiteColor].CGColor, (id)gradient.CGColor];
gradientMask.locations = startLocations;
gradientMask.startPoint = CGPointMake(0 - (gradientSize * 2), .5);
gradientMask.endPoint = CGPointMake(1 + gradientSize, .5);

view.layer.mask = gradientMask;

animation.fromValue = startLocations;
animation.toValue = endLocations;
animation.repeatCount = HUGE_VALF;
animation.duration  = 3.0f;

[gradientMask addAnimation:animation forKey:@"animateGradient"];

SWIFT VERSION:

快速版本:

let transparency:CGFloat = 0.5
let gradientWidth: CGFloat = 40

let gradientMask = CAGradientLayer()
gradientMask.frame = swipeView.bounds
let gradientSize = gradientWidth/swipeView.frame.size.width
let gradient = UIColor(white: 1, alpha: transparency)
let startLocations = [0, gradientSize/2, gradientSize]
let endLocations = [(1 - gradientSize), (1 - gradientSize/2), 1]
let animation = CABasicAnimation(keyPath: "locations")

gradientMask.colors = [gradient.CGColor, UIColor.whiteColor().CGColor, gradient.CGColor]
gradientMask.locations = startLocations
gradientMask.startPoint = CGPointMake(0 - (gradientSize*2), 0.5)
gradientMask.endPoint = CGPointMake(1 + gradientSize, 0.5)

swipeView.layer.mask = gradientMask

animation.fromValue = startLocations
animation.toValue = endLocations
animation.repeatCount = HUGE
animation.duration = 3

gradientMask.addAnimation(animation, forKey: "animateGradient")

Swift 3

斯威夫特 3

fileprivate func addGradientMaskToView(view:UIView, transparency:CGFloat = 0.5, gradientWidth:CGFloat = 40.0) {        
    let gradientMask = CAGradientLayer()
    gradientMask.frame = view.bounds
    let gradientSize = gradientWidth/view.frame.size.width
    let gradientColor = UIColor(white: 1, alpha: transparency)
    let startLocations = [0, gradientSize/2, gradientSize]
    let endLocations = [(1 - gradientSize), (1 - gradientSize/2), 1]
    let animation = CABasicAnimation(keyPath: "locations")

    gradientMask.colors = [gradientColor.cgColor, UIColor.white.cgColor, gradientColor.cgColor]
    gradientMask.locations = startLocations as [NSNumber]?
    gradientMask.startPoint = CGPoint(x:0 - (gradientSize * 2), y: 0.5)
    gradientMask.endPoint = CGPoint(x:1 + gradientSize, y: 0.5)

    view.layer.mask = gradientMask

    animation.fromValue = startLocations
    animation.toValue = endLocations
    animation.repeatCount = HUGE
    animation.duration = 3

    gradientMask.add(animation, forKey: nil)
}

回答by rpetrich

You can use the kCGTextClipdrawing mode to set the clipping path and then fill with a gradient.

您可以使用kCGTextClip绘图模式设置剪切路径,然后填充渐变。

// Get Context
CGContextRef context = UIGraphicsGetCurrentContext();
// Set Font
CGContextSelectFont(context, "Helvetica", 24.0, kCGEncodingMacRoman);
// Set Text Matrix
CGAffineTransform xform = CGAffineTransformMake(1.0,  0.0,
                                                0.0, -1.0,
                                                0.0,  0.0);
CGContextSetTextMatrix(context, xform);
// Set Drawing Mode to set clipping path
CGContextSetTextDrawingMode (context, kCGTextClip);
// Draw Text
CGContextShowTextAtPoint (context, 0, 20, "Gradient", strlen("Gradient")); 
// Calculate Text width
CGPoint textEnd = CGContextGetTextPosition(context);
// Generate Gradient locations & colors
size_t num_locations = 3;
CGFloat locations[3] = { 0.3, 0.5, 0.6 };
CGFloat components[12] = { 
    1.0, 1.0, 1.0, 0.5,
    1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 0.5,
};
// Load Colorspace
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
// Create Gradient
CGGradientRef gradient = CGGradientCreateWithColorComponents (colorspace, components,
                                                              locations, num_locations);
// Draw Gradient (using clipping path
CGContextDrawLinearGradient (context, gradient, rect.origin, textEnd, 0);
// Cleanup (exercise for reader)

Setup an NSTimer and vary the values in locations, or use CoreAnimation to do the same.

设置一个 NSTimer 并改变位置的值,或者使用 CoreAnimation 来做同样的事情。

回答by cberkley

I added the code provided above by Pascal as a category on UILabel so you can animate any UILabel in this fashion. Here's the code. Some params might need to be changed for your background colors, etc. It uses the same mask image that Pascal has embedded in his answer.

我将 Pascal 上面提供的代码添加为 UILabel 上的一个类别,以便您可以以这种方式为任何 UILabel 设置动画。这是代码。某些参数可能需要针对您的背景颜色等进行更改。它使用 Pascal 嵌入在他的答案中的相同蒙版图像。

//UILabel+FSHighlightAnimationAdditions.m
#import "UILabel+FSHighlightAnimationAdditions.h"
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@implementation UILabel (FSHighlightAnimationAdditions)

- (void)setTextWithChangeAnimation:(NSString*)text
{
    NSLog(@"value changing");
    self.text = text;
    CALayer *maskLayer = [CALayer layer];

    // Mask image ends with 0.15 opacity on both sides. Set the background color of the layer
    // to the same value so the layer can extend the mask image.
    maskLayer.backgroundColor = [[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.15f] CGColor];
    maskLayer.contents = (id)[[UIImage imageNamed:@"Mask.png"] CGImage];

    // Center the mask image on twice the width of the text layer, so it starts to the left
    // of the text layer and moves to its right when we translate it by width.
    maskLayer.contentsGravity = kCAGravityCenter;
    maskLayer.frame = CGRectMake(self.frame.size.width * -1, 0.0f, self.frame.size.width * 2, self.frame.size.height);

    // Animate the mask layer's horizontal position
    CABasicAnimation *maskAnim = [CABasicAnimation animationWithKeyPath:@"position.x"];
    maskAnim.byValue = [NSNumber numberWithFloat:self.frame.size.width];
    maskAnim.repeatCount = 1e100f;
    maskAnim.duration = 2.0f;
    [maskLayer addAnimation:maskAnim forKey:@"slideAnim"];

    self.layer.mask = maskLayer;
}

@end

//UILabel+FSHighlightAnimationAdditions.h
#import <Foundation/Foundation.h>
@interface UILabel (FSHighlightAnimationAdditions)

- (void)setTextWithChangeAnimation:(NSString*)text;

@end

回答by marcio

not so fresh...but maybe it'll be useful

不是很新鲜……但也许会有用

#define MM_TEXT_TO_DISPLAY          @"default"

#define MM_FONT             [UIFont systemFontOfSize:MM_FONT_SIZE]
#define MM_FONT_SIZE            25
#define MM_FONT_COLOR           [[UIColor darkGrayColor] colorWithAlphaComponent:0.75f];

#define MM_SHADOW_ENABLED           NO
#define MM_SHADOW_COLOR         [UIColor grayColor]
#define MM_SHADOW_OFFSET            CGSizeMake(-1,-1)


#define MM_CONTENT_EDGE_INSETS_TOP      0
#define MM_CONTENT_EDGE_INSETS_LEFT     10
#define MM_CONTENT_EDGE_INSETS_BOTTON   0
#define MM_CONTENT_EDGE_INSETS_RIGHT    10
#define MM_CONTENT_EDGE_INSETS          UIEdgeInsetsMake(MM_CONTENT_EDGE_INSETS_TOP, MM_CONTENT_EDGE_INSETS_LEFT, MM_CONTENT_EDGE_INSETS_BOTTON, MM_CONTENT_EDGE_INSETS_RIGHT)

#define MM_TEXT_ALIGNMENT           UITextAlignmentCenter
#define MM_BACKGROUND_COLOR         [UIColor clearColor]

#define MM_TIMER_INTERVAL           0.05f
#define MM_HORIZONTAL_SPAN          5


@interface MMAnimatedGradientLabel : UILabel {  

    NSString *textToDisplay;
    int text_length;

    CGGradientRef gradient;

    int current_position_x;
    NSTimer *timer;

    CGPoint alignment;

    CGGlyph *_glyphs;
}

- (id)initWithString:(NSString *)_string;

- (void)startAnimation;
- (void)toggle;
- (BOOL)isAnimating;

@end

#define RGB_COMPONENTS(r, g, b, a)  (r) / 255.0f, (g) / 255.0f, (b) / 255.0f, (a)

@interface MMAnimatedGradientLabel (Private)
- (CGRect)calculateFrame;
@end


@implementation MMAnimatedGradientLabel

// Missing in standard headers.
extern void CGFontGetGlyphsForUnichars(CGFontRef, const UniChar[], const CGGlyph[], size_t);

- (id)init {
    textToDisplay = MM_TEXT_TO_DISPLAY;
    return [self initWithFrame:[self calculateFrame]];
}

- (id)initWithString:(NSString *)_string {
    textToDisplay = _string;
    return [self initWithFrame:[self calculateFrame]];
}

-(id)initWithFrame:(CGRect)frame {  
    if (self = [super initWithFrame:frame]) {

        // set default values
        //
        self.textAlignment      = MM_TEXT_ALIGNMENT;
        self.backgroundColor    = MM_BACKGROUND_COLOR;
        self.font               = MM_FONT;
        self.text               = textToDisplay;
        self.textColor          = MM_FONT_COLOR;

        if (MM_SHADOW_ENABLED) {
            self.shadowColor        = MM_SHADOW_COLOR;
            self.shadowOffset       = MM_SHADOW_OFFSET;
        }

        text_length = -1;

        CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
        CGFloat colors[] =
        {       
            RGB_COMPONENTS(255.0, 255.0, 255.0, 0.00),
//          RGB_COMPONENTS(255.0, 255.0, 255.0, 0.15),
            RGB_COMPONENTS(255.0, 255.0, 255.0, 0.95),
//          RGB_COMPONENTS(255.0, 255.0, 255.0, 0.15),
            RGB_COMPONENTS(255.0, 255.0, 255.0, 0.00)
        };

        gradient = CGGradientCreateWithColorComponents(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));
        CGColorSpaceRelease(rgb);

        current_position_x = -(frame.size.width/2);// - MM_CONTENT_EDGE_INSETS.left - MM_CONTENT_EDGE_INSETS.right); 
    }

    return self;
}

- (CGRect)calculateFrame {
    CGSize size = [textToDisplay sizeWithFont:MM_FONT];
    NSLog(@"size: %f, %f", size.width, size.height);
    return CGRectMake(0, 0, size.width + MM_CONTENT_EDGE_INSETS.left + MM_CONTENT_EDGE_INSETS.right, size.height + MM_CONTENT_EDGE_INSETS.top + MM_CONTENT_EDGE_INSETS.bottom);
}

- (void)tick:(NSTimer*)theTimer {
    if (current_position_x < self.frame.size.width)
        current_position_x = current_position_x + MM_HORIZONTAL_SPAN;
    else
        current_position_x = -(self.frame.size.width/2); // - MM_CONTENT_EDGE_INSETS.left - MM_CONTENT_EDGE_INSETS.right);

    [self setNeedsDisplay]; 
}

- (void)startAnimation {    
    timer = [[NSTimer alloc] initWithFireDate:[NSDate date] 
                                     interval:MM_TIMER_INTERVAL
                                       target:self 
                                     selector:@selector(tick:)
                                     userInfo:nil
                                      repeats:YES];

    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

- (void)toggle {

    if (!timer) {
        timer = [[NSTimer alloc] initWithFireDate:[NSDate date] 
                                         interval:MM_TIMER_INTERVAL
                                           target:self 
                                         selector:@selector(tick:)
                                         userInfo:nil
                                          repeats:YES];

        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    } else {
        [timer invalidate];
        [timer release];
        timer = nil;

        current_position_x = -(self.frame.size.width/2);
        [self setNeedsDisplay]; 
    }
}

- (BOOL)isAnimating {

    if (timer) 
        return YES;
    else
        return NO;
}

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // Get drawing font.
    CGFontRef font = CGFontCreateWithFontName((CFStringRef)[[self font] fontName]);
    CGContextSetFont(ctx, font);
    CGContextSetFontSize(ctx, [[self font] pointSize]);

    // Calculate text drawing point only first time
    // 
    if (text_length == -1) {    

        // Transform text characters to unicode glyphs.
        text_length = [[self text] length];
        unichar chars[text_length];
        [[self text] getCharacters:chars range:NSMakeRange(0, text_length)];

        _glyphs = malloc(sizeof(CGGlyph) * text_length);
        for (int i=0; i<text_length;i ++)
            _glyphs[i] = chars[i] - 29;

        // Measure text dimensions.
        CGContextSetTextDrawingMode(ctx, kCGTextInvisible); 
        CGContextSetTextPosition(ctx, 0, 0);
        CGContextShowGlyphs(ctx, _glyphs, text_length);
        CGPoint textEnd = CGContextGetTextPosition(ctx);

        // Calculate text drawing point.        
        CGPoint anchor = CGPointMake(textEnd.x * (-0.5), [[self font] pointSize] * (-0.25));  
        CGPoint p = CGPointApplyAffineTransform(anchor, CGAffineTransformMake(1, 0, 0, -1, 0, 1));

        if ([self textAlignment] == UITextAlignmentCenter) 
            alignment.x = [self bounds].size.width * 0.5 + p.x;
        else if ([self textAlignment] == UITextAlignmentLeft) 
            alignment.x = 0;
        else 
            alignment.x = [self bounds].size.width - textEnd.x;

        alignment.y = [self bounds].size.height * 0.5 + p.y;
    }

    // Flip back mirrored text.
    CGContextSetTextMatrix(ctx, CGAffineTransformMakeScale(1, -1));

    // Draw shadow.
    CGContextSaveGState(ctx);
    CGContextSetTextDrawingMode(ctx, kCGTextFill);
    CGContextSetFillColorWithColor(ctx, [[self textColor] CGColor]);
    CGContextSetShadowWithColor(ctx, [self shadowOffset], 0, [[self shadowColor] CGColor]);
    CGContextShowGlyphsAtPoint(ctx, alignment.x, alignment.y, _glyphs, text_length);
    CGContextRestoreGState(ctx);

    // Draw text clipping path.
    CGContextSetTextDrawingMode(ctx, kCGTextClip);
    CGContextShowGlyphsAtPoint(ctx, alignment.x, alignment.y, _glyphs, text_length);

    // Restore text mirroring.
    CGContextSetTextMatrix(ctx, CGAffineTransformIdentity);

    if ([self isAnimating]) {
        // Fill text clipping path with gradient.
        CGPoint start = CGPointMake(rect.origin.x + current_position_x, rect.origin.y);
        CGPoint end = CGPointMake(rect.size.width/3*2 + current_position_x, rect.origin.y);

        CGContextDrawLinearGradient(ctx, gradient, start, end, 0);
    }
}


- (void) dealloc {
    free(_glyphs);
    [timer invalidate];
    [timer release];

    CGGradientRelease(gradient);
    [super dealloc];
}

回答by MyCatsNameIsBernie

Thanks to rpetrich for the clipping gradient recipe. I am a newbie iPhone and Cocoa developer, so I was real happy to find it.

感谢 rpetrich 的裁剪渐变配方。我是 iPhone 和 Cocoa 开发新手,所以我很高兴找到它。

I've implemented a decent-looking Slide to CancelUIViewController using rpetrich's method. You can download the Xcode project of my implementation from here.

我已经使用 rpetrich 的方法实现了一个看起来不错的Slide to CancelUIViewController。您可以从这里下载我的实现的 Xcode 项目。

My implementation uses a repeating NSTimer. I was unable to figure out how use Core (or Gore) Animation to have the iPhone's graphics engine continuously move the highlighting. I think that could be done on OS X with CALayer mask layers, but mask layers are not supported on iPhone OS.

我的实现使用重复的 NSTimer。我无法弄清楚如何使用 Core(或 Gore)动画让 iPhone 的图形引擎连续移动突出显示。我认为这可以在带有 CALayer 蒙版层的 OS X 上完成,但 iPhone 操作系统不支持蒙版层。

When I play with Apple's "Slide to Unlock" slider on my iPhone's home screen, I occasionally see the animation freeze. So I think Apple may be using a timer as well.

当我在 iPhone 的主屏幕上玩 Apple 的“滑动解锁”滑块时,我偶尔会看到动画冻结。所以我认为苹果可能也在使用计时器。

If anyone can figure out how to do a non-timer based implementation using CA or OpenGL, I would love to see it.

如果有人能弄清楚如何使用 CA 或 OpenGL 进行基于非计时器的实现,我很乐意看到它。

Thanks for the help!

谢谢您的帮助!

回答by Maxim Pavlov

I know, I am a bit late with the answer, but Facebook has great library Shimmerthat implements exactly that effect.

我知道,我的答案有点晚了,但是 Facebook 有很棒的库Shimmer可以实现这种效果。

回答by Nico S.

I took the best from above solutions and created a neat method that does all for you:

我从上面的解决方案中汲取了最好的东西,并创建了一个简洁的方法来为您完成所有工作:

- (void)createSlideToUnlockViewWithText:(NSString *)text
{
    UILabel *label = [[UILabel alloc] init];
    label.text = text;
    [label sizeToFit];
    label.textColor = [UIColor whiteColor];

    //Create an image from the label
    UIGraphicsBeginImageContextWithOptions(label.bounds.size, NO, 0.0);
    [[label layer] renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *textImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    CGFloat textWidth = textImage.size.width;
    CGFloat textHeight = textImage.size.height;

    CALayer *textLayer = [CALayer layer];
    textLayer.contents = (id)[textImage CGImage];
    textLayer.frame = CGRectMake(self.view.frame.size.width / 2 - textWidth / 2, self.view.frame.size.height / 2 - textHeight / 2, textWidth, textHeight);

    UIImage *maskImage = [UIImage imageNamed:@"Mask.png"];
    CALayer *maskLayer = [CALayer layer];
    maskLayer.backgroundColor = [[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.15] CGColor];
    maskLayer.contents = (id)maskImage.CGImage;
    maskLayer.contentsGravity = kCAGravityCenter;
    maskLayer.frame = CGRectMake(-textWidth - maskImage.size.width, 0.0, (textWidth * 2) + maskImage.size.width, textHeight);

    CABasicAnimation *maskAnimation = [CABasicAnimation animationWithKeyPath:@"position.x"];
    maskAnimation.byValue = [NSNumber numberWithFloat:textWidth + maskImage.size.width];
    maskAnimation.repeatCount = HUGE_VALF;
    maskAnimation.duration = 2.0;
    maskAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    [maskLayer addAnimation:maskAnimation forKey:@"slideAnimation"];

    textLayer.mask = maskLayer;
    self.slideToUnlockLayer = textLayer;
    [self.view.layer addSublayer:self.slideToUnlockLayer];
}

回答by Gabriel.Massana

I uploaded to GitHub a mini project who helps with the “slide to unlock” animation.

我将一个小项目上传到 GitHub,该项目有助于“滑动解锁”动画。

https://github.com/GabrielMassana/GM_FSHighlightAnimationAdditions

https://github.com/GabrielMassana/GM_FSHighlightAnimationAdditions

The project have LTR, RTL, Up to Down and Down to Up animations and it is based in the posts:

该项目有 LTR、RTL、Up to Down 和 Down to Up 动画,它基于以下帖子:

Pascal Bourque: https://stackoverflow.com/a/2778232/1381708

帕斯卡布尔克:https: //stackoverflow.com/a/2778232/1381708

cberkley: https://stackoverflow.com/a/5710097/1381708

cberkley:https://stackoverflow.com/a/5710097/1381708

Cheers

干杯

回答by Dave Klotz

First, a HUGE thank you to marcio for his solution. This worked almost perfectly, saved me hours of effort, and made a huge splash in my app. My boss loved it. I owe you beer. Or several.

首先,非常感谢 marcio 的解决方案。这几乎完美地工作,为我节省了数小时的精力,并在我的应用程序中引起了巨大轰动。我的老板很喜欢。我欠你啤酒。或者几个。

One small correction for iPhone 4 only. I mean the hardware itself, not just iOS 4. They changed the system font on the iPhone 4 from Helvetica (iPhone 3Gs and below) to Helvetic Neue. This caused the translation you're doing from character to glyphs to be off by exactly 4 spots. For example the string "fg" would appear as "bc". I fixed this by explicitly setting the font to "Helvetica" rather than using "systemFontofSize". Now it works like a charm.

仅适用于 iPhone 4 的一个小修正。我指的是硬件本身,而不仅仅是 iOS 4。他们将 iPhone 4 上的系统字体从 Helvetica(iPhone 3G 及以下)更改为 Helvetic Neue。这导致您从字符到字形的转换恰好偏离了 4 个点。例如,字符串“fg”将显示为“bc”。我通过将字体显式设置为“Helvetica”而不是使用“systemFontofSize”来解决这个问题。现在它就像一个魅力。

Again...THANK YOU!

再次谢谢你!