// // CustomRadioGroup.m // JasonDevelop // // Created by Jason Lee on 3/10/14. // Copyright (c) jasondevelop. All rights reserved. // @import ObjectiveC.runtime; #import #import "CustomRadioGroup.h" #import "CommonUtil.h" #import "ImageUtil.h" @interface CustomRadioButton () { } @end @implementation CustomRadioButton @synthesize checked = _checked; - (instancetype)initWithFrame:(CGRect)frame normalImage:(UIImage *)normalImage highlightImage:(UIImage *)highlightImage {//소스레벨에서 로드하는 경우, 초기화 if (self = [super initWithFrame:frame]) { _normalImage = normalImage; _highlightImage = highlightImage; [self setImage:_normalImage forState:UIControlStateNormal]; [self setImage:_highlightImage forState:UIControlStateHighlighted]; [self.titleLabel setLineBreakMode:NSLineBreakByTruncatingTail]; [self addTarget:self action:@selector(didRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside]; } return self; } - (void)awakeFromNib { _normalImage = [self imageForState:UIControlStateNormal]; _highlightImage = [self imageForState:UIControlStateHighlighted]; _titleColorNormal = [self titleColorForState:UIControlStateNormal]; _titleColorHighlight = [self titleColorForState:UIControlStateHighlighted] ? [self titleColorForState:UIControlStateHighlighted] : _titleColorNormal; [self.titleLabel setLineBreakMode:NSLineBreakByTruncatingTail]; [self addTarget:self action:@selector(didRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside]; } - (void)setChecked:(BOOL)checked {// _checked = checked; if (_checked) { [self setImage:_highlightImage forState:UIControlStateNormal]; [self setTitleColor:_titleColorHighlight forState:UIControlStateNormal]; } else { [self setImage:_normalImage forState:UIControlStateNormal]; [self setTitleColor:_titleColorNormal forState:UIControlStateNormal]; } if (_value) { objc_setAssociatedObject(_value, ksCustomRadioButtonStatus, [NSNumber numberWithBool:_checked], OBJC_ASSOCIATION_COPY_NONATOMIC); } } - (BOOL)getRadioStatusFromValue { BOOL isChecked = NO; if (_value) { isChecked = [objc_getAssociatedObject(_value, ksCustomRadioButtonStatus) boolValue]; } return isChecked; } - (void)didRadioButtonTouched:(id)sender { if (self.delegate) { self.checked = !self.checked; } if ([self.delegate respondsToSelector:@selector(didCheckRadioButton:)]) { [self.delegate didCheckRadioButton:self]; } } @end @interface CustomBgRadioButton () { // UIImage *_bgNormalImage, *_bgHighlightImage; // UIEdgeInsets _bgInsets; } @end #define kfRoundWidth 1.0f @implementation CustomBgRadioButton @dynamic checked; - (instancetype)initWithFrame:(CGRect)frame bgNormalImage:(UIImage *)bgNormalImage bgHighlightImage:(UIImage *)bgHighlightImage rectForCapBg:(CGRect)rectForCapBg { if (self = [super initWithFrame:frame]) { _bgNormalImage = bgNormalImage; _bgHighlightImage = bgHighlightImage; _rectForCapBg = rectForCapBg; [self setBackgroundImage:_bgNormalImage forState:UIControlStateNormal]; [self setBackgroundImage:_bgHighlightImage forState:UIControlStateHighlighted]; [self setImage:_normalImage forState:UIControlStateNormal]; [self setImage:_highlightImage forState:UIControlStateHighlighted]; if (!CGRectEqualToRect(_rectForCapBg, CGRectZero)) {//rectForCap이 설정된 경우, 이미지를 리사이즈함. CGFloat top, left, bottom, right; top = CGRectGetMinY(_rectForCapBg); left = CGRectGetMinX(_rectForCapBg); bottom = CGRectGetHeight(_rectForCapBg); right = CGRectGetWidth(_rectForCapBg); _bgInsets = UIEdgeInsetsMake(top, left, bottom, right); [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets]; [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets]; } else {//rectForCap이 설정되지 않은 경우, 픽스된 사이즈로 이미지를 리사이즈함. _bgInsets = UIEdgeInsetsMake(kfRoundWidth, kfRoundWidth, kfRoundWidth, kfRoundWidth); [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets]; [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets]; } [self addTarget:self action:@selector(didRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside]; } return self; } - (void)setBackgroundImageStretchForState:(UIControlState)state capInsets:(UIEdgeInsets)insets { UIImage *bimage = [self backgroundImageForState:state]; bimage = [ImageUtil resizableImageWithCapInsets:insets resizingMode:UIImageResizingModeStretch img:bimage]; [super setBackgroundImage:bimage forState:state]; } - (void)awakeFromNib { _bgNormalImage = [self backgroundImageForState:UIControlStateNormal]; _bgHighlightImage = [self backgroundImageForState:UIControlStateHighlighted]; _normalImage = [self imageForState:UIControlStateNormal]; _highlightImage = [self imageForState:UIControlStateHighlighted]; _titleColorNormal = [self titleColorForState:UIControlStateNormal]; _titleColorHighlight = [self titleColorForState:UIControlStateHighlighted] ? [self titleColorForState:UIControlStateHighlighted] : _titleColorNormal; if (!CGRectEqualToRect(_rectForCapBg, CGRectZero)) {//rectForCap이 설정된 경우, 이미지를 리사이즈함. CGFloat top, left, bottom, right; top = CGRectGetMinY(_rectForCapBg); left = CGRectGetMinX(_rectForCapBg); bottom = CGRectGetHeight(_rectForCapBg); right = CGRectGetWidth(_rectForCapBg); _bgInsets = UIEdgeInsetsMake(top, left, bottom, right); [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets]; [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets]; } else {//rectForCap이 설정되지 않은 경우, 픽스된 사이즈로 이미지를 리사이즈함. [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets]; [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets]; } [self addTarget:self action:@selector(didRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside]; } - (void)setChecked:(BOOL)checked { _checked = checked; if (_checked) { [self setBackgroundImage:_bgHighlightImage forState:UIControlStateNormal]; [self setTitleColor:_titleColorHighlight forState:UIControlStateNormal]; if (_normalImage && _highlightImage) { [self setImage:_highlightImage forState:UIControlStateNormal]; [self setImage:_normalImage forState:UIControlStateHighlighted]; } } else { [self setBackgroundImage:_bgNormalImage forState:UIControlStateNormal]; [self setTitleColor:_titleColorNormal forState:UIControlStateNormal]; if (_normalImage && _highlightImage) { [self setImage:_normalImage forState:UIControlStateNormal]; [self setImage:_highlightImage forState:UIControlStateHighlighted]; } } [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets]; [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets]; if (self.value) { objc_setAssociatedObject(self.value, ksCustomRadioButtonStatus, [NSNumber numberWithBool:self.checked], OBJC_ASSOCIATION_COPY_NONATOMIC); } } @end @interface CustomRadioGroup () { NSMutableArray *_btns; CustomRadioButton *_btnChecked; UIImage *_imageNormal, *_imageHighlight, *_bgImageNormal, *_bgImageHighlight; BOOL _isFirstLoading; } @end @implementation CustomRadioGroup - (id)init { if (self = [super init]) { _btns = [NSMutableArray new]; _isFirstLoading = YES; } return self; } - (id)initWithRadioButtons:(id)buttons, ... {//라디오 버튼 그룹을 만듬, 들어오는 버튼수만큰 멤버로 할당됨. if (self = [super init]) { if (buttons) { _btns = [NSMutableArray new]; if ([buttons isKindOfClass:[CustomBgRadioButton class]]) { _bgImageNormal = [UIImage imageNamed:@"tp_01_img_control_bg_black"]; _bgImageHighlight = [UIImage imageNamed:@"tp_01_img_control_bg_active"]; [(UIButton *)buttons setBackgroundImage:_imageHighlight forState:UIControlStateHighlighted]; } else if ([buttons isKindOfClass:[CustomBgRadioButton class]]) { _imageNormal = [UIImage imageNamed:@"common_radiobox_default"]; _imageHighlight = [UIImage imageNamed:@"common_radiobox_checked"]; [(UIButton *)buttons setImage:_imageHighlight forState:UIControlStateHighlighted]; } [buttons addTarget:self action:@selector(someRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside]; [_btns addObject:buttons]; _btnChecked = buttons; //첫번째 버튼을 선택상태로 _btnChecked.checked = YES; va_list args; va_start(args, buttons); while ((buttons = va_arg(args, id)) != nil) {//루프 - 버튼을 그룹에 추가함. if ([buttons isKindOfClass:[CustomRadioButton class]]) { [buttons addTarget:self action:@selector(someRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside]; [_btns addObject:buttons]; } } va_end(args); } } return self; } //Do not use in resusable table - (void)addRadioButton:(CustomRadioButton *)button {//라디오 그룹에 버튼을 추가함. CustomRadioButton *lBtn = [_btns lastObject]; if ([button isKindOfClass:[CustomBgRadioButton class]]) { if (lBtn == nil) {//첫번째 버튼 if (_isFirstLoading) { _bgImageNormal = [button backgroundImageForState:UIControlStateNormal]; _bgImageHighlight = [button backgroundImageForState:UIControlStateHighlighted]; _isFirstLoading = NO; } [button setBackgroundImage:_bgImageHighlight forState:UIControlStateNormal]; [button setBackgroundImage:_bgImageNormal forState:UIControlStateHighlighted]; _btnChecked = button; _btnChecked.checked = YES; } else { [button setBackgroundImage:_bgImageNormal forState:UIControlStateNormal]; [button setBackgroundImage:_bgImageHighlight forState:UIControlStateHighlighted]; } } else if ([button isKindOfClass:[CustomRadioButton class]]) { if (lBtn == nil) {//첫번째 버튼 if (_isFirstLoading) { _imageNormal = [button imageForState:UIControlStateNormal]; _imageHighlight = [button imageForState:UIControlStateHighlighted]; _isFirstLoading = NO; } [button setImage:_imageHighlight forState:UIControlStateNormal]; [button setImage:_imageNormal forState:UIControlStateHighlighted]; _btnChecked = button; _btnChecked.checked = YES; } else { [button setImage:_imageNormal forState:UIControlStateNormal]; [button setImage:_imageHighlight forState:UIControlStateHighlighted]; } } [button addTarget:self action:@selector(someRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside]; [_btns addObject:button]; } - (void)reset { [_btns removeAllObjects]; } - (id)valueForChecked {//선택된 Object를 반환함. return _btnChecked.value; } - (id)titleForChecked {//선택된 타이틀을 반환함. return _btnChecked.titleLabel.text; } - (NSInteger)count { return _btns.count; } - (NSArray *)rdoBtns { return _btns; } - (void)someRadioButtonTouched:(id)sender {//특정 라디오버튼이 선택된 경우, 값을 설정함. if (_btnChecked == sender) return; CustomRadioButton *btnSender = (CustomRadioButton *)sender; for (CustomRadioButton *btn in _btns) { if ([btnSender isEqual:btn]) { _btnChecked = btnSender; _btnChecked.checked = YES; } else { btn.checked = NO; } } if ([self.delegate respondsToSelector:@selector(didSomeRadioButtonTouched:)]) { [self.delegate didSomeRadioButtonTouched:sender]; } } @end @interface CustomRadioReusableGroup () { NSMutableArray *_valueArray; } @end @implementation CustomRadioReusableGroup - (instancetype)init { if (self = [super init]) { _valueArray = [[NSMutableArray alloc] init]; } return self; } - (void)addRadioButton:(CustomRadioButton *)rbtn { if ([_valueArray containsObject:rbtn.value]) {//동일한 오브젝트에 대한 validate return; } rbtn.delegate = self; [_valueArray addObject:rbtn.value]; } - (NSArray *)values { return _valueArray; } - (void)someRadioButtonTouched:(CustomRadioButton *)touchedRbtn { for (id avalue in _valueArray) { if ([touchedRbtn.value isEqual:avalue]) { touchedRbtn.checked = YES; continue; } if ([objc_getAssociatedObject(avalue, ksCustomRadioButtonStatus) boolValue]) { objc_setAssociatedObject(avalue, ksCustomRadioButtonStatus, [NSNumber numberWithBool:NO], OBJC_ASSOCIATION_COPY_NONATOMIC); } } [_tableView reloadData]; if ([self.delegate respondsToSelector:@selector(didSomeReuableRadioButtonTouched:)]) { [self.delegate didSomeReuableRadioButtonTouched:touchedRbtn]; } } - (void)reset { [_valueArray removeAllObjects]; } - (id)valueForChecked { id resultValue = nil; for (id avalue in _valueArray) { if ([objc_getAssociatedObject(avalue, ksCustomRadioButtonStatus) boolValue]) { resultValue = avalue; } } return resultValue; } #pragma mark - CustomRadioButton Delegate - (void)didCheckRadioButton:(id)sender { [self someRadioButtonTouched:sender]; } @end