尝试使用 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.CurrentMediaTime() 更改显式动画的速度
使用 CAAnimation 在 RMMapView 上为 RMPointAnnotation 设置动画
使用 CAAnimation 检测正在动画的 uiview 子视图的触摸