2013-12-08 1 views
0

Мне нужны советы по рисованию в iOS и, более конкретно, о графике производительности. Я прочитал много статей о чертеже в iOS7, но мне не удалось получить правильный результат.Динамический чертеж в iOS7 с Core Graphic

У меня есть точки, которые мне нужны, чтобы связать их в правильном порядке. Благодаря моему Dot & Упругие классы, мне это удается. Я очень доволен: http://d.pr/v/nYzH

Эти точки представляют собой карту, и мне нужно использовать временную шкалу для перемещения между каждой карточкой. Я использую библиотеку iCarousel для реализации этой цели. Я работаю как UITableView, за исключением того, что мы управляем представлением. Просмотров могут быть повторно использованы и т. Д.

Но проблема начинается там. Это результат: http://d.pr/v/y7dq

Первая проблема: точки имеют низкое разрешение. Вторая реальная проблема: у меня есть некоторые запаздывания.

Здесь вы можете найти мои файлы, используемые для рисования dot &.

Dot.m файл

@interface Dot() { 
    CAShapeLayer *_foreground; 
    CAShapeLayer *_background; 
    UIBezierPath *_path; 
} 
@end 

@implementation Dot 

- (id)initWithPoint:(CGPoint)point andRadius:(CGFloat)radius 
{ 
    self = [super init]; 
    if (self) { 
     self.frame = CGRectMake(point.x, point.y, (radius + 10) * 2, (radius + 10) * 2); 
     self.radius = radius; 
     self.color = [UIColor colorWithHexString:@"#FFFFFF"]; 
     [self setPosition:point]; 
     [self setupPath]; 

     _background = [CAShapeLayer layer]; 
     [_background setFrame:CGRectMake(0, 0, self.width, self.height)]; 
     [_background setPath:_path.CGPath]; 
     [self.layer addSublayer:_background]; 
     [self drawStrokedDotToLayer:_background]; 

     _foreground = [CAShapeLayer layer]; 
     [_foreground setFrame:CGRectMake(0, 0, self.width, self.height)]; 
     [_foreground setPath:_path.CGPath]; 
     [self.layer addSublayer:_foreground]; 
     [self drawPlainDotToLayer:_foreground]; 

     [self setBackgroundColor:[UIColor clearColor]]; 

     self.state = DotStateHidden; 
    } 
    return self; 
} 

- (void)setupPath 
{ 
    _path = [UIBezierPath bezierPath]; 
    [_path addArcWithCenter:CGPointMake(self.width*.5f, self.height*.5f) radius:self.radius startAngle:0 endAngle:M_PI * 2 clockwise:NO]; 
} 

#pragma mark - Setters 

- (void)setPosition:(CGPoint)position 
{ 
    self.x = position.x - self.width*.5f; 
    self.y = position.y - self.width*.5f; 
} 

- (CGPoint)position 
{ 
    return CGPointMake(self.x + self.width*.5f, self.y + self.height*.5f); 
} 

- (void)setState:(DotState)state 
{ 
    _state = state; 

    CAKeyframeAnimation *foregroundAnim = nil; 
    CAKeyframeAnimation *backgroundAnim = nil; 

    switch (_state) { 
     case DotStateFeedback: 
     { 
      self.color = [UIColor colorWithHexString:@"#FFFFFF"]; 
      [self drawFeedback:_foreground]; 
      [self removeGlow:_foreground]; 

      foregroundAnim = [self animation:ScaleIn function:ExponentialEaseOut duration:1.f]; 
      break; 
     } 

     case DotStateVisible: 
     { 
      self.color = [UIColor colorWithHexString:@"#FFFFFF"]; 
      [self drawPlainDotToLayer:_foreground]; 
      [self drawGlow:_foreground]; 
      [self drawStrokedDotToLayer:_background]; 

      foregroundAnim = [self animation:ScaleIn function:ExponentialEaseOut duration:.2f]; 
      break; 
     } 
     case DotStateNext: 
     { 
      self.color = [UIColor colorWithHexString:@"#FFFFFF"]; 
      [self drawStrokedDotToLayer:_background]; 

      foregroundAnim = [self animation:ScaleOut function:ExponentialEaseOut duration:.16f]; 
      backgroundAnim = [self animation:ScaleIn function:ExponentialEaseOut duration:.25f]; 
      [foregroundAnim setBeginTime:CACurrentMediaTime() + .04f]; 
      break; 
     } 

     case DotStateHidden: 
     default: 
     { 
      self.color = [UIColor colorWithHexString:@"#333333"]; 
      [self drawPlainDotToLayer:_foreground]; 
      [self removeGlow:_foreground]; 

      foregroundAnim = [self animation:ScaleIn function:ExponentialEaseOut duration:.5f]; 
      backgroundAnim = [self animation:ScaleOut function:ExponentialEaseOut duration:.25f]; 
      break; 
     } 
    } 

    if (foregroundAnim) [_foreground addAnimation:foregroundAnim forKey:nil]; 
    if (backgroundAnim) [_background addAnimation:backgroundAnim forKey:nil]; 
} 

#pragma mark - Drawing 

- (void)drawStrokedDotToLayer:(CAShapeLayer *)layer 
{ 
    [layer setLineWidth:2.f]; 
    [layer setStrokeColor:self.color.CGColor]; 
    [layer setFillColor:[UIColor colorWithHexString:@"#1F1F1F"].CGColor]; 
} 

- (void)drawPlainDotToLayer:(CAShapeLayer *)layer 
{ 
    [layer setLineWidth:2.f]; 
    [layer setStrokeColor:[UIColor clearColor].CGColor]; 
    [layer setFillColor:self.color.CGColor]; 
} 

- (void)drawFeedback:(CAShapeLayer *)layer 
{ 
    [layer setLineWidth:2.f]; 
    [layer setStrokeColor:[UIColor clearColor].CGColor]; 
    [layer setFillColor:[UIColor colorWithHex:0xFFFFFF andAlpha:.025f].CGColor]; 
} 

- (void)drawGlow:(CAShapeLayer *)layer 
{ 
    [layer setShadowRadius:8]; 
    [layer setShadowOpacity:1.f]; 
    [layer setShadowOffset:CGSizeMake(0, 0)]; 
    [layer setShadowColor:[UIColor whiteColor].CGColor]; 
    [layer didChangeValueForKey:@"path"]; 
} 

- (void)removeGlow:(CAShapeLayer *)layer 
{ 
    [layer setShadowRadius:0]; 
    [layer setShadowOpacity:0.f]; 
    [layer setShadowOffset:CGSizeMake(0, 0)]; 
    [layer setShadowColor:[UIColor clearColor].CGColor]; 
    [layer didChangeValueForKey:@"path"]; 
} 

- (CAKeyframeAnimation *)animation:(NSInteger)name function:(AHEasingFunction)function duration:(CGFloat)duration 
{ 
    CAKeyframeAnimation *animation; 

    switch (name) { 
     case ScaleIn: 
     { 
      animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale" function:function fromValue:0.f toValue:1.f]; 
      break; 
     } 

     case ScaleInFeedback: 
     { 
      animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale" function:function fromValue:0.f toValue:3.f]; 
      break; 
     } 

     case ScaleOut: 
     { 
      animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale" function:function fromValue:1.f toValue:0.f]; 
      break; 
     } 

     default: 
     { 
      animation = [CAKeyframeAnimation animationWithKeyPath:@"opacity" function:function fromValue:0.f toValue:1.f]; 
      break; 
     } 
    } 

    animation.duration = duration; 
    animation.fillMode = kCAFillModeForwards; 
    animation.removedOnCompletion = NO; 

    return animation; 
} 

@end 

Elastic.m

@interface Elastic() { 
    UIBezierPath *_path; 
    UIImage *_image; 
} 

@end 

@implementation Elastic 

- (id)initWithDotOne:(Dot *)aDotOne DotTwo:(Dot *)aDotTwo 
{ 
    self = [super initWithFrame:[UIScreen mainScreen].bounds]; 
    if (self) { 
     self.dotOne = aDotOne; 
     self.dotTwo = aDotTwo; 

     self.displayDots = NO; 
     self.feedBack = NO; 

     self.curveRadius = 4; 

     [self setBackgroundColor:[UIColor clearColor]]; 

     _path = [UIBezierPath bezierPath]; 
     [self updatePath]; 
    } 
    return self; 
} 

- (void)setDisplayDots:(BOOL)displayDots 
{ 
    _displayDots = displayDots; 

    if (_displayDots) { 
     [self addSubview:self.dotTwo]; 
    } else { 
     [self.dotTwo removeFromSuperview]; 
    } 
} 

- (void)drawRect:(CGRect)rect 
{ 
    [_image drawInRect:rect]; 
} 

- (void)updatePath 
{ 
    // Initialize variables 
    CGFloat dist = distance(self.dotOne.position, self.dotTwo.position); 
    CGFloat angle = angleBetweenPoints(self.dotOne.position, self.dotTwo.position) + M_PI * 1.5; 

    // Points 
    CGPoint ptA = CGPointMake(
           self.dotOne.position.x + cosf(angle) * (self.dotOne.radius - self.curveRadius), 
           self.dotOne.position.y + sinf(angle) * (self.dotOne.radius - self.curveRadius) 
          ); 
    CGPoint ptB = CGPointMake(
           self.dotOne.position.x + cosf(angle + M_PI) * (self.dotOne.radius - self.curveRadius), 
           self.dotOne.position.y + sinf(angle + M_PI) * (self.dotOne.radius - self.curveRadius) 
          ); 

    CGPoint ptC = CGPointMake(
           self.dotTwo.position.x + cosf(angle) * (self.dotTwo.radius - self.curveRadius), 
           self.dotTwo.position.y + sinf(angle) * (self.dotTwo.radius - self.curveRadius) 
          ); 
    CGPoint ptD = CGPointMake(
           self.dotTwo.position.x + cosf(angle + M_PI) * (self.dotTwo.radius - self.curveRadius), 
           self.dotTwo.position.y + sinf(angle + M_PI) * (self.dotTwo.radius - self.curveRadius) 
          ); 

    // Bezier 
    CGFloat mapA = angle + M_PI_2 + map(dist, 150, 350, 0.0001, 0.0005); 
    CGFloat mapB = angle + M_PI_2 - map(dist, 150, 350, 0.0001, 0.0005); 

    CGPoint bzA = CGPointMake(self.dotOne.position.x + cosf(mapA) * dist*.5f, self.dotOne.position.y + sinf(mapA) * dist*.5f); 
    CGPoint bzB = CGPointMake(self.dotOne.position.x + cosf(mapB) * dist*.5f, self.dotOne.position.y + sinf(mapB) * dist*.5f); 

    // Start drawing path 
    [_path moveToPoint:ptA]; 
    [_path addQuadCurveToPoint:ptC controlPoint:bzA]; 
    [_path addLineToPoint:ptD]; 
    [_path addQuadCurveToPoint:ptB controlPoint:bzB]; 

    [self drawBitmap]; 

    [self setNeedsDisplay]; 
} 

- (void)drawBitmap 
{ 
    _image = nil; 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0); 
    [_image drawAtPoint:CGPointZero]; 
    [[UIColor whiteColor] setFill]; 
    [_path fill]; 

    _image = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    [_path removeAllPoints]; 
} 

@end 

ответ

0

Ваши видео смотреть, как если бы они были записаны на тренажере, а не устройство. Тестирование симулятора бессмысленно для производительности, особенно для графической производительности, поскольку выделенный графический процессор недоступен для симулятора.

При этом на симуляторе тяжелые операции с GPU будут значительно хуже, чем устройство.

Таким образом, я могу предложить вам следующий совет: тестирование производительности

  1. Run на устройстве, в идеале самый медленный, который вы ориентируетесь.
  2. Используйте инструмент основной анимации, который даст вам частоту кадров и профилирование времени и выделит дорогие области вашего кода.
  3. Исследовать различные графические опции отладки, доступные через инструменты на устройстве, а также - закадровый рендеринга, перерисовки и так далее

Если вы любите iCarousel, то автор этого проекта, Ник Локвуд, имеет отличную книгу для базовой анимации для iOS, которая содержит главу о настройке производительности.