0

I am working now on custom UITextField, my main goal is to deliver custom placeholder animation. I want simply resize the placeholder and move it to top left corner. In gif bellow you can see move to top left works well, but resize is not animated and I have no idea way. Both of those actions are animated the same way with auto layout. Base on what I read it should works, and works for any other animation within auto layout, exclude view resize.

Thoughts / comments? What the heck am I doing wrong?

My current implementation:

#import "LTTextField.h"
#import "PureLayout.h"
#import <QuartzCore/QuartzCore.h>

@interface LTTextField()<UITextFieldDelegate>

@property (nonatomic, strong) UILabel *betterPlaceholder;
@property (nonatomic, strong) NSLayoutConstraint *heightConstraint;

@end

@implementation LTTextField

- (id)initWithCoder:(NSCoder *)aDecoder{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setBorderStyle:UITextBorderStyleNone];
        self.delegate = self;

        self.betterPlaceholder = [[UILabel alloc] initForAutoLayout];

        [self.betterPlaceholder setFont:[UIFont systemFontOfSize:17.0f]];
        [self.betterPlaceholder setAdjustsFontSizeToFitWidth:YES];
        [self.betterPlaceholder setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];

        [self addSubview:self.betterPlaceholder];

        [self.betterPlaceholder autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:self];
        [self.betterPlaceholder autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self];
        [self.betterPlaceholder autoMatchDimension:ALDimensionHeight toDimension:ALDimensionWidth ofView:self.betterPlaceholder];
        self.heightConstraint = [self.betterPlaceholder autoSetDimension:ALDimensionHeight toSize:CGRectGetHeight(self.frame)];

        [self setNeedsUpdateConstraints];
        [self updateConstraintsIfNeeded];

        [self addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

    }
    return self;
}

- (void)drawPlaceholderInRect:(CGRect)rect {}

- (void)awakeFromNib{
    [super awakeFromNib];
    [self refreshPlaceHolderText];
}

- (void)refreshPlaceHolderText{
    if (self.placeholder) {
        if (self.attributedPlaceholder) {
            NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedPlaceholder];
            [attributedString setAttributes:@{NSForegroundColorAttributeName: [UIColor blueColor]} range:NSMakeRange(0, attributedString.string.length)];
            [self.betterPlaceholder setAttributedText:attributedString];
        } else {
            [self.betterPlaceholder setText:self.placeholder];
        }
        NSLog(@"Placeholder text %@",self.placeholder);
    }
}

- (void)animatePlaceholderToState:(LTPlaceholderState)state animated:(BOOL)animated {

    if (LTPlaceholderStateStart == state) {
        self.heightConstraint.constant = CGRectGetHeight(self.frame);
    } else if (LTPlaceholderStateEnd == state) {
        self.heightConstraint.constant = 20;
    }

    [UIView animateKeyframesWithDuration:1.0f
                                   delay:0.0f
                                 options:UIViewKeyframeAnimationOptionBeginFromCurrentState
                              animations:^{
                                  [self setNeedsLayout];
                                  [self layoutIfNeeded];
                              } completion:nil];
}

#pragma mark - UITextFieldDelegate

- (void)textFieldDidChange:(UITextField *)theTextField{
    LTPlaceholderState placeholderState;
    if( theTextField.text.length > 0 ) {
          placeholderState = LTPlaceholderStateEnd;
    } else {
          placeholderState = LTPlaceholderStateStart;
    }
    [self animatePlaceholderToState:placeholderState animated:self.editing];
}

@end

Current implementation example

  • 1) try to set `self.betterPlaceholder.contentMode = UIViewContentModeCenter;` or... 2) add your self.betterPlaceholder to a UIView - and animate the frame/size of tthis UIView (http://stackoverflow.com/a/27091446) – TonyMkenu Jan 19 '15 at 08:59

1 Answers1

0

It looks like your animation is working fine, and it's just that the font size snaps to the smaller font. You're forcing the width and height of the label to be the same with your use of autoMatchDimension, and you've requested setAdjustsFontSizeToFitWidth:YES. Ergo when the new layout is computed, the font size is reduced (or increased, depending on whether it's animating in or out). Font size is not an animatable property, so the change happens immediately.

You might have some luck in not changing the view frame height, but instead animating a change in both the scale and frame origin of the view. This will ensure it gets smaller, but doesn't actually require animating text attribute changes.

Adam Wright
  • 48,938
  • 12
  • 131
  • 152
  • Ok, but how scale and frame animation will looks like with auto layout? I can do that without it, but in this project I would like to use auto layout everywhere. – Łukasz Tomaszewski Jan 17 '15 at 18:26