2013-03-04 15 views
9

Ich versuche, einige der 2D-Übergänge in Impress.js sample presentation in Objective C zu reproduzieren. Speziell das Drehen, Schwenken und Skalieren - im Moment konzentriere ich mich auf die Skalierung.Wie skaliere ich den Übergang UILabel ohne viel Speicher zu verwenden?

Ich habe versucht, ein UILabel zu skalieren, wo es "den Bildschirm passiert", wie die "visualisieren Sie Ihre großen Gedanken" -> "und winzige Ideen" in der Beispielpräsentation tut.

Das ist, was ich bisher versucht habe:

UILabel *label = [[UILabel alloc] init]; 

label.text = @"Hello World!"; 
label.textColor = [UIColor blackColor]; 
label.font = [UIFont fontWithName:@"Arial" size:18.f]; 
[label sizeToFit]; 
label.center = CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2); 
[self.view addSubview:label]; 

label.contentScaleFactor *= 80; 

[UIView animateWithDuration:5 animations:^{ 
    label.transform = CGAffineTransformScale(label.transform, 80, 80); 
}]; 

Leider frisst dies etwa bis ~ 30-60 MB RAM, je nachdem, was der contentScaleFactor und erste Schriftgröße ist. Wenn ich den contentScaleFactor nicht vergrößere, sieht der Text verschwommen aus. Auch die Erhöhung der Schriftgröße scheint genau so viel Speicher zu verbrauchen.

Hier ist, was es im Profiler aussieht:

enter image description here

Und das ist nur eine einzige UILabel.

Gibt es eine Möglichkeit, dies zu tun, ohne so viel Speicher zu verbrauchen, ohne die Qualität des darzustellenden Textes oder die Übergänge zu opfern?

+0

Wie auch immer, sehen Sie sich CATransformLayer als eine Möglichkeit an, Layer zu gruppieren und zu transformieren. –

+0

Aktualisierte Frage, um nach dem Skalieren eines UILabel auf den Speicherverbrauch zu konzentrieren. Die vorherige Frage war zu weit gefasst (und als solche geschlossen). Obwohl die derzeit akzeptierte Antwort fantastisch ist, wird das Problem in der aktualisierten Frage nicht angesprochen. Während ich noch ein Bounty darauf setzen möchte, habe ich sehr wenig Rep, um weitere 500 fallen zu lassen. – Luke

Antwort

4

Project download link

Ich glaube nicht, ist es notwendig, Quarz verlassen diese Wiedergabe zu erreichen. Alles, was Sie beschrieben haben, und alles, was ich aus Impress.js zusammengetragen habe, scheint replizierbar zu sein, indem Transformationen (meist 2D, einige 3D) auf eine Reihe von UILabels angewendet werden, die zu einer Containeransicht hinzugefügt werden Hauptansicht.

Um dies zu tun, das Projekt, das ich erstellt wurde, verwendet eine Unterklasse von UILabel dem Titel „ImpressLabel“ mit einer zusätzlichen Funktion init wo statt dem Etikett einen Rahmen vorbei, können Sie es eine Größe, einen Mittelpunkt und ein CGFloat für den Pass Label-Rotation auf der Z-Achse. Diese Transformation wird beim Instanziieren auf die Beschriftung angewendet, sodass sie beim Einrichten der Beschriftungen bereits in der von Ihnen angegebenen Position und Transformation auf dem Bildschirm angezeigt wird.

Dann, soweit die Konfiguration des Textes geht, können Sie das Etikett ein NSAttributedString anstelle von NSString übergeben. Auf diese Weise können Sie verschiedene Teile des Strings können unabhängig voneinander in dem Etikett sein, verschiedene Größen, Schriftart, Farben, Hintergrundfarben usw. ein Beispiel der obigen beiden Absätzen Hier ist, so verschiedene Wörter ändern:

ImpressLabel *label1 = [[ImpressLabel alloc] initWithSize:CGSizeMake(260.0f, 80.0f) andCenterPointInSuperview:CGPointMake(500.0f, 500.0f) andRotationInSuperview:0.0f andEndingScaleFactor:1.3]; 

NSMutableAttributedString *firstLabelAttributes = [[NSMutableAttributedString alloc] initWithString:@"then you should try\nimpress.js*\n* no rhyme intended"]; 

[firstLabelAttributes addAttribute:NSFontAttributeName 
          value:[UIFont systemFontOfSize:label1.font.pointSize - 2] 
          range:NSMakeRange(0, 19)]; 

[firstLabelAttributes addAttribute:NSFontAttributeName 
          value:[UIFont systemFontOfSize:label1.font.pointSize - 8] 
          range:NSMakeRange(firstLabelAttributes.string.length - 19, 19)]; 

[firstLabelAttributes addAttribute:NSFontAttributeName 
          value:[UIFont boldSystemFontOfSize:label1.font.pointSize + 14] 
          range:NSMakeRange(23, 11)]; 


[label1 setNumberOfLines:3]; 
[label1 setAttributedText:firstLabelAttributes]; 
[label1 setTextAlignment:NSTextAlignmentCenter]; 
[containmentView addSubview:label1]; 

Jetzt, auf mehr von den Eingeweiden der ganzen Operation. Wie ich oben erwähnt habe, fügt diese Unterklasse jedem Label eine Tippgeste hinzu. Wenn ein Tippen erkannt wird, passieren ein paar Dinge. Die Ansicht mit den Beschriftungen wird durch Anpassen der Skalierung verschoben/zurück/entfernt. Es wird auch beginnen, zu rotieren und seinen Ankerpunkt in der Hauptansicht so anzupassen, dass die ausgewählte Beschriftung auf dem Bildschirm in der richtigen Ausrichtung zentriert wird, wenn die Animation stoppt. Dann, während dies alles läuft, wird das Alpha des ausgewählten Labels auf 1,0 f angehoben, während das Alpha des Rests auf 0,25 f gesenkt wird.

- (void)tapForRotationDetected:(UITapGestureRecognizer *)sender { 
    CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; 
    [scale setToValue:[NSNumber numberWithFloat:0.8]]; 
    [scale setAutoreverses:YES]; 
    [scale setDuration:0.3]; 

    //Create animation to adjust the container views anchorpoint. 
    CABasicAnimation *adjustAnchor = [CABasicAnimation animationWithKeyPath:@"anchorPoint"]; 
    [adjustAnchor setFromValue:[NSValue valueWithCGPoint:self.superview.layer.anchorPoint]]; 
    [adjustAnchor setToValue:[NSValue valueWithCGPoint:CGPointMake(self.center.x/self.superview.frame.size.width, self.center.y/self.superview.frame.size.height)]]; 
    [adjustAnchor setRemovedOnCompletion:NO]; 
    [adjustAnchor setFillMode:kCAFillModeForwards]; 

    //Create animation to rotate the container view within its superview. 
    CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; 

    //Create the animation group to apply these transforms 
    CAAnimationGroup *animationGroup = [CAAnimationGroup animation]; 
    [animationGroup setAnimations:@[adjustAnchor,rotation]]; 
    [animationGroup setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]]; 
    [animationGroup setDuration:0.6]; 

    //Apply the end results of the animations directly to the container views layer. 

    [self.superview.layer setTransform:CATransform3DRotate(CATransform3DIdentity, DEGREES_TO_RADIANS(-self.rotationInSuperview), 0.0f, 0.0f, 1.0f)]; 
    [self.superview.layer setAnchorPoint:CGPointMake(self.center.x/self.superview.frame.size.width, self.center.y/self.superview.frame.size.height)]; 
    [self.superview.layer addAnimation:animationGroup forKey:@"animationGroup"]; 

    //Animate the alpha property of all ImpressLabels in the container view. 
    [self.superview bringSubviewToFront:self]; 
    [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 
     for (ImpressLabel *label in sender.view.superview.subviews) { 
      if ([label isKindOfClass:[ImpressLabel class]]) { 
       if (label != self) { 
        [label setAlpha:0.25f]; 
       }else{ 
        [label setAlpha:1.0f]; 
       } 

      } 
     } 
    } completion:nil]; 
} 

nun einige der Bedenken in der Frage genannten Adresse.

  1. Ich habe dieses Projekt in Zuteilungen Werkzeug Instruments profiliert und es verbraucht nur etwa 3,2 MB insgesamt, so würde ich sagen, dieser Ansatz effizient genug ist.

  2. Das von mir zur Verfügung gestellte Beispiel animiert die meisten Objekte im 2D-Raum, mit Ausnahme der Skalierungsanimation, die bestenfalls eine Illusion ist. Was ich hier gemacht habe, soll als ein Beispiel dafür dienen, wie das gemacht werden kann und ist keine 100% vollständige Demonstration, weil, wie ich oben erwähnte, Animation wirklich nicht mein Fachgebiet ist. Wenn man jedoch über die Dokumente blickt, scheint es der Schlüssel zu sein, ein Etikett in der dritten Dimension rotieren zu lassen und seine Superansicht anzupassen, um alle Etiketten zu drehen und das ausgewählte Etikett flach zu lassen, wäre die Verwendung von CATransform3DInvert(). Obwohl ich noch keine Zeit hatte, um herauszufinden, ob es funktioniert, scheint es genau das zu sein, was in diesem Szenario benötigt wird.

  3. Soweit Spiegelung geht, glaube ich nicht, dass es Probleme mit der richtigen Skalierung alles geben wird. Wenn man über Apples Multiple Display Programming Guide schaut, sieht es so aus, als ob das an die NSNotificationUIScreenDidConnectNotification übergebene Objekt ein UIScreen Objekt ist. Da dies der Fall ist, können Sie leicht nach diesen Anzeigengrenzen fragen und die Rahmen der Etiketten und der Containeransicht entsprechend anpassen.

Anmerkung: In diesem Beispiel werden nur 0, 90, 180 und -90 Grad transformiert richtig 100% animieren, aufgrund der Koordinaten des Ankerpunkt falsch erzeugt wird. Es sieht so aus, als ob die Lösung bei CGPointApplyAffineTransform(<#CGPoint point#>, <#CGAffineTransform t#>) liegt, aber ich hatte wieder nicht so viel Zeit damit zu spielen, wie ich es mir gewünscht hätte. In jedem Fall sollte dies ausreichen, um mit Ihrer Reproduktion zu beginnen.

Dies hat definitiv mein Interesse geweckt, und wenn ich die Möglichkeit habe, nochmal daran zu arbeiten, werde ich diesen Beitrag gerne mit neuen Informationen ergänzen. Hoffe das hilft!

+0

Super! Die "eine weitere Sache ... haben Sie bemerkt, dass es in 3D ist" ist nicht kritisch. Rotation und Panning sind die größten Dinge. Wenn es eine Rotation und eine Pfanne gibt, scheint die Pfanne in der letzten Sekunde zu ruckeln. 2D-Skalierung wäre nett. Sie sollten das Projekt auf Github anstelle von Dropbox setzen, damit es immer auf der Antwort verfügbar ist. – Luke

+0

@Luke Leider konnte ich das nicht 100% ig arbeiten. Das Springen tritt nur auf, wenn versucht wird, zu/von Etiketten zu animieren, die nicht im rechten Winkel gedreht sind. Dies liegt daran, dass die Ankerpunktkoordinaten des Containers nicht korrekt aus der Transformation stammen. Wie ich in der Antwort "CGPointApplyAffineTransform()" gesagt habe, sieht es so aus, als könnte es das beheben, aber ich muss es noch schaffen können. Und ich werde das jetzt für Dropbox behalten und wenn ich ein paar Bugs ausbügeln werde ich das gerne auf Github hosten. –

+0

Ok, vielen Dank für die Mühe, ich schätze es wirklich! – Luke

1

Ich denke, es würde helfen, wenn Sie den Text auf einem CALayer zeichnen. Eine Bibliothek, die dabei helfen könnte, ist: https://github.com/ZaBlanc/CanvasKit Zeichnen Sie den nächsten Schritt Ihrer Animation auf einen neuen CALayer und transformieren Sie in diesen. Sie könnten Kette die erforderlichen Animationen mit dieser Bibliothek: https://github.com/yangmeyer/CPAnimationSequence oder diese Bibliothek: https://github.com/clayallsopp/Walt

+0

Der letzte Link ist Ruby. Das CanvasKit scheint [NSString drawAtPoint] zu verwenden. Der Speicherverbrauch scheint jedoch niedriger als bei UILabel, also lohnt sich der Check out, danke! – Luke