Анимация Изменения Размера Шрифта UILabel
в настоящее время я создаю приложение, которое использует пользовательский контейнер контроллера вида. Одновременно на экране отображается несколько видов, и при нажатии на один из них выбранный контроллер вида анимируется в полноэкранном режиме. При этом выбранные контроллеры видов также масштабируются (рамка, размер шрифта и т. д.).) Хотя, свойство шрифта UILabel не анимируется, что приводит к проблемам. Я пробовал несколько решений, но все плоские сосать.
решения, которые я пробовал:
- сделайте скриншот большего вида и анимация изменения (аналогично тому, как Flipboard делает)
- анимация с помощью свойства transform
- масштабирование UIScrollView и масштабирование его при переходе на полный экран.
- установка adjustsFontSizeToFitWidth в YES и установка размера шрифта до анимации
один был лучшим решением до сих пор, но я не удовлетворен этим.
Я ищу другие предложения, если у кого-либо есть замена UILabel, которая плавно анимируется с помощью [UIView animate..].
вот хороший пример, который похож на то, что я хотел бы сделать мой UILabel: http://www.cocoawithlove.com/2010/09/zoomingviewcontroller-to-animate-uiview.html
изменить: этот код работает
// 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];
}];
7 ответов:
вы можете изменить размер и шрифт
UILabel
с анимацией как пыльник .. здесь я просто поставил пример того, как изменить шрифтUILabel
с анимацией преобразования ..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); }];
Я надеюсь, что это полезно для вас..
на 2017 год и далее....
Swift 3.0, 4.0
UIView.animate(withDuration: 0.5) { label.transform = CGAffineTransform(scaleX: 1.1, y: 1.1) //Scale label area }
вы также можете использовать CATextLayer, который имеет fontSize в качестве анимируемого свойства.
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)
я использовал его в своем проекте:https://github.com/yinanq/AngelListJobs
эта анимация сохраняет верхний левый шрифт выровненным (в отличие от cgaffinetransformscale масштабирование метки от центра), pro или con в зависимости от ваших потребностей. Недостатком CATextLayer является то, что CALayers не работают с анимацией ограничения autolayout (которая мне понадобилась и решила ее создание UIView, содержащего только CATextLayer и анимацию его ограничений).
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 }
для тех, кто хочет изменить направление анимации
Я создал расширение для
UILabel
для анимации изменения размера шрифтаextension 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 } }
если вы хотите настроить направление анимации, используйте метод ниже и поместите подходящую точку привязки.
Свифт
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 } } }
С
// 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
например, чтобы анимировать изменение размера шрифта метки до 30, длительность 1s от центра и масштаб больше. Просто позвоните
Свифт
YOUR_LABEL.animate(fontSize: 30, duration: 1, animateAnchorPoint: LabelAnimateAnchorPoint.centerXCenterY)
С
[YOUR_LABEL animateWithFontSize:30 duration:1 animateAnchorPoint:kCenterXCenterYAnchorPoint];
Я нашел каждое из предложений здесь неадекватным по следующим причинам:
- они на самом деле не меняют размер шрифта.
- они не играют хорошо с размером кадра и автоматической компоновкой.
- их интерфейс нетривиален и / или не играет хорошо внутри блоков анимации.
для того, чтобы сохранить все эти функции и по-прежнему получить плавный переход анимации я объединил подход преобразования и шрифт подход.
интерфейс прост. Просто обновите
fontSize
свойство и вы будете обновлять размер шрифта. Сделать это внутри блока анимации и анимировать.@interface UILabel(MPFontSize) @property(nonatomic) CGFloat fontSize; @end
Что касается реализации, есть простой способ, и есть лучший способ.
просто:
@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
теперь проблема с этим заключается в том, что макет может заикаться по завершении, потому что размер кадра представления основан на исходном шрифте до тех пор, пока завершение анимации, в этот момент кадр обновляется для размещения целевого шрифта без анимации.
исправление этой проблемы немного сложнее, потому что нам нужно переопределить
intrinsicContentSize
. Вы можете сделать это либо путем подклассовUILabel
или путем swizzling метод. Я лично swizzle метод, потому что это позволяет мне сохранить общийfontSize
свойство доступно для всехUILabel
s, но это зависит от некоторого кода библиотеки, который я не могу поделиться здесь. Вот как вы могли бы пойти об этом с помощью подклассы.интерфейс:
@interface AnimatableLabel : UILabel @property(nonatomic) CGFloat fontSize; @end
реализация:
@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