Pytanie Kształt animacji i / lub kształtu iOS z koła na kwadrat


Próbuję zmienić okrąg w kwadrat i odwrotnie, a już prawie jestem. Jednak nie animuje się zgodnie z oczekiwaniami. Chciałbym, aby wszystkie narożniki kwadratu były animowane / przekształcane w tym samym czasie, ale otrzymuję:

enter image description here

używam CAShapeLayer i CABasicAnimation w celu animowania właściwości kształtu.

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

- (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 kwadratowa ś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;
}

Stosuję ścieżkę koła do jednej z warstw widoku, ustawię wypełnienie itd. Rysuje idealnie. Następnie w selektorze gestureRecognizer tworzę i uruchom następującą 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: Postępuję zgodnie z sugestią stąd (aby mieć taką samą liczbę segmentów i punktów kontrolnych): Płynna animacja przesunięcia kształtu

Animacja wygląda lepiej niż w poście od góry, ale wciąż nie jest tą, którą chcę osiągnąć :(

Wiem, że mogę to zrobić w prosty sposób CALayer a następnie ustaw odpowiedni poziom cornerRadius zrobić okrąg poza kwadratem / prostokątem, a potem animować cornerRadius Właściwość, aby zmienić ją z koła na kwadrat, ale nadal jestem ekstremalnie ciekawy, czy można to nawet zrobić CAShapeLayer i path animacja.

Z góry dziękuję za pomoc!


11
2017-07-16 18:40


pochodzenie


Wygląda na to, że masz taki sam problem jak to pytanie [stackoverflow.com/questions/17429797/..., na podstawie animacji - może warto rzucić okiem - username tbd
hmm .. Być może - znam to pytanie i poszedłem za sugestią z zaakceptowanej odpowiedzi, ale wciąż jestem dla mnie ślepym zaułkiem. 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


Odpowiedzi:


Po zabawie z 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 dzwonienie closePath dodaje jeszcze dwa. 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


7
2017-12-06 23:29



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


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")

2
2018-02-07 09:21





Mogę bardzo polecić bibliotekę CanvasPodma również predefiniowaną animację "morfingu" i jest łatwa do zintegrowania. Możesz również sprawdzić przykłady na stronie internetowej canvaspod.io.


0
2017-12-07 00:20





Na podstawie odpowiedzi @Danchoys, tutaj jest dla Objective-C.

info to przycisk o wielkości 60 pikseli i infoVC jest następna pchnięta ViewController:

    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];

0
2018-02-17 16:15