尝试使用CAAnimation和CATextLayer滑动文本

时间:2011-06-09 17:23:01

标签: macos core-animation calayer quartz-graphics caanimation


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

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

代码(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 个答案:

答案 0 :(得分:0)

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

新实施,如果有人想看到它:

#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