programing

UILabel 글꼴 크기 변경 애니메이션화

bestprogram 2023. 8. 10. 18:58

UILabel 글꼴 크기 변경 애니메이션화

현재 사용자 지정 View 컨트롤러 컨테이너를 사용하는 응용 프로그램을 만들고 있습니다.한 번에 여러 보기가 화면에 표시되고 하나를 누르면 선택한 보기 컨트롤러가 전체 화면으로 애니메이션화됩니다.이렇게 하면 선택한 뷰 컨트롤러가 스케일(프레임, 글꼴 크기 등)도 봅니다.그러나 UILabel의 글꼴 속성은 애니메이션화가 불가능하여 문제가 발생할 수 있습니다.저는 여러 가지 해결책을 시도해 보았지만 완전히 엉망이었습니다.

제가 시도한 솔루션은 다음과 같습니다.

  1. 더 큰 화면을 캡처하여 변경 사항을 애니메이션화합니다(Flipboard의 기능과 유사).
  2. 변환 속성을 사용하여 애니메이션을 만듭니다.
  3. UIScrollView를 축소하고 전체 화면으로 이동할 때 확대합니다.
  4. 설정은 FontSizeToFitWidth를 YES로 조정하고 애니메이션 전에 fontSize를 설정합니다.

하나는 지금까지 최고의 해결책이었지만 나는 그것에 만족하지 않습니다.

[UIView animate...]를 사용하여 부드럽게 애니메이션화되는 UILabel 대체물이나 UILabel 대체물이 있다면 다른 제안을 찾고 있습니다.

다음은 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];

}];

의 크기와 글꼴을 변경할 수 있습니다.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년 이후로는..

스위프트 3.0, 4.0

UIView.animate(withDuration: 0.5) {
     label.transform = CGAffineTransform(scaleX: 1.1, y: 1.1) //Scale label area
 }

중요:

흐림을 방지하기 위한 중요한 점은 가장 큰 크기로 시작하여 축소해야 한다는 것입니다.그런 다음 필요할 때 "1"로 확장합니다.

빠른 "팝"(하이라이트 애니메이션과 같은)의 경우 1 이상으로 확장해도 괜찮지만 두 가지 크기 사이에서 전환하는 경우크기를 "올바른" 일반 크기로 설정합니다.

내가 만든UILabel스위프트 내선 번호입니다.

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()
        }
    }
}

레이블 텍스트가 왼쪽 또는 오른쪽으로 정렬된 경우 선에 주석을 달 수 있습니다.

또한 fontSize가 있는 CATextLayer를 애니메이션 가능한 속성으로 사용할 수 있습니다.

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

이 애니메이션은 (CGAfineTransformScale이 레이블을 중앙에서 스케일링하는 것과 달리) 필요에 따라 글꼴 상단을 왼쪽으로 정렬하거나 반대로 유지합니다.CATextLayer의 단점은 CATextLayer가 자동 레이아웃 제약 조건 애니메이션과 함께 작동하지 않는다는 것입니다(CATextLayer만 포함하는 UIView를 만들고 제약 조건을 애니메이션화하여 필요하게 되었습니다).

혁신이 아닌 실제 가치 변화를 원하는 고객:

UIView.transition(with: label, duration: 0.25, options: .transitionCrossDissolve, animations: {
    self.label.font = UIFont.systemFont(ofSize: 15)
}) { isFinished in }

enter image description here

애니메이션의 방향을 조정하고 싶은 사람을 위한 것입니다.

▁extension의 확장자를 .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
    }
  }
}

목표-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

예를 들어 레이블 글꼴 크기를 30으로 변경하는 애니메이션을 만들려면 가운데에서 지속 시간 1초를 더 크게 조정합니다.간단히 전화하기

스위프트

YOUR_LABEL.animate(fontSize: 30, duration: 1, animateAnchorPoint: LabelAnimateAnchorPoint.centerXCenterY)

목표-C

[YOUR_LABEL animateWithFontSize:30 
                       duration:1 
             animateAnchorPoint:kCenterXCenterYAnchorPoint];

스위프트 3.0 & 스위프트 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      

    }

저는 다음과 같은 이유로 여기에 제시된 각각의 제안이 부적절하다는 것을 알게 되었습니다.

  1. 그들은 실제로 글꼴 크기를 바꾸지 않습니다.
  2. 프레임 크기 조정 및 자동 레이아웃을 사용할 수 없습니다.
  3. 인터페이스가 단순하지 않거나 애니메이션 블록 내부에서 제대로 작동하지 않습니다.

이러한 모든 기능을 유지하면서도 원활한 애니메이션 전환을 위해 변환 접근 방식과 글꼴 접근 방식을 결합했습니다.

인터페이스는 간단합니다.업데이트하기만 하면 됩니다.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또는 방법을 스와이프함으로써.저는개로그방변다니경합을법으인적을 할 수 해주기 에 그 방법을 . 왜냐하면 그것은 제가 제네릭을 유지할 수 있게 해주기 때문입니다.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

다른 앵커 포인트에서 텍스트 크기를 애니메이션화하려면 Swift 5 솔루션을 사용합니다.

신청 방법:

yourLabel.setAnimatedFont(.systemFont(ofSize: 48), duration: 0.2, anchorPointX: 0, anchorPointY: 1)

확장:

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

언급URL : https://stackoverflow.com/questions/14494566/animating-uilabel-font-size-change