Ich erstelle derzeit eine Anwendung, die einen benutzerdefinierten View Controller-Container verwendet. Es werden mehrere Ansichten gleichzeitig auf dem Bildschirm angezeigt. Wenn Sie auf eine tippen, wird der ausgewählte Ansichts-Controller im Vollbildmodus animiert. Dabei werden auch die Unteransichten der ausgewählten Ansichtssteuerungen skaliert (Rahmen, Schriftgröße usw.). Die Schrifteigenschaft von UILabel kann jedoch nicht animiert werden, was zu Problemen führt. Ich habe mehrere Lösungen ausprobiert, aber alle saugen.
Die Lösungen, die ich versucht habe, sind:
- Machen Sie einen Screenshot der größeren Ansicht und animieren Sie die Änderung (ähnlich wie bei Flipboard).
- Animieren Sie mithilfe der Transformationseigenschaft
- Verkleinern einer UIScrollView und Vergrößern, wenn sie auf Vollbild gebracht wird.
- Durch Einstellen von adjustsFontSizeToFitWidth auf YES und Festlegen der Schriftgröße vor der Animation
Eine war bisher die beste Lösung, aber ich bin damit nicht zufrieden.
Ich suche nach anderen Vorschlägen, wenn jemand einen oder einen UILabel-Ersatz hat, der mit [UIView animate ..] reibungslos animiert.
Hier ist ein gutes Beispiel, das dem ähnelt, was mein UILabel tun soll: http://www.cocoawithlove.com/2010/09/zoomingviewcontroller-to-animate-uiview.html
EDIT: Dieser Code funktioniert
// Load View
self.label = [[UILabel alloc] init];
self.label.text = @"TEXT";
self.label.font = [UIFont boldSystemFontOfSize:20.0];
self.label.backgroundColor = [UIColor clearColor];
[self.label sizeToFit];
[self.view addSubview:self.label];
// Animation
self.label.font = [UIFont boldSystemFontOfSize:80.0];
self.label.transform = CGAffineTransformScale(self.label.transform, .25, .25);
[self.label sizeToFit];
[UIView animateWithDuration:1.0 animations:^{
self.label.transform = CGAffineTransformScale(self.label.transform, 4.0, 4.0);
self.label.center = self.view.center;
} completion:^(BOOL finished) {
self.label.font = [UIFont boldSystemFontOfSize:80.0];
self.label.transform = CGAffineTransformScale(self.label.transform, 1.0, 1.0);
[self.label sizeToFit];
}];
Antworten:
Sie können die Größe und Schriftart Ihrer
UILabel
Animation wie unten ändern . Hier habe ich nur ein Beispiel dafür, wie Sie die SchriftartUILabel
mit transform Animation ändern können .yourLabel.font = [UIFont boldSystemFontOfSize:35]; // set font size which you want instead of 35 yourLabel.transform = CGAffineTransformScale(yourLabel.transform, 0.35, 0.35); [UIView animateWithDuration:1.0 animations:^{ yourLabel.transform = CGAffineTransformScale(yourLabel.transform, 5, 5); }];
Ich hoffe das ist hilfreich für dich ..
quelle
CGAffineTransform
die Schriftartverfolgung nicht berücksichtigt wird. Wenn man also versucht, eineUILabel
Schriftart mit der Schriftart San Francisco zu skalieren, hat das skalierte Etikett falsche Tracking-Werte.Ab 2017 ....
Swift 3.0, 4.0
UIView.animate(withDuration: 0.5) { label.transform = CGAffineTransform(scaleX: 1.1, y: 1.1) //Scale label area }
Kritisch:
Der kritische Punkt, um Unschärfe zu vermeiden, ist, dass Sie mit der größten Größe beginnen und sie verkleinern müssen. Erweitern Sie dann bei Bedarf auf "1".
Für schnelle "Pops" (wie eine Hervorhebungsanimation) ist es in Ordnung, über 1 hinaus zu expandieren. Wenn Sie jedoch zwischen zwei Größen wechseln, machen Sie die größere Größe zur "richtigen" normalen .
quelle
Ich habe eine
UILabel
Erweiterung in Swift erstellt.import UIKit extension UILabel { func animate(font: UIFont, duration: TimeInterval) { // let oldFrame = frame let labelScale = self.font.pointSize / font.pointSize self.font = font let oldTransform = transform transform = transform.scaledBy(x: labelScale, y: labelScale) // let newOrigin = frame.origin // frame.origin = oldFrame.origin // only for left aligned text // frame.origin = CGPoint(x: oldFrame.origin.x + oldFrame.width - frame.width, y: oldFrame.origin.y) // only for right aligned text setNeedsUpdateConstraints() UIView.animate(withDuration: duration) { //L self.frame.origin = newOrigin self.transform = oldTransform self.layoutIfNeeded() } } }
Kommentieren Sie Zeilen aus, wenn der Beschriftungstext links oder rechts ausgerichtet ist.
quelle
Sie können auch CATextLayer verwenden, der fontSize als animierbare Eigenschaft hat.
let startFontSize: CGFloat = 20 let endFontSize: CGFloat = 80 let textLayer = CATextLayer() textLayer.string = "yourText" textLayer.font = yourLabel.font.fontName as CFTypeRef? textLayer.fontSize = startFontSize textLayer.foregroundColor = UIColor.black.cgColor textLayer.contentsScale = UIScreen.main.scale //for some reason CATextLayer by default only works for 1x screen resolution and needs this line to work properly on 2x, 3x, etc. ... textLayer.frame = parentView.bounds parentView.layer.addSublayer(textLayer) //animation: let duration: TimeInterval = 1 textLayer.fontSize = endFontSize //because upon completion of the animation CABasicAnimation resets the animated CALayer to its original state (as opposed to changing its properties to the end state of the animation), setting fontSize to endFontSize right BEFORE the animation starts ensures the fontSize doesn't jump back right after the animation. let fontSizeAnimation = CABasicAnimation(keyPath: "fontSize") fontSizeAnimation.fromValue = startFontSize fontSizeAnimation.toValue = endFontSize fontSizeAnimation.duration = duration fontSizeAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) textLayer.add(fontSizeAnimation, forKey: nil)
Ich habe es in meinem Projekt verwendet: https://github.com/yinanq/AngelListJobs
Bei dieser Animation wird die Schriftart oben links ausgerichtet (im Gegensatz zu CGAffineTransformScale, bei der das Etikett von der Mitte aus skaliert wird), je nach Bedarf für oder wider. Ein Nachteil von CATextLayer ist, dass CALayers nicht mit Autolayout-Einschränkungsanimationen arbeiten (was ich zufällig brauchte und löste, indem ich eine UIView erstellte, die nur den CATextLayer enthielt, und dessen Einschränkungen animierte).
quelle
textLayer.fontSize = endFontSize //because upon completion of the animation CABasicAnimation resets the animated CALayer to its original state (as opposed to changing its properties to the end state of the animation), setting fontSize to endFontSize right BEFORE the animation starts ensures the fontSize doesn't jump back right after the animation.
Das Zurücksetzen auf fromValue ist das Verhalten für jede CABasicAnimation. Glücklicherweise ist diese Lösung auch für jede CABasicAnimation universellfontSizeAnimation.isRemovedOnCompletion = false fontSizeAnimation.fillMode = CAMediaTimingFillMode.forwards
Für jemanden, der die Animationsrichtung anpassen möchte
Ich habe eine Erweiterung erstellt
UILabel
, um die Änderung der Schriftgröße zu animierenextension UILabel { func animate(fontSize: CGFloat, duration: TimeInterval) { let startTransform = transform let oldFrame = frame var newFrame = oldFrame let scaleRatio = fontSize / font.pointSize newFrame.size.width *= scaleRatio newFrame.size.height *= scaleRatio newFrame.origin.x = oldFrame.origin.x - (newFrame.size.width - oldFrame.size.width) * 0.5 newFrame.origin.y = oldFrame.origin.y - (newFrame.size.height - oldFrame.size.height) * 0.5 frame = newFrame font = font.withSize(fontSize) transform = CGAffineTransform.init(scaleX: 1 / scaleRatio, y: 1 / scaleRatio); layoutIfNeeded() UIView.animate(withDuration: duration, animations: { self.transform = startTransform newFrame = self.frame }) { (Bool) in self.frame = newFrame } }
Wenn Sie die Animationsrichtung anpassen möchten, verwenden Sie die folgende Methode und setzen Sie einen geeigneten Ankerpunkt.
SCHNELL
struct LabelAnimateAnchorPoint { // You can add more suitable archon point for your needs static let leadingCenterY = CGPoint.init(x: 0, y: 0.5) static let trailingCenterY = CGPoint.init(x: 1, y: 0.5) static let centerXCenterY = CGPoint.init(x: 0.5, y: 0.5) static let leadingTop = CGPoint.init(x: 0, y: 0) } extension UILabel { func animate(fontSize: CGFloat, duration: TimeInterval, animateAnchorPoint: CGPoint) { let startTransform = transform let oldFrame = frame var newFrame = oldFrame let archorPoint = layer.anchorPoint let scaleRatio = fontSize / font.pointSize layer.anchorPoint = animateAnchorPoint newFrame.size.width *= scaleRatio newFrame.size.height *= scaleRatio newFrame.origin.x = oldFrame.origin.x - (newFrame.size.width - oldFrame.size.width) * animateAnchorPoint.x newFrame.origin.y = oldFrame.origin.y - (newFrame.size.height - oldFrame.size.height) * animateAnchorPoint.y frame = newFrame font = font.withSize(fontSize) transform = CGAffineTransform.init(scaleX: 1 / scaleRatio, y: 1 / scaleRatio); layoutIfNeeded() UIView.animate(withDuration: duration, animations: { self.transform = startTransform newFrame = self.frame }) { (Bool) in self.layer.anchorPoint = archorPoint self.frame = newFrame } } }
ZIEL C
// You can add more suitable archon point for your needs #define kLeadingCenterYAnchorPoint CGPointMake(0.f, .5f) #define kTrailingCenterYAnchorPoint CGPointMake(1.f, .5f) #define kCenterXCenterYAnchorPoint CGPointMake(.5f, .5f) #define kLeadingTopAnchorPoint CGPointMake(0.f, 0.f) @implementation UILabel (FontSizeAnimating) - (void)animateWithFontSize:(CGFloat)fontSize duration:(NSTimeInterval)duration animateAnchorPoint:(CGPoint)animateAnchorPoint { CGAffineTransform startTransform = self.transform; CGRect oldFrame = self.frame; __block CGRect newFrame = oldFrame; CGPoint archorPoint = self.layer.anchorPoint; CGFloat scaleRatio = fontSize / self.font.pointSize; self.layer.anchorPoint = animateAnchorPoint; newFrame.size.width *= scaleRatio; newFrame.size.height *= scaleRatio; newFrame.origin.x = oldFrame.origin.x - (newFrame.size.width - oldFrame.size.width) * animateAnchorPoint.x; newFrame.origin.y = oldFrame.origin.y - (newFrame.size.height - oldFrame.size.height) * animateAnchorPoint.y; self.frame = newFrame; self.font = [self.font fontWithSize:fontSize]; self.transform = CGAffineTransformScale(self.transform, 1.f / scaleRatio, 1.f / scaleRatio); [self layoutIfNeeded]; [UIView animateWithDuration:duration animations:^{ self.transform = startTransform; newFrame = self.frame; } completion:^(BOOL finished) { self.layer.anchorPoint = archorPoint; self.frame = newFrame; }]; } @end
Um beispielsweise die Änderung der Schriftgröße des Etiketts auf 30 zu animieren, dauert die Dauer 1 Sekunde von der Mitte und die Skalierung größer. Einfach anrufen
SCHNELL
YOUR_LABEL.animate(fontSize: 30, duration: 1, animateAnchorPoint: LabelAnimateAnchorPoint.centerXCenterY)
ZIEL C
[YOUR_LABEL animateWithFontSize:30 duration:1 animateAnchorPoint:kCenterXCenterYAnchorPoint];
quelle
Für diejenigen, die keine Transformation, sondern eine tatsächliche Wertänderung suchen:
UIView.transition(with: label, duration: 0.25, options: .transitionCrossDissolve, animations: { self.label.font = UIFont.systemFont(ofSize: 15) }) { isFinished in }
quelle
Swift 3.0 & Swift 4.0
UIView.animate(withDuration: 0.5, delay: 0.1, options: .curveLinear, animations: { label.transform = label.transform.scaledBy(x:4,y:4) //Change x,y to get your desired effect. } ) { (completed) in //Animation Completed }
quelle
Ich fand jeden der Vorschläge hier aus folgenden Gründen unzureichend:
Um all diese Funktionen beizubehalten und dennoch einen reibungslosen Animationsübergang zu erzielen, habe ich den Transformationsansatz und den Schriftansatz kombiniert.
Die Schnittstelle ist einfach. Aktualisieren
fontSize
Sie einfach die Eigenschaft und Sie aktualisieren die Schriftgröße. Wenn Sie dies in einem Animationsblock tun, wird es animiert.@interface UILabel(MPFontSize) @property(nonatomic) CGFloat fontSize; @end
Was die Implementierung betrifft, gibt es den einfachen und den besseren Weg.
Einfach:
@implementation UILabel(MPFontSize) - (void)setFontSize:(CGFloat)fontSize { CGAffineTransform originalTransform = self.transform; UIFont *targetFont = [self.font fontWithSize:fontSize]; [UIView animateWithDuration:0 delay:0 options:0 animations:^{ self.transform = CGAffineTransformScale( originalTransform, fontSize / self.fontSize, fontSize / self.fontSize ); } completion:^(BOOL finished) { self.transform = originalTransform; if (finished) self.font = targetFont; }]; } - (CGFloat)fontSize { return self.font.pointSize; }; @end
Das Problem dabei ist nun, dass das Layout nach Abschluss stottern kann, da der Rahmen der Ansicht bis zur Fertigstellung der Animation auf der Grundlage der Originalschrift angepasst wird. Zu diesem Zeitpunkt wird der Rahmen aktualisiert, um die Zielschrift ohne Animation aufzunehmen.
Die Behebung dieses Problems ist etwas schwieriger, da wir es überschreiben müssen
intrinsicContentSize
. Sie können dies entweder durch UnterklassenUILabel
oder durch Swizzeln der Methode tun . Ich persönlich habe die Methode geändert, weil ich damit eine generischefontSize
Eigenschaft für alle verfügbar halten kannUILabel
s , aber das hängt von einem Bibliothekscode ab, den ich hier nicht kann. Hier erfahren Sie, wie Sie dies mithilfe von Unterklassen tun.Schnittstelle:
@interface AnimatableLabel : UILabel @property(nonatomic) CGFloat fontSize; @end
Implementierung:
@interface AnimatableLabel() @property(nonatomic) UIFont *targetFont; @property(nonatomic) UIFont *originalFont; @end @implementation AnimatableLabel - (void)setFontSize:(CGFloat)fontSize { CGAffineTransform originalTransform = self.transform; self.originalFont = self.font; self.targetFont = [self.font fontWithSize:fontSize]; [self invalidateIntrinsicContentSize]; [UIView animateWithDuration:0 delay:0 options:0 animations:^{ self.transform = CGAffineTransformScale( originalTransform, fontSize / self.fontSize, fontSize / self.fontSize ); } completion:^(BOOL finished) { self.transform = originalTransform; if (self.targetFont) { if (finished) self.font = self.targetFont; self.targetFont = self.originalFont = nil; [self invalidateIntrinsicContentSize]; } }]; } - (CGFloat)fontSize { return self.font.pointSize; }; - (CGSize)intrinsicContentSize { @try { if (self.targetFont) self.font = self.targetFont; return self.intrinsicContentSize; } @finally { if (self.originalFont) self.font = self.originalFont; } } @end
quelle
Wenn Sie die Textgröße von einem anderen Ankerpunkt aus animieren möchten, finden Sie hier den Swift 5 Lösung:
So bewerben Sie sich:
yourLabel.setAnimatedFont(.systemFont(ofSize: 48), duration: 0.2, anchorPointX: 0, anchorPointY: 1)
Erweiterungen:
extension UILabel { /// Animate font size from a given anchor point of the label. /// - Parameters: /// - duration: Animation measured in seconds /// - anchorPointX: 0 = left, 0.5 = center, 1 = right /// - anchorPointY: 0 = top, 0.5 = center, 1 = bottom func setAnimatedFont(_ font: UIFont, duration: TimeInterval, anchorPointX: CGFloat, anchorPointY: CGFloat) { guard let oldFont = self.font else { return } setAnchorPoint(CGPoint(x: anchorPointX, y: anchorPointY)) self.font = font let scaleFactor = oldFont.pointSize / font.pointSize let oldTransform = transform transform = transform.scaledBy(x: scaleFactor, y: scaleFactor) setNeedsUpdateConstraints() UIView.animate(withDuration: duration) { self.transform = oldTransform self.layoutIfNeeded() } } } extension UIView { /// Change the anchor point without moving the view's position. /// - Parameters: /// - point: The layer's bounds rectangle. func setAnchorPoint(_ point: CGPoint) { let oldOrigin = frame.origin layer.anchorPoint = point let newOrigin = frame.origin let translation = CGPoint(x: newOrigin.x - oldOrigin.x, y: newOrigin.y - oldOrigin.y) translatesAutoresizingMaskIntoConstraints = true center = CGPoint(x: center.x - translation.x, y: center.y - translation.y) } }
quelle