// // CustomInsetTextField.m // JasonDevelop // // Created by Jason Lee on 2013. 12. 6.. // Copyright (c) jasondevelop. All rights reserved. // #import "NSString-Addtions.h" #import "CommonUtil.h" #import "CustomTextField.h" #import "ImageUtil.h" #define kUIBtnTintColor [UIColor whiteColor] #define kfBoxCap 12.0f #define kUIPlaceHolderColor RGBCOLOR(136, 143, 168) @interface CustomTextField () { @protected UIView *_targetSuperView; CGRect _cRect; CGRect _superRect; CGPoint _contentOffset; CGFloat _marginTop, _naviMargin, _adjustY; UIBarButtonItem *_btnPrev, *_btnNext, *_btnClose; UIToolbar *_toolBar; NSMutableArray *_barItems; UIBarButtonItem *_btnFlexibleSpace; UIEdgeInsets _bgInsets; BOOL _isSecureEntry; BOOL _isScrollUp; } @end CGRect gKeyboardRect; @implementation CustomTextField @dynamic delegate; - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { _customTextFieldSuperview = _customTextFieldSuperview == CustomTextFieldSuperviewIsNone ? CustomTextFieldSuperviewIsViewController : _customTextFieldSuperview; self.inputAccessoryView = [self generateAccessoryView]; self.borderStyle = UITextBorderStyleNone; _bgImageName = @"img_input_round_bg_default"; UIImage *bgImage = [UIImage imageNamed:_bgImageName]; if (bgImage) { _bgInsets = UIEdgeInsetsMake(kfBoxCap, kfBoxCap, kfBoxCap, kfBoxCap); bgImage = [ImageUtil resizableImageWithCapInsets:_bgInsets resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; } if (self.placeholder) { NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:self.placeholder attributes:@{NSForegroundColorAttributeName:kUIPlaceHolderColor}]; self.attributedPlaceholder = attrString; } _cRect = self.frame; } return self; } - (id)initWithFrame:(CGRect)frame bgImageName:(NSString *)btnImageName bgPressImageName:(NSString *)bgPressImageName { if (self = [super initWithFrame:frame]) { _customTextFieldSuperview = _customTextFieldSuperview == CustomTextFieldSuperviewIsNone ? CustomTextFieldSuperviewIsViewController : _customTextFieldSuperview; self.inputAccessoryView = [self generateAccessoryView]; self.borderStyle = UITextBorderStyleNone; _bgPressImageName = bgPressImageName; UIImage *bgImage = _bgImageName && ![_bgImageName isEmptyString] ? [UIImage imageNamed:_bgImageName] : [UIImage imageNamed:@"input_wh"]; if (bgImage) { bgImage = [ImageUtil resizableImageWithCapInsets:UIEdgeInsetsMake(kfBoxCap, kfBoxCap, kfBoxCap, kfBoxCap) resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; } if (self.placeholder) { NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:self.placeholder attributes:@{NSForegroundColorAttributeName:kUIPlaceHolderColor}]; self.attributedPlaceholder = attrString; } _cRect = self.frame; } return self; } - (id)initWithFrame:(CGRect)frame hasMoveButton:(BOOL)hasMoveButton disablePrev:(BOOL)disablePrev disableNext:(BOOL)disableNext { if (self = [super initWithFrame:frame]) { _customTextFieldSuperview = _customTextFieldSuperview == CustomTextFieldSuperviewIsNone ? CustomTextFieldSuperviewIsViewController : _customTextFieldSuperview; _hasMoveButton = hasMoveButton; _disablePrevButton = disablePrev; _disableNextButton = disableNext; self.inputAccessoryView = [self generateAccessoryView]; self.borderStyle = UITextBorderStyleNone; _bgImageName = @"img_input_round_bg_default"; UIImage *bgImage = [UIImage imageNamed:_bgImageName]; if (bgImage) { _bgInsets = UIEdgeInsetsMake(kfBoxCap, kfBoxCap, kfBoxCap, kfBoxCap); bgImage = [ImageUtil resizableImageWithCapInsets:_bgInsets resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; } if (self.placeholder) { NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:self.placeholder attributes:@{NSForegroundColorAttributeName:kUIPlaceHolderColor}]; self.attributedPlaceholder = attrString; } _cRect = self.frame; } return self; } - (void)awakeFromNib { _customTextFieldSuperview = _customTextFieldSuperview == CustomTextFieldSuperviewIsNone ? CustomTextFieldSuperviewIsViewController : _customTextFieldSuperview; self.inputAccessoryView = [self generateAccessoryView]; // self.borderStyle = UITextBorderStyleNone; _bgImageName = _bgImageName && ![_bgImageName isEmptyString] ? _bgImageName : @"img_input_round_bg_default"; _bgDisableImageName = _bgDisableImageName && ![_bgDisableImageName isEmptyString] ? _bgDisableImageName : @"img_input_round_bg_disable"; UIImage *bgImage = [UIImage imageNamed:_bgImageName]; if (bgImage) { if (!CGRectEqualToRect(_rectForCapBackground, CGRectZero)) {//rectForCap이 설정된 경우, 이미지를 리사이즈함. CGFloat top, left, bottom, right; top = CGRectGetMinY(_rectForCapBackground); left = CGRectGetMinX(_rectForCapBackground); bottom = CGRectGetHeight(_rectForCapBackground); right = CGRectGetWidth(_rectForCapBackground); _bgInsets = UIEdgeInsetsMake(top, left, bottom, right); } else { _bgInsets = UIEdgeInsetsMake(kfBoxCap, kfBoxCap, kfBoxCap, kfBoxCap); } bgImage = [ImageUtil resizableImageWithCapInsets:_bgInsets resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; } if (self.placeholder) { NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:self.placeholder attributes:@{NSForegroundColorAttributeName:kUIPlaceHolderColor}]; self.attributedPlaceholder = attrString; } _cRect = self.frame; if (self.secureTextEntry) { _isSecureEntry = self.secureTextEntry; } #ifdef DEBUG NSString *identifier = [NSString stringWithFormat:@"%@", self.placeholder]; [self setValue:identifier forKey:@"layoutDebuggingIdentifier"]; #endif } - (UIView *)generateAccessoryView { self.keyboardAppearance = UIKeyboardAppearanceDark; CGFloat width = [UIScreen mainScreen].bounds.size.width; _toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, width, 44.0)]; _toolBar.barStyle = UIBarStyleBlack; _toolBar.translucent = YES; _barItems = [NSMutableArray new]; _btnFlexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; _btnPrev = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"이전", @"이전") style:UIBarButtonItemStylePlain target:self action:@selector(goPrevField:)]; _btnNext = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"다음", @"다음") style:UIBarButtonItemStylePlain target:self action:@selector(goNextField:)]; _btnClose = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"닫기", @"닫기") style:UIBarButtonItemStylePlain target:self action:@selector(hideKeyboard:)]; if (IOS_VERSION >= 7.0f) { _btnClose.tintColor = kUIBtnTintColor; _btnPrev.tintColor = kUIBtnTintColor; _btnNext.tintColor = kUIBtnTintColor; } if (_hasMoveButton) { [_barItems addObject:_btnPrev]; [_barItems addObject:_btnNext]; _btnPrev.enabled = !_disablePrevButton; _btnNext.enabled = !_disableNextButton; } [_barItems addObject:_btnFlexibleSpace]; [_barItems addObject:_btnClose]; [_toolBar setItems:_barItems animated:YES]; return _toolBar; } - (void)setCustomTextFieldSuperview:(CustomTextFieldSuperview)customTextFieldSuperview { if (!_autoScrollUp) { return; } _customTextFieldSuperview = customTextFieldSuperview; if (_customTextFieldSuperview == CustomTextFieldSuperviewIsViewController) { UIViewController *vc = [CommonUtil currentViewController]; vc = vc.presentedViewController ? vc.presentedViewController : vc; _targetSuperView = vc.view; } else if (_customTextFieldSuperview == CustomTextFieldSuperviewIsPopup) { _targetSuperView = self.superview.superview; _adjustY = 130.0f; } else if (_customTextFieldSuperview == CustomTextFieldSuperviewIsPopupContentView) { _targetSuperView = self.superview.superview.superview; //팝업에서의 viewInRect로 계산됨. } else if (_customTextFieldSuperview == CustomTextFieldSuperviewIsScrollView) { _targetSuperView = self.superview; if ([_targetSuperView isKindOfClass:[UIScrollView class]]) { UIScrollView *sv = (UIScrollView *)_targetSuperView; _contentOffset = sv.contentOffset; _naviMargin = 150.0f; _adjustY = 0.0f; //? } } else if (_customTextFieldSuperview == CustomTextFieldSuperviewIsContentView) { _targetSuperView = self.superview.superview.superview.superview; // _targetSuperView = self.superview; if ([_targetSuperView isKindOfClass:[UIScrollView class]]) { UIScrollView *sv = (UIScrollView *)_targetSuperView; _contentOffset = sv.contentOffset; _naviMargin = 80.0f; _adjustY = 0.0f; //? } } else if (_customTextFieldSuperview == CustomTextFieldSuperviewIsChildViewController) { UIViewController *cvc = [CommonUtil currentViewController]; _targetSuperView = cvc.view; // if ([_targetSuperView isKindOfClass:[UIScrollView class]]) { // UIScrollView *sv = (UIScrollView *)_targetSuperView; // _contentOffset = sv.contentOffset; // _naviMargin = 0.0f; // _adjustY = 0.0f; //? // } } } - (void)scrollUp { if (_autoScrollUp) { if (CGRectEqualToRect(CGRectZero, gKeyboardRect)) { [self performSelector:@selector(scrollUp) withObject:nil afterDelay:0.1f]; return; } if (!_targetSuperView) { [self setCustomTextFieldSuperview:_customTextFieldSuperview]; } CGRect selfRect = self.frame; if (CGRectEqualToRect(_superRect, CGRectZero)) {//기존 위치를 저장함. _superRect = _targetSuperView.frame; } CGRect cr = [self.superview convertRect:selfRect toView:_targetSuperView]; if (_customTextFieldSuperview == CustomTextFieldSuperviewIsPopupContentView || _customTextFieldSuperview == CustomTextFieldSuperviewIsChildViewController) { cr = [self.superview convertRect:selfRect toView:[[UIApplication sharedApplication].delegate window]]; } CGFloat cy = CGRectGetMaxY(cr) + _adjustY; CGFloat ay = gKeyboardRect.size.height + 60;//(gKeyboardRect.size.height + KEYBOARD_ACCESSORY_HEIGHT + KEYBOARD_PREDICTS_HEIGHT); CGFloat ky = ([UIScreen mainScreen].bounds.size.height - _naviMargin) - ay; // 260 NSLog(@"_superRect1 %@, cy=%f", NSStringFromCGRect(_superRect), cy); if (cy >= ky) { __block CGRect scrollRect = _targetSuperView.frame; scrollRect.origin.y = ky - cy; [UIView animateWithDuration:kfAnimationDur animations:^{ if ([_targetSuperView isKindOfClass:[UIScrollView class]]) { CGFloat offsetY = _contentOffset.y + (cy - ky); [(UIScrollView *)_targetSuperView setContentOffset:CGPointMake(0, offsetY) animated:NO]; } else { if (_customTextFieldSuperview == CustomTextFieldSuperviewIsPopupContentView || _customTextFieldSuperview == CustomTextFieldSuperviewIsChildViewController) { scrollRect.origin.y += _superRect.origin.y; } _targetSuperView.frame = scrollRect; } } completion:^(BOOL finished) { _isScrollUp = YES; }]; } else { if (!CGRectEqualToRect(_superRect, CGRectZero)) { [UIView animateWithDuration:kfAnimationDur animations:^{ _targetSuperView.frame = _superRect; } completion:^(BOOL finished) { _isScrollUp = YES; }]; } } } } - (BOOL)becomeFirstResponder { _bgPressImageName = _bgPressImageName && ![_bgPressImageName isEmptyString] ? _bgPressImageName : @"img_input_round_bg_active"; UIImage *bgImage = [UIImage imageNamed:_bgPressImageName]; if (bgImage) { bgImage = [ImageUtil resizableImageWithCapInsets:_bgInsets resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; } if ([self isKindOfClass:[CustomSearchTextField class]] || _isScrollUp) { return [super becomeFirstResponder]; } //텍스트필드가 여러개일 경우, 다른 텍스트필드에서 resign을 처리하기 전에 호출되는 문제를 해결함. for (id textField in _targetSuperView.subviews) { if ([textField isKindOfClass:[UITextField class]] && [textField isFirstResponder]) { [textField resignFirstResponder]; NSLog(@"regisgn t=%@, s=%@", textField, self); } } _isScrollUp = NO; [self scrollUp]; return [super becomeFirstResponder]; } - (BOOL)resignFirstResponder { UIImage *bgImage = [UIImage imageNamed:_bgImageName]; bgImage = [ImageUtil resizableImageWithCapInsets:_bgInsets resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; if ([self isKindOfClass:[CustomSearchTextField class]] || !_isScrollUp) { return [super resignFirstResponder]; } if (_autoScrollUp) { // if (_customTextFieldSuperview == CustomTextFieldSuperviewIsScrollView) { // _targetSuperView = self.superview; // _superRect.origin.y = _superRect.origin.y < 0 ? 0.0f : _superRect.origin.y; // } [UIView animateWithDuration:kfAnimationDur animations:^{ if ([_targetSuperView isKindOfClass:[UIScrollView class]]) { [(UIScrollView *)_targetSuperView setContentOffset:_contentOffset animated:NO]; } else if (!CGRectIsEmpty(_superRect)) { _targetSuperView.frame = _superRect; NSLog(@"_superRect2 %@", NSStringFromCGRect(_superRect)); } } completion:^(BOOL finished) { _isScrollUp = NO; }]; } return [super resignFirstResponder]; } - (void)goPrevField:(id)sender { [self resignFirstResponder]; if ([self.delegate respondsToSelector:@selector(moveToPrevField:)]) { [self.delegate moveToPrevField:self]; } } - (void)goNextField:(id)sender { [self resignFirstResponder]; if ([self.delegate respondsToSelector:@selector(moveToNextField:)]) { [self.delegate moveToNextField:self]; } } - (void)hideKeyboard:(id)sender { [self resignFirstResponder]; if ([self.delegate respondsToSelector:@selector(willHideKeyboard:)]) { [self.delegate willHideKeyboard:self]; } } // placeholder position - (CGRect)textRectForBounds:(CGRect)bounds { CGFloat margin = 16; CGRect inset = bounds; if (self.textAlignment == NSTextAlignmentLeft || self.textAlignment == NSTextAlignmentJustified || self.textAlignment == NSTextAlignmentNatural) { inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width, bounds.size.height); } return inset; } // text position - (CGRect)editingRectForBounds:(CGRect)bounds { CGFloat margin = 16; CGRect inset = bounds; if (self.textAlignment == NSTextAlignmentLeft || self.textAlignment == NSTextAlignmentJustified || self.textAlignment == NSTextAlignmentNatural) { inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width, bounds.size.height); } return inset; } - (void)deleteBackward { if ([self.delegate respondsToSelector:@selector(deleteBackward:)] && [self.text isEmptyString]) { [self.delegate deleteBackward:self]; return; } [super deleteBackward]; } - (void)setUserInteractionEnabled:(BOOL)userInteractionEnabled { [super setUserInteractionEnabled:userInteractionEnabled]; UIImage *bgImage = [UIImage imageNamed:@"img_input_round_bg_active"]; bgImage = [ImageUtil resizableImageWithCapInsets:UIEdgeInsetsMake(kfBoxCap, kfBoxCap, kfBoxCap, kfBoxCap) resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; } @end @implementation CustomTextField2 // placeholder position - (CGRect)textRectForBounds:(CGRect)bounds { // CGFloat y = IOS_VERSION < 7.0f ? 6 : 0; CGFloat margin = 16; CGRect inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width, bounds.size.height); return inset; } // text position - (CGRect)editingRectForBounds:(CGRect)bounds { // CGFloat y = IOS_VERSION < 7.0f ? 6 : 0; CGFloat margin = 16; CGRect inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width, bounds.size.height); return inset; } @end @implementation CustomSearchTextField - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.borderStyle = UITextBorderStyleNone; UIImage *bgImage = [UIImage imageNamed:@"input_wh_search"]; if (bgImage) { bgImage = [ImageUtil resizableImageWithCapInsets:UIEdgeInsetsMake(1, 22, 1, 1) resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; } if (self.placeholder) { NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:self.placeholder attributes:@{NSForegroundColorAttributeName:kUIPlaceHolderColor}]; self.attributedPlaceholder = attrString; } } return self; } - (BOOL)becomeFirstResponder { //텍스트필드가 여러개일 경우, 다른 텍스트필드에서 resign을 처리하기 전에 호출되는 문제를 해결함. for (id textField in _targetSuperView.subviews) { if ([textField isKindOfClass:[UITextField class]] && [textField isFirstResponder]) { [textField resignFirstResponder]; NSLog(@"regisgn t=%@, s=%@", textField, self); } } UIImage *bgImage = [UIImage imageNamed:@"input_wh_search_press"]; if (bgImage) { bgImage = [ImageUtil resizableImageWithCapInsets:UIEdgeInsetsMake(1, 22, 1, 1) resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; } return [super becomeFirstResponder]; } - (BOOL)resignFirstResponder { UIImage *bgImage = [UIImage imageNamed:@"input_wh_search"]; bgImage = [ImageUtil resizableImageWithCapInsets:UIEdgeInsetsMake(1, 22, 1, 1) resizingMode:UIImageResizingModeStretch img:bgImage]; [self setBackground:bgImage]; if (self.autoScrollUp) { // if (_customTextFieldSuperview == CustomTextFieldSuperviewIsScrollView) { // _targetSuperView = self.superview; // _superRect.origin.y = _superRect.origin.y < 0 ? 0.0f : _superRect.origin.y; // } [UIView animateWithDuration:kfAnimationDur animations:^{ if ([_targetSuperView isKindOfClass:[UIScrollView class]]) { [(UIScrollView *)_targetSuperView setContentOffset:_contentOffset animated:NO]; } else if (!CGRectIsEmpty(_superRect)) { _targetSuperView.frame = _superRect; NSLog(@"_superRect2 %@", NSStringFromCGRect(_superRect)); } }]; } return [super resignFirstResponder]; } // placeholder position - (CGRect)textRectForBounds:(CGRect)bounds { return CGRectInset(bounds, 30.0f, 0); } // text position - (CGRect)editingRectForBounds:(CGRect)bounds { return CGRectInset(bounds, 30.0f, 0); } @end /* @implementation CustomTextField3 - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.inputAccessoryView = [self generateAccessoryView]; self.borderStyle = UITextBorderStyleNone; [self setBackground:[ACDUtil getStretchedImage:[UIImage imageNamed:@"bm_src_textfield_bg"] expectSize:self.bounds.size]]; _cRect = self.frame; } return self; } - (void)awakeFromNib { self.inputAccessoryView = [self generateAccessoryView]; self.borderStyle = UITextBorderStyleNone; [self setBackground:[ACDUtil getStretchedImage:[UIImage imageNamed:@"bm_src_textfield_bg"] expectSize:self.bounds.size]]; _cRect = self.frame; } - (void)drawRect:(CGRect)rect { CGRect tr = _cRect; tr.size.height = 29.0f; self.frame = tr; [self setNeedsLayout]; } // placeholder position - (CGRect)textRectForBounds:(CGRect)bounds { return CGRectInset(bounds, 26, 0); } // text position - (CGRect)editingRectForBounds:(CGRect)bounds { return CGRectInset(bounds, 26, 0); } @end @implementation CustomTextField4 - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.inputAccessoryView = [self generateAccessoryView]; self.borderStyle = UITextBorderStyleNone; [self setBackground:[ACDUtil getStretchedImage:[UIImage imageNamed:@"bm_src_textfield_bg2"] expectSize:self.bounds.size]]; _cRect = self.frame; } return self; } - (void)awakeFromNib { self.inputAccessoryView = [self generateAccessoryView]; self.borderStyle = UITextBorderStyleNone; [self setBackground:[ACDUtil getStretchedImage:[UIImage imageNamed:@"bm_src_textfield_bg2"] expectSize:self.bounds.size]]; _cRect = self.frame; } - (void)drawRect:(CGRect)rect { CGRect tr = _cRect; tr.size.height = 29.0f; self.frame = tr; [self setNeedsLayout]; } // placeholder position - (CGRect)textRectForBounds:(CGRect)bounds { return CGRectInset(bounds, 26, 0); } // text position - (CGRect)editingRectForBounds:(CGRect)bounds { return CGRectInset(bounds, 26, 0); } @end @implementation CustomTextField5 - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.inputAccessoryView = [self generateAccessoryView]; self.borderStyle = UITextBorderStyleNone; [self setBackground:[ACDUtil getStretchedImage:[UIImage imageNamed:@"st_src_textfield_bg"] expectSize:self.bounds.size]]; _cRect = self.frame; } return self; } - (void)awakeFromNib { self.inputAccessoryView = [self generateAccessoryView]; self.borderStyle = UITextBorderStyleNone; [self setBackground:[ACDUtil getStretchedImage:[UIImage imageNamed:@"st_src_textfield_bg"] expectSize:self.bounds.size]]; _cRect = self.frame; } - (void)drawRect:(CGRect)rect { CGRect tr = _cRect; tr.size.height = 36.0f; self.frame = tr; [self setNeedsLayout]; } // placeholder position - (CGRect)textRectForBounds:(CGRect)bounds { return CGRectInset(bounds, 5, 0); } // text position - (CGRect)editingRectForBounds:(CGRect)bounds { return CGRectInset(bounds, 5, 0); } @end */ @implementation CustomMenuTextFieldMenu @end @implementation CustomMenuTextField //텍스트필드 컨텍스트 메뉴 커스터마이징 - (void)setMenuItems:(NSArray *)menuItems { UIMenuController *menu = [UIMenuController sharedMenuController]; menu.menuItems = menuItems; [menu update]; } - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { BOOL canPerform = NO; for (CustomMenuTextFieldMenu *menu in _menuItems) { canPerform = (action == menu.selector); if (canPerform) break; } return canPerform; } @end