2014-07-16 20 views
11

Próbuję zmienić okrąg w kwadrat i odwrotnie, a już prawie jestem. Jednak nie animuje się zgodnie z oczekiwaniami. Chciałbym wszystkie narożniki kwadratu być animowane/przekształcił w tym samym czasie, ale co mam jest następujące:Kształt animacji iOS iOS od koła do kwadratu

enter image description here

używam CAShapeLayer i CABasicAnimation aby animować właściwości kształtu.

Oto jak utworzyć ścieżkę kółko:

- (UIBezierPath *)circlePathWithCenter:(CGPoint)center radius:(CGFloat)radius 
{  
    UIBezierPath *circlePath = [UIBezierPath bezierPath]; 
    [circlePath addArcWithCenter:center radius:radius startAngle:0 endAngle:M_PI/2 clockwise:YES]; 
    [circlePath addArcWithCenter:center radius:radius startAngle:M_PI/2 endAngle:M_PI clockwise:YES]; 
    [circlePath addArcWithCenter:center radius:radius startAngle:M_PI endAngle:3*M_PI/2 clockwise:YES]; 
    [circlePath addArcWithCenter:center radius:radius startAngle:3*M_PI/2 endAngle:M_PI clockwise:YES]; 
    [circlePath closePath]; 
    return circlePath; 
} 

Oto kwadrat ścieżka:

- (UIBezierPath *)squarePathWithCenter:(CGPoint)center size:(CGFloat)size 
{ 
    CGFloat startX = center.x-size/2; 
    CGFloat startY = center.y-size/2; 

    UIBezierPath *squarePath = [UIBezierPath bezierPath]; 
    [squarePath moveToPoint:CGPointMake(startX, startY)]; 
    [squarePath addLineToPoint:CGPointMake(startX+size, startY)]; 
    [squarePath addLineToPoint:CGPointMake(startX+size, startY+size)]; 
    [squarePath addLineToPoint:CGPointMake(startX, startY+size)]; 
    [squarePath closePath]; 
    return squarePath; 
} 

ubiegać ścieżkę koło jednego z moim zdaniem w warstwach ustaw wypełnienie itd. Doskonale się rysuje. Wtedy w moim selektora gestureRecognizer utworzyć i uruchomić następujące animację:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"]; 
    animation.duration = 1; 
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 

animation.fromValue = (__bridge id)(self.stateLayer.path); 
     animation.toValue = (__bridge id)(self.stopPath.CGPath); 
self.stateLayer.path = self.stopPath.CGPath; 

[self.stateLayer addAnimation:animation forKey:@"animatePath"]; 

Jak można zauważyć w circlePathWithCenter:radius: i squarePathWithCenter:size: śledzę sugestię stąd (mają taką samą liczbę segmentów i punktów kontrolnych): Smooth shape shift animation

animacja wygląda lepiej niż w poście z góry, ale to jeszcze nie jest jeden chcę osiągnąć :(

wiem, że mogę zrobić to z prostego CALayer a następnie ustawić Odpowiedni poziom cornerRadius, aby wykreślić okrąg z kwadratu/prostokąta, a następnie animować właściwość, aby zmienić go z koła na kwadrat, ale nadal jestem ekstremalnie ciekawy, czy jest to nawet możliwe z animacją CAShapeLayer i path.

Z góry dziękujemy za pomoc!

+0

Wygląda na to, że masz ten sam problem jak to pytanie [http://stackoverflow.com/questions/17429797/smooth-shape-shift-animation], na podstawie animacji - może być wart zobaczenia –

+0

hmm .. Być może - znam to pytanie i podążałem za sugestią z zaakceptowanej odpowiedzi, ale wciąż jestem sierżantem koniec dla mnie. Mam taką samą liczbę segmentów/punktów kontrolnych, które moim zdaniem pomagają, ponieważ moja animacja jest w nieco lepszej formie, niż ta, która istnieje, ale nie ma wskazówki, jak ją poprawić. – fgeorgiew

Odpowiedz

7

Po zabawieniu się nim przez chwilę na placu zabaw zauważyłem, że każdy łuk dodaje dwa segmenty do ścieżki Beziera, a nie tylko jednego. Ponadto wywołanie closePath powoduje dodanie dwóch kolejnych. Aby zachować spójność liczby segmentów, doszedłem do dodania fałszywych segmentów do mojej ścieżki kwadratowej. Kod znajduje się w Swift, ale myślę, że to nie ma znaczenia.

func circlePathWithCenter(center: CGPoint, radius: CGFloat) -> UIBezierPath { 
    let circlePath = UIBezierPath() 
    circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI), endAngle: -CGFloat(M_PI/2), clockwise: true) 
    circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI/2), endAngle: 0, clockwise: true) 
    circlePath.addArcWithCenter(center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI/2), clockwise: true) 
    circlePath.addArcWithCenter(center, radius: radius, startAngle: CGFloat(M_PI/2), endAngle: CGFloat(M_PI), clockwise: true) 
    circlePath.closePath() 
    return circlePath 
} 

func squarePathWithCenter(center: CGPoint, side: CGFloat) -> UIBezierPath { 
    let squarePath = UIBezierPath() 
    let startX = center.x - side/2 
    let startY = center.y - side/2 
    squarePath.moveToPoint(CGPoint(x: startX, y: startY)) 
    squarePath.addLineToPoint(squarePath.currentPoint) 
    squarePath.addLineToPoint(CGPoint(x: startX + side, y: startY)) 
    squarePath.addLineToPoint(squarePath.currentPoint) 
    squarePath.addLineToPoint(CGPoint(x: startX + side, y: startY + side)) 
    squarePath.addLineToPoint(squarePath.currentPoint) 
    squarePath.addLineToPoint(CGPoint(x: startX, y: startY + side)) 
    squarePath.addLineToPoint(squarePath.currentPoint) 
    squarePath.closePath() 
    return squarePath 
} 

enter image description here

+0

dobre odkrycie w dwóch punktach, wykonane w wersji obiektywnej-c. –

0

bardzo polecam bibliotekę CanvasPod, posiada również predefiniowane "morph" animacja i jest łatwy do zintegrowania. Możesz również sprawdzić przykłady na stronie internetowej canvaspod.io.

2

Wiem, że to stare pytanie, ale to może pomóc komuś.

Myślę, że lepiej animować promień narożnika, aby uzyskać ten efekt.

let v1 = UIView(frame: CGRect(x: 100, y: 100, width: 50, height: 50)) 
    v1.backgroundColor = UIColor.green 
    view.addSubview(v1) 

animacja:

let animation = CABasicAnimation(keyPath: "cornerRadius") 
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 
    animation.fillMode = kCAFillModeForwards 
    animation.isRemovedOnCompletion = false 
    animation.fromValue = v1.layer.cornerRadius 
    animation.toValue = v1.bounds.width/2 
    animation.duration = 3 
    v1.layer.add(animation, forKey: "cornerRadius") 
0

podstawie @Danchoys odpowiedź, to jest tutaj dla Objective-C.

informacji jest przycisk 60px i infoVC jest kolejnym ViewController pchanych:

UIBezierPath * maskPath = [UIBezierPath new]; 
    [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(180) endAngle:DEGREES_TO_RADIANS(270) clockwise:true]; 
    [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(270) endAngle:DEGREES_TO_RADIANS(0) clockwise:true]; 
    [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(0) endAngle:DEGREES_TO_RADIANS(90) clockwise:true]; 
    [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(90) endAngle:DEGREES_TO_RADIANS(180) clockwise:true]; 
    [maskPath closePath]; 

    UIBezierPath * endPath = [UIBezierPath new]; 
    [endPath moveToPoint:CGPointMake(0,0)]; 
    [endPath addLineToPoint:endPath.currentPoint]; 
    [endPath addLineToPoint:CGPointMake(w, 0)]; 
    [endPath addLineToPoint:endPath.currentPoint]; 
    [endPath addLineToPoint:CGPointMake(w, h)]; 
    [endPath addLineToPoint:endPath.currentPoint]; 
    [endPath addLineToPoint:CGPointMake(0, h)]; 
    [endPath addLineToPoint:endPath.currentPoint]; 
    [endPath closePath]; 

    CAShapeLayer *maskLayer = [CAShapeLayer layer]; 
    maskLayer.frame = info.bounds; 
    maskLayer.path = maskPath.CGPath; 
    _infoVC.view.layer.mask = maskLayer; 

    CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"path"]; 
    animation.fromValue = (id)maskPath.CGPath; 
    animation.toValue = (id)endPath.CGPath; 
    animation.duration = 0.3f; 
    [maskLayer addAnimation:animation forKey:nil]; 
    [maskLayer setPath:endPath.CGPath]; 
Powiązane problemy