尝试使用 CAAnimation 和 CATextLayer 滑动文本

Posted

技术标签:

【中文标题】尝试使用 CAAnimation 和 CATextLayer 滑动文本【英文标题】:Trying to slide text with CAAnimation and CATextLayer 【发布时间】:2011-06-09 17:23:00 【问题描述】:

我正在尝试使用 CATextLayer 在视图中滑动文本,但它显然不起作用:

函数animationDidStop:finished: 被调用一次,但flag 的值为NO。

代码(NSView 子类):

#import "AppStatusItemView.h"

#define DEFAULT_FRAME (NSMakeRect(0 , 0 , 80 , 20))

/* ============================================================================
 MARK: -
 MARK: Private Interface
 =========================================================================== */
@interface AppStatusItemView (Private)
- (void)updateLayer;
- (CATextLayer *)makeTextLayer;
- (CABasicAnimation *)makeMoveAnimation;
@end

/* ============================================================================
 MARK: -
 MARK: Public Implementation
 =========================================================================== */
@implementation AppStatusItemView
/* MARK: Init */
- (id)initWithText:(NSString *)pS 
    self = [self initWithFrame:DEFAULT_FRAME];
    if(self != nil) 
        _text = [pS retain];

        /* initialize view */
        [self updateLayer];
    
    return self;


- (void)dealloc 
    [_text release];
    [_textLayer release];
    [super dealloc];


/* MARK: Properties */ 
@synthesize text=_text;
- (void)setText:(NSString *)pT 
    if(![_text isEqualToString:pT]) 
        [_text release];
        _text = [pT retain];

        [self updateLayer];
    


/* MARK: Animation Delegate */
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag 
    if(flag) 
        CABasicAnimation *myAnimation;
        myAnimation = [self makeMoveAnimation];
        [myAnimation setDelegate:self];
        [_textLayer addAnimation:myAnimation forKey:@"slide"];
    

@end

/* ============================================================================
 MARK: -
 MARK: Private Implementation
 =========================================================================== */
@implementation AppStatusItemView (Private)
- (void)updateLayer 
    CABasicAnimation *myAnimation;
    CATextLayer *myLayer;

    myLayer = [self makeTextLayer];
    myAnimation = [self makeMoveAnimation];

    [_textLayer removeAllAnimations];
    [_textLayer removeFromSuperlayer];

    [_textLayer release];
    _textLayer = [myLayer retain];
    [[self layer] addSublayer:_textLayer];

    [myAnimation setDelegate:self];
    [_textLayer addAnimation:myAnimation forKey:@"slide"];


- (CATextLayer *)makeTextLayer 
    CATextLayer *layer;
    NSString *myString;
    CGRect myFrame;
    CGPoint myPosition;

    myString = _text;
    layer = [[CATextLayer layer] retain];
    [layer setString:myString];
    myFrame.origin = CGPointZero;
    myFrame.size = NSSizeToCGSize([myString sizeWithAttributes:nil]);
    [layer setFrame:myFrame];

    myPosition.y = 1.0;
    myPosition.x = [self bounds].size.width + 2.0;
    [layer setPosition:myPosition];

    return [layer autorelease];


- (CABasicAnimation *)makeMoveAnimation 
    CABasicAnimation *animation;
    CGPoint myPoint;

    myPoint.y = 1.0;
    animation = [CABasicAnimation animationWithKeyPath:@"position"];
    myPoint.x = [self bounds].size.width + 1.0;
    [animation setFromValue:[NSValue valueWithPoint:myPoint]];
    myPoint.x = -[_textLayer bounds].size.width - 1.0;
    [animation setToValue:[NSValue valueWithPoint:myPoint]];
    [animation setTimingFunction:
     [CAMediaTimingFunction 
      functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];

    [animation setDuration:5.0];

    return animation;

@end

提前谢谢你, ief2

【问题讨论】:

【参考方案1】:

我已经更改了代码,但没有调试之前的代码。

新的实现,如果有人想看的话:

#import "AppStatusItemView.h"

#define DEFAULT_FRAME (NSMakeRect(0 , 0 , 140 , 20))
#define SLIDE_SPEED (30.0) /* points per second */

/* ============================================================================
 MARK: -
 MARK: Private Interface
 =========================================================================== */
@interface AppStatusItemView (Private)
- (void)slide;
- (NSTimeInterval)intervalWithWidth:(CGFloat)w speed:(CGFloat)s;
@end

/* ============================================================================
 MARK: -
 MARK: Public Implementation
 =========================================================================== */
@implementation AppStatusItemView
/* MARK: Init */
- (id)initWithText:(NSString *)pS 
    self = [self initWithFrame:DEFAULT_FRAME];
    if(self != nil) 
        _text = [pS retain];

        /* Create root layer */
        
            //CGColorRef myColor = CGColorCreateGenericRGB(0.5 , 0.0 , 0.0 , 0.5);
            _rootLayer = [[CAScrollLayer layer] retain];
            [_rootLayer setFrame:NSRectToCGRect([self bounds])];
            //[_rootLayer setBackgroundColor:myColor];
            [self setWantsLayer:YES];
            [self setLayer:_rootLayer];
            //CGColorRelease(myColor);
        

        /* Create text layer */
        
            CGColorRef myColor = CGColorCreateGenericRGB(0.0 , 0.0 , 0.0 , 1.0);
            _textLayer = [[CATextLayer layer] retain];
            [_textLayer setFontSize:12.0];
            [_textLayer setForegroundColor:myColor];
            [self slide];
            CGColorRelease(myColor);
        

    
    return self;


- (void)dealloc 
    [_text release];
    [_textLayer release];
    [_rootLayer release];
    [super dealloc];


/* MARK: Properties */ 
@synthesize text=_text;
- (void)setText:(NSString *)pT 
    if(![_text isEqualToString:pT]) 
        [_text release];
        _text = [pT retain];
    


/* MARK: Animation Delegate */
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag 
    if(flag) 
        [self slide];
    

@end

/* ============================================================================
 MARK: -
 MARK: Private Implementation
 =========================================================================== */
@implementation AppStatusItemView (Private)
- (void)slide 
    NSRect startFrame, endFrame;
    NSPoint startPosititon, endPosition;
    NSSize textSize;

    [_textLayer removeFromSuperlayer];

    /* Set start frame and position */
    
        NSDictionary *attributes;
        NSFont *font;
        CGFloat h;

        font = [NSFont fontWithName:@"Helvetica" 
                               size:12.0];
        attributes = [NSDictionary dictionaryWithObject:font 
                                                 forKey:NSFontAttributeName];
        textSize = [_text sizeWithAttributes:attributes];

        h = ([self bounds].size.height - textSize.height) / 2.0;
        startFrame = NSMakeRect([self bounds].size.width,
                                h, textSize.width , textSize.height);
        startPosititon.x = [self bounds].size.width + textSize.width / 2.0;
        startPosititon.y = [self bounds].size.height / 2.0;

        [_textLayer setString:_text];
        [_textLayer setFrame:NSRectToCGRect(startFrame)];
        [_textLayer setPosition:NSPointToCGPoint(startPosititon)];
    

    /* Slide to end position */
    
        CGFloat h;
        CABasicAnimation *animation;

        h = ([self bounds].size.height - textSize.height) / 2.0;
        endFrame = NSMakeRect(0.0 - textSize.width, h, 
                              textSize.width, 
                              textSize.height);
        endPosition.x = -textSize.width / 2.0;
        endPosition.y = [self bounds].size.height / 2.0;

        animation = [CABasicAnimation animationWithKeyPath:@"position"];
        [animation setFromValue:
         [NSValue valueWithPoint:startPosititon]];
        [animation setToValue:
         [NSValue valueWithPoint:endPosition]];
        [animation setDelegate:self];
        [animation setDuration:
         [self intervalWithWidth:textSize.width speed:SLIDE_SPEED]];
        [animation setTimingFunction:
         [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];

        [_textLayer addAnimation:animation forKey:@"slide"];

        //p[_textLayer setFrame:NSRectToCGRect(endFrame)];
        [_textLayer setPosition:NSPointToCGPoint(endPosition)];
    

    [_rootLayer addSublayer:_textLayer];


- (NSTimeInterval)intervalWithWidth:(CGFloat)w speed:(CGFloat)s 
    return (NSTimeInterval)(w / s);

@end

【讨论】:

以上是关于尝试使用 CAAnimation 和 CATextLayer 滑动文本的主要内容,如果未能解决你的问题,请参考以下文章

CAAnimation 跟踪进度

使用 CAAnimation.CurrentMediaTime() 更改显式动画的速度

使用 CAAnimation 在 RMMapView 上为 RMPointAnnotation 设置动画

使用 CAAnimation 检测正在动画的 uiview 子视图的触摸

CAAnimation 在 CALayer 上没有按预期工作

从 CAAnimation 获取 UIVIew