【问题标题】:iPhone "slide to unlock" animationiPhone“滑动解锁”动画
【发布时间】:2010-10-01 02:00:42
【问题描述】:

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

我考虑过某种动画蒙版 - 但出于性能原因,在 iPhone OS 上无法使用蒙版。

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

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

【问题讨论】:

  • 我是否正确理解 iPhone 不支持透明度? (我没有自己的所以我不知道)反正根据这个视频,实际的文字是可以改变的,所以它不是一些预渲染的动画:uk.youtube.com/watch?v=PVhRnL55cJQ
  • 这是一部越狱手机。我想知道如何使用官方 SDK 拉出这个动画。也就是说,不使用隐藏的 API 或访问从 CoreFilters 等 beta 版本中删除的内容。

标签: ios objective-c cocoa-touch core-animation


【解决方案1】:

也许它只是一个渲染出来的动画——你知道,一系列的剧照一个接一个地播放。不一定是动态效果。

更新:没关系,DrJokepu 发布的视频证明它是动态生成的。

【讨论】:

    【解决方案2】:

    您可以使用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)
    

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

    【讨论】:

    • 最后一定要喜欢GoreAnimation
    • 想知道什么时候有人会接受它。花了将近一年的时间。
    • @Sonts:您可能需要改用kCGEncodingFontSpecific
    • @rpetrich:它完全坏了。 AFAIK,对于 kCGEncodingFontSpecific,我必须提供自己的字符到字形的翻译,而 iOS 中没有相应的 API。
    【解决方案3】:

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

    我已经使用 rpetrich 的方法实现了一个外观不错的 Slide to Cancel UIViewController。你可以从here下载我实现的Xcode项目。

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

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

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

    感谢您的帮助!

    【讨论】:

      【解决方案4】:

      不是那么新鲜......但也许它会有用

      #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];
      }
      

      【讨论】:

      • CGFontGetGlyphsForUnichars - 一些使用该报告的人因为使用私有 API 而未通过审核?
      【解决方案5】:

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

      在任何普通的 UIViewController 中试试这个(你可以从一个基于 View-based application 项目模板的新 Xcode 项目开始),或者获取我的 Xcode 项目here

      请注意,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];
      }
      

      这段代码使用的图片是:

      【讨论】:

      • 很好的解决方案。对于那些有兴趣不为标签添加资源的人,我从UILabel(或任何其他UIView)创建了一个UIImageUIGraphicsBeginImageContext(_label); [[_label layer] renderInContext:UIGraphicsGetCurrentContext()]; UIImage *textImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
      【解决方案6】:

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

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

      再次...谢谢!

      【讨论】:

        【解决方案7】:

        我将上面 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
        

        【讨论】:

        • 这对我来说不适合开箱即用......也许我在我的 UILabel 的配置中遗漏了一些特定的东西。在不创建文本图像的情况下执行此操作的完整示例会很棒。
        • @bandejapaisa 您可能还没有将 Mask.png 添加到您的资源中
        • 更好地使用FLT_MAX 而不是1e100f
        【解决方案8】:

        另一个使用图层蒙版的解决方案,而是手动绘制渐变并且不需要图像。 View 是带有动画的视图,透明度是一个从 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 版本:

        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")
        

        斯威夫特 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)
        }
        

        【讨论】:

        • 像魅力一样工作!您应该按照文档的建议将 repeatCount 常量替换为 HUGE_VALF。
        • 最好!超级简单,适用于各种 CALayer!为此做了一个方法:-(void)addSlidingTextEffectToLabel:(UILabel*)label direction:(UISwipeGestureRecognizerDirection)dir gradientWidth:(CGFloat)gradientWidth speed:(CGFloat)dur intensity:(CGFloat)intensity;
        • @Samsinite 一个问题,为什么在设置图层蒙版之前需要[view removeFromSuperview],之后需要[superview addSubview:view]?没有它似乎可以正常工作,可能是我遗漏了什么?
        • @dariaa,自从我完成任何 iOS 开发以来已经一年多了,所以我的记忆力很差。但是,看起来它只会在将渐变蒙版添加到其父视图时才绘制渐变蒙版。一旦它已经被添加到父视图(绘制),任何添加的图层蒙版都不会被绘制。不过现在这可能已经改变了,这段代码是在 iOS 6 天期间编写的。
        • 不错的一个!感谢分享。
        【解决方案9】:

        我向 GitHub 上传了一个帮助制作“滑动解锁”动画的小项目。

        https://github.com/GabrielMassana/GM_FSHighlightAnimationAdditions

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

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

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

        干杯

        【讨论】:

          【解决方案10】:
          • 顶部:具有不透明背景和清晰文本的 UILabel
            • 在drawRect中呈现清晰的文本:func通过复杂的屏蔽过程
          • 中间:执行重复动画的工作视图将图像移动到顶部标签后面
          • Bottom:按该顺序添加中间和顶部子视图的 UIView。可以是您希望文本的任何颜色

          一个例子可以在这里看到https://github.com/jhurray/AnimatedLabelExample

          【讨论】:

            【解决方案11】:

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

            【讨论】:

              【解决方案12】:

              我从上述解决方案中汲取了精华,并创建了一个可以为您解决所有问题的简洁方法:

              - (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];
              }
              

              【讨论】:

                【解决方案13】:

                这是一个 SwiftUI 版本:

                struct Shimmer: AnimatableModifier {
                
                    private let gradient: Gradient
                
                    init(sideColor: Color = Color(white: 0.25), middleColor: Color = .white) {
                        gradient = Gradient(colors: [sideColor, middleColor, sideColor])
                    }
                
                    @State private var position: CGFloat = 0
                    var animatableData: CGFloat {
                        get { position }
                        set { position = newValue }
                    }
                
                    func body(content: Content) -> some View {
                        content
                            .overlay(LinearGradient(
                                        gradient: gradient,
                                        startPoint: .init(x: position - 0.2 * (1 - position), y: 0.5),
                                        endPoint: .init(x: position + 0.2 * position, y: 0.5)))
                            .mask(content)
                            .onAppear {
                                withAnimation(Animation
                                                .linear(duration: 2)
                                                .delay(1)
                                                .repeatForever(autoreverses: false)) {
                                    position = 1
                                }
                            }
                    }
                }
                

                像这样使用它:

                Text("slide to unlock")
                    .modifier(Shimmer())
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-06-15
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-11-08
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多