iphone - لوحة - تغيير حجم الخط UILabel الرسوم المتحركة




تكبير خط الفيس بوك في الايفون (5)

أقوم حاليًا بإنشاء تطبيق يستخدم حاوية وحدة تحكم عرض مخصصة. توجد طرق عرض متعددة على الشاشة في وقت واحد وعندما يتم النقر فوق أحدها ، يتحكم جهاز التحكم في العرض المحدد في وضع ملء الشاشة. عند القيام بذلك ، يتم قياس وحدات العرض الفرعية للتحكم في العرض أيضًا (الإطار ، حجم الخط ، إلخ) على الرغم من أن خاصية خط UILabel ليست قابلة للتحريك مما يؤدي إلى حدوث مشكلات. لقد جربت العديد من الحلول ولكن تمتص بالكامل.

الحلول التي جربتها هي:

  1. التقاط لقطة شاشة للرؤية الأكبر وتحريك التغيير (على غرار طريقة عمل Flipboard)
  2. تحريك باستخدام خاصية التحويل
  3. يمكنك تصغير UIScrollView وتكبيره عند إحضاره إلى وضع ملء الشاشة.
  4. يضبط الضبط FontSizeToFitWidth إلى YES ويضبط fontSize قبل الحركة

أحدهما كان الحل الأفضل حتى الآن لكني لست راضياً عنه.

أنا أبحث عن اقتراحات أخرى إذا كان أي شخص لديه أي أو بديل 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];

}];

لعام 2017 فصاعدا ....

سويفت 3.0 ، 4.0

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

لمن يريد تعديل اتجاه الرسوم المتحركة

لقد قمت بإنشاء ملحق لـ 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
    }
  }

إذا كنت تريد ضبط اتجاه الرسوم المتحركة ، استخدم الطريقة أدناه ووضع نقطة ربط مناسبة.

SWIFT

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 ، فستصبح المدة 1 من المركز والمقياس أكبر. ببساطة اتصل

SWIFT

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

ج موضوعية

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

لقد وجدت أن كل من الاقتراحات هنا غير كافية لهذه الأسباب:

  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 أو عن طريق swzling الطريقة. أنا شخصيا أذهل هذه الطريقة ، لأنها تسمح لي بالحفاظ على خاصية عامة UILabel المتاح لجميع UILabel ، ولكن ذلك يعتمد على بعض رمز المكتبة لا أستطيع المشاركة هنا. هنا كيف يمكنك الذهاب عن هذا باستخدام subclassing.

جهة تعامل:

@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

يمكنك أيضًا استخدام 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 قياس الملصق من الوسط) أو المؤيد أو con وفقًا لاحتياجاتك. عيوب من CATextLayer هو أن CALayers لا تعمل مع الرسوم المتحركة autolayout القيد (الذي حدث أنني بحاجة إلى وحلها عن طريق جعل UIView يحتوي فقط على CATextLayer وتحريك قيوده).


سويفت 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      

    }






uilabel