1

我面临与使用 CoreAnimation 为形状设置动画类似的问题

我有一个习惯UIView

我的用户界面视图

- (void)drawRect:(CGRect)rect {
    // Right here, I might also draw some triangle, circle which I do not wish
    // to be animated.

    // ...
    // Calculate minX, minY, ... based on rect and self->value.
    // ...

    // Draw a rounded rectangle based on minX, minY, ...
    // The x-location of rounded rectangle will be different for difference self->value
    CGContextMoveToPoint(context, minx, midy);
    CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
    ...
    ...
    CGContextDrawPath(context, kCGPathFillStroke);        
}

// Usually trigger by controller via button clicked
- (void) setValueViaButtonClicked:(double) value {
    self->currentValue = value;
    dispatch_async(dispatch_get_main_queue(), ^{
        [self setNeedsDisplay];
    });
}

目前,每当我单击具有与旧值不同的新值的按钮时,我都可以看到圆角矩形从旧位置移动到新位置,但没有动画。

我想要动画,只有在明确的按钮点击期间。对于我见过的大多数示例,动画代码是在控制器中执行的,由

  • 动画是通过 Layer 和 CGPathCreateMutable 完成的
  • Layer 和 CGPathCreateMutable 的创建是在视图控制器中执行的。

我想知道,我怎么可能通过MyUIView's执行上述任务setValueViaButtonClicked?由于没有来自 drawRect 的适当rect信息,我将如何配置从创建的路径的信息CGPathCreateMutable

4

1 回答 1

0

我认为您不使用CoreAnimation,而CoreGraphics只是绘制当前状态/值。每当涉及到动画而不是静态图像时,我都会切换到CoreAnimation图层。在您的情况下,我将创建一个UIView子类并CAShapeLayer为您的三角形(或任何形状)添加一个。

它看起来像这样:

@interface MyView ()
@property (nonatomic, strong) CAShapeLayer *shapeLayer;
@property (nonatomic, assign) double currentValue;
@end

@implementation MyView

-(instancetype)init {
  if (self = [super init]) {
    [self setup];
  }
  return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
  if (self = [super initWithCoder:aDecoder]) {
    [self setup];
  }
  return self;
}

- (instancetype)initWithFrame:(CGRect)frame
{
  self = [super initWithFrame:frame];
  if (self) {
    [self setup];
  }
  return self;
}

- (void)setup {
  CAShapeLayer *shape = [CAShapeLayer layer];
  shape.contentsScale = [[UIScreen mainScreen] scale];
  self.shapeLayer = shape;
  [self.layer addSublayer:shape];
}

- (void)layoutSubviews {
  [super layoutSubviews];
  self.shapeLayer.frame = self.bounds;
  self.shapeLayer.path = [self bezierPathForValue:self.currentValue].CGPath;
}

- (UIBezierPath *)bezierPathForValue:(double)value {
  UIBezierPath *path = [UIBezierPath bezierPath];
  [path moveToPoint:...]; // points are depending on currentValue
  return path;
}

- (void)setValueViaButtonClicked:(double) value {
  double oldValue = self.currentValue;
  self.currentValue = value;

  // update model value
  self.shapeLayer.path = [self bezierPathForValue:value].CGPath;

  CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
  pathAnimation.fromValue = (id)[self bezierPathForValue:oldValue].CGPath;
  pathAnimation.toValue = (id)[self bezierPathForValue:value].CGPath;
  pathAnimation.duration = 0.3f;
  [self.shapeLayer addAnimation:pathAnimation forKey:nil];
}

@end
于 2016-04-02T17:06:50.880 回答