CustomRadioGroup.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. //
  2. // CustomRadioGroup.m
  3. // JasonDevelop
  4. //
  5. // Created by Jason Lee on 3/10/14.
  6. // Copyright (c) jasondevelop. All rights reserved.
  7. //
  8. @import ObjectiveC.runtime;
  9. #import <stdarg.h>
  10. #import "CustomRadioGroup.h"
  11. #import "CommonUtil.h"
  12. @interface CustomRadioButton () {
  13. }
  14. @end
  15. @implementation CustomRadioButton
  16. @synthesize checked = _checked;
  17. - (instancetype)initWithFrame:(CGRect)frame normalImage:(UIImage *)normalImage highlightImage:(UIImage *)highlightImage {//소스레벨에서 로드하는 경우, 초기화
  18. if (self = [super initWithFrame:frame]) {
  19. _normalImage = normalImage;
  20. _highlightImage = highlightImage;
  21. [self setImage:_normalImage forState:UIControlStateNormal];
  22. [self setImage:_highlightImage forState:UIControlStateHighlighted];
  23. [self.titleLabel setLineBreakMode:NSLineBreakByTruncatingTail];
  24. [self addTarget:self action:@selector(didRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
  25. }
  26. return self;
  27. }
  28. - (void)awakeFromNib {
  29. _normalImage = [self imageForState:UIControlStateNormal];
  30. _highlightImage = [self imageForState:UIControlStateHighlighted];
  31. _titleColorNormal = [self titleColorForState:UIControlStateNormal];
  32. _titleColorHighlight = [self titleColorForState:UIControlStateHighlighted] ? [self titleColorForState:UIControlStateHighlighted] : _titleColorNormal;
  33. [self.titleLabel setLineBreakMode:NSLineBreakByTruncatingTail];
  34. [self addTarget:self action:@selector(didRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
  35. }
  36. - (void)setChecked:(BOOL)checked {//
  37. _checked = checked;
  38. if (_checked) {
  39. [self setImage:_highlightImage forState:UIControlStateNormal];
  40. [self setTitleColor:_titleColorHighlight forState:UIControlStateNormal];
  41. } else {
  42. [self setImage:_normalImage forState:UIControlStateNormal];
  43. [self setTitleColor:_titleColorNormal forState:UIControlStateNormal];
  44. }
  45. if (_value) {
  46. objc_setAssociatedObject(_value, ksCustomRadioButtonStatus, [NSNumber numberWithBool:_checked], OBJC_ASSOCIATION_COPY_NONATOMIC);
  47. }
  48. }
  49. - (BOOL)getRadioStatusFromValue {
  50. BOOL isChecked = NO;
  51. if (_value) {
  52. isChecked = [objc_getAssociatedObject(_value, ksCustomRadioButtonStatus) boolValue];
  53. }
  54. return isChecked;
  55. }
  56. - (void)didRadioButtonTouched:(id)sender {
  57. if (self.delegate) {
  58. self.checked = !self.checked;
  59. }
  60. if ([self.delegate respondsToSelector:@selector(didCheckRadioButton:)]) {
  61. [self.delegate didCheckRadioButton:self];
  62. }
  63. }
  64. @end
  65. @interface CustomBgRadioButton () {
  66. // UIImage *_bgNormalImage, *_bgHighlightImage;
  67. // UIEdgeInsets _bgInsets;
  68. }
  69. @end
  70. #define kfRoundWidth 1.0f
  71. @implementation CustomBgRadioButton
  72. @dynamic checked;
  73. - (instancetype)initWithFrame:(CGRect)frame bgNormalImage:(UIImage *)bgNormalImage bgHighlightImage:(UIImage *)bgHighlightImage rectForCapBg:(CGRect)rectForCapBg {
  74. if (self = [super initWithFrame:frame]) {
  75. _bgNormalImage = bgNormalImage;
  76. _bgHighlightImage = bgHighlightImage;
  77. _rectForCapBg = rectForCapBg;
  78. [self setBackgroundImage:_bgNormalImage forState:UIControlStateNormal];
  79. [self setBackgroundImage:_bgHighlightImage forState:UIControlStateHighlighted];
  80. [self setImage:_normalImage forState:UIControlStateNormal];
  81. [self setImage:_highlightImage forState:UIControlStateHighlighted];
  82. if (!CGRectEqualToRect(_rectForCapBg, CGRectZero)) {//rectForCap이 설정된 경우, 이미지를 리사이즈함.
  83. CGFloat top, left, bottom, right;
  84. top = CGRectGetMinY(_rectForCapBg);
  85. left = CGRectGetMinX(_rectForCapBg);
  86. bottom = CGRectGetHeight(_rectForCapBg);
  87. right = CGRectGetWidth(_rectForCapBg);
  88. _bgInsets = UIEdgeInsetsMake(top, left, bottom, right);
  89. [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets];
  90. [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets];
  91. } else {//rectForCap이 설정되지 않은 경우, 픽스된 사이즈로 이미지를 리사이즈함.
  92. _bgInsets = UIEdgeInsetsMake(kfRoundWidth, kfRoundWidth, kfRoundWidth, kfRoundWidth);
  93. [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets];
  94. [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets];
  95. }
  96. [self addTarget:self action:@selector(didRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
  97. }
  98. return self;
  99. }
  100. - (void)setBackgroundImageStretchForState:(UIControlState)state capInsets:(UIEdgeInsets)insets {
  101. UIImage *bimage = [self backgroundImageForState:state];
  102. bimage = [CommonUtil resizableImageWithCapInsets:insets resizingMode:UIImageResizingModeStretch img:bimage];
  103. [super setBackgroundImage:bimage forState:state];
  104. }
  105. - (void)awakeFromNib {
  106. _bgNormalImage = [self backgroundImageForState:UIControlStateNormal];
  107. _bgHighlightImage = [self backgroundImageForState:UIControlStateHighlighted];
  108. _normalImage = [self imageForState:UIControlStateNormal];
  109. _highlightImage = [self imageForState:UIControlStateHighlighted];
  110. _titleColorNormal = [self titleColorForState:UIControlStateNormal];
  111. _titleColorHighlight = [self titleColorForState:UIControlStateHighlighted] ? [self titleColorForState:UIControlStateHighlighted] : _titleColorNormal;
  112. if (!CGRectEqualToRect(_rectForCapBg, CGRectZero)) {//rectForCap이 설정된 경우, 이미지를 리사이즈함.
  113. CGFloat top, left, bottom, right;
  114. top = CGRectGetMinY(_rectForCapBg);
  115. left = CGRectGetMinX(_rectForCapBg);
  116. bottom = CGRectGetHeight(_rectForCapBg);
  117. right = CGRectGetWidth(_rectForCapBg);
  118. _bgInsets = UIEdgeInsetsMake(top, left, bottom, right);
  119. [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets];
  120. [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets];
  121. } else {//rectForCap이 설정되지 않은 경우, 픽스된 사이즈로 이미지를 리사이즈함.
  122. [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets];
  123. [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets];
  124. }
  125. [self addTarget:self action:@selector(didRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
  126. }
  127. - (void)setChecked:(BOOL)checked {
  128. _checked = checked;
  129. if (_checked) {
  130. [self setBackgroundImage:_bgHighlightImage forState:UIControlStateNormal];
  131. [self setTitleColor:_titleColorHighlight forState:UIControlStateNormal];
  132. if (_normalImage && _highlightImage) {
  133. [self setImage:_highlightImage forState:UIControlStateNormal];
  134. [self setImage:_normalImage forState:UIControlStateHighlighted];
  135. }
  136. } else {
  137. [self setBackgroundImage:_bgNormalImage forState:UIControlStateNormal];
  138. [self setTitleColor:_titleColorNormal forState:UIControlStateNormal];
  139. if (_normalImage && _highlightImage) {
  140. [self setImage:_normalImage forState:UIControlStateNormal];
  141. [self setImage:_highlightImage forState:UIControlStateHighlighted];
  142. }
  143. }
  144. [self setBackgroundImageStretchForState:UIControlStateNormal capInsets:_bgInsets];
  145. [self setBackgroundImageStretchForState:UIControlStateHighlighted capInsets:_bgInsets];
  146. if (self.value) {
  147. objc_setAssociatedObject(self.value, ksCustomRadioButtonStatus, [NSNumber numberWithBool:self.checked], OBJC_ASSOCIATION_COPY_NONATOMIC);
  148. }
  149. }
  150. @end
  151. @interface CustomRadioGroup () {
  152. NSMutableArray *_btns;
  153. CustomRadioButton *_btnChecked;
  154. UIImage *_imageNormal, *_imageHighlight, *_bgImageNormal, *_bgImageHighlight;
  155. BOOL _isFirstLoading;
  156. }
  157. @end
  158. @implementation CustomRadioGroup
  159. - (id)init {
  160. if (self = [super init]) {
  161. _btns = [NSMutableArray new];
  162. _isFirstLoading = YES;
  163. }
  164. return self;
  165. }
  166. - (id)initWithRadioButtons:(id)buttons, ... {//라디오 버튼 그룹을 만듬, 들어오는 버튼수만큰 멤버로 할당됨.
  167. if (self = [super init]) {
  168. if (buttons) {
  169. _btns = [NSMutableArray new];
  170. if ([buttons isKindOfClass:[CustomBgRadioButton class]]) {
  171. _bgImageNormal = [UIImage imageNamed:@"tp_01_img_control_bg_black"];
  172. _bgImageHighlight = [UIImage imageNamed:@"tp_01_img_control_bg_active"];
  173. [(UIButton *)buttons setBackgroundImage:_imageHighlight forState:UIControlStateHighlighted];
  174. } else if ([buttons isKindOfClass:[CustomBgRadioButton class]]) {
  175. _imageNormal = [UIImage imageNamed:@"common_radiobox_default"];
  176. _imageHighlight = [UIImage imageNamed:@"common_radiobox_checked"];
  177. [(UIButton *)buttons setImage:_imageHighlight forState:UIControlStateHighlighted];
  178. }
  179. [buttons addTarget:self action:@selector(someRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
  180. [_btns addObject:buttons];
  181. _btnChecked = buttons; //첫번째 버튼을 선택상태로
  182. _btnChecked.checked = YES;
  183. va_list args;
  184. va_start(args, buttons);
  185. while ((buttons = va_arg(args, id)) != nil) {//루프 - 버튼을 그룹에 추가함.
  186. if ([buttons isKindOfClass:[CustomRadioButton class]]) {
  187. [buttons addTarget:self action:@selector(someRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
  188. [_btns addObject:buttons];
  189. }
  190. }
  191. va_end(args);
  192. }
  193. }
  194. return self;
  195. }
  196. //Do not use in resusable table
  197. - (void)addRadioButton:(CustomRadioButton *)button {//라디오 그룹에 버튼을 추가함.
  198. CustomRadioButton *lBtn = [_btns lastObject];
  199. if ([button isKindOfClass:[CustomBgRadioButton class]]) {
  200. if (lBtn == nil) {//첫번째 버튼
  201. if (_isFirstLoading) {
  202. _bgImageNormal = [button backgroundImageForState:UIControlStateNormal];
  203. _bgImageHighlight = [button backgroundImageForState:UIControlStateHighlighted];
  204. _isFirstLoading = NO;
  205. }
  206. [button setBackgroundImage:_bgImageHighlight forState:UIControlStateNormal];
  207. [button setBackgroundImage:_bgImageNormal forState:UIControlStateHighlighted];
  208. _btnChecked = button;
  209. _btnChecked.checked = YES;
  210. } else {
  211. [button setBackgroundImage:_bgImageNormal forState:UIControlStateNormal];
  212. [button setBackgroundImage:_bgImageHighlight forState:UIControlStateHighlighted];
  213. }
  214. } else if ([button isKindOfClass:[CustomRadioButton class]]) {
  215. if (lBtn == nil) {//첫번째 버튼
  216. if (_isFirstLoading) {
  217. _imageNormal = [button imageForState:UIControlStateNormal];
  218. _imageHighlight = [button imageForState:UIControlStateHighlighted];
  219. _isFirstLoading = NO;
  220. }
  221. [button setImage:_imageHighlight forState:UIControlStateNormal];
  222. [button setImage:_imageNormal forState:UIControlStateHighlighted];
  223. _btnChecked = button;
  224. _btnChecked.checked = YES;
  225. } else {
  226. [button setImage:_imageNormal forState:UIControlStateNormal];
  227. [button setImage:_imageHighlight forState:UIControlStateHighlighted];
  228. }
  229. }
  230. [button addTarget:self action:@selector(someRadioButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
  231. [_btns addObject:button];
  232. }
  233. - (void)reset {
  234. [_btns removeAllObjects];
  235. }
  236. - (id)valueForChecked {//선택된 Object를 반환함.
  237. return _btnChecked.value;
  238. }
  239. - (id)titleForChecked {//선택된 타이틀을 반환함.
  240. return _btnChecked.titleLabel.text;
  241. }
  242. - (NSInteger)count {
  243. return _btns.count;
  244. }
  245. - (NSArray *)rdoBtns {
  246. return _btns;
  247. }
  248. - (void)someRadioButtonTouched:(id)sender {//특정 라디오버튼이 선택된 경우, 값을 설정함.
  249. if (_btnChecked == sender)
  250. return;
  251. CustomRadioButton *btnSender = (CustomRadioButton *)sender;
  252. for (CustomRadioButton *btn in _btns) {
  253. if ([btnSender isEqual:btn]) {
  254. _btnChecked = btnSender;
  255. _btnChecked.checked = YES;
  256. } else {
  257. btn.checked = NO;
  258. }
  259. }
  260. if ([self.delegate respondsToSelector:@selector(didSomeRadioButtonTouched:)]) {
  261. [self.delegate didSomeRadioButtonTouched:sender];
  262. }
  263. }
  264. @end
  265. @interface CustomRadioReusableGroup () <CustomRadioButtonDelegate> {
  266. NSMutableArray *_valueArray;
  267. }
  268. @end
  269. @implementation CustomRadioReusableGroup
  270. - (instancetype)init {
  271. if (self = [super init]) {
  272. _valueArray = [[NSMutableArray alloc] init];
  273. }
  274. return self;
  275. }
  276. - (void)addRadioButton:(CustomRadioButton *)rbtn {
  277. if ([_valueArray containsObject:rbtn.value]) {//동일한 오브젝트에 대한 validate
  278. return;
  279. }
  280. rbtn.delegate = self;
  281. [_valueArray addObject:rbtn.value];
  282. }
  283. - (NSArray *)values {
  284. return _valueArray;
  285. }
  286. - (void)someRadioButtonTouched:(CustomRadioButton *)touchedRbtn {
  287. for (id avalue in _valueArray) {
  288. if ([touchedRbtn.value isEqual:avalue]) {
  289. touchedRbtn.checked = YES;
  290. continue;
  291. }
  292. if ([objc_getAssociatedObject(avalue, ksCustomRadioButtonStatus) boolValue]) {
  293. objc_setAssociatedObject(avalue, ksCustomRadioButtonStatus, [NSNumber numberWithBool:NO], OBJC_ASSOCIATION_COPY_NONATOMIC);
  294. }
  295. }
  296. [_tableView reloadData];
  297. if ([self.delegate respondsToSelector:@selector(didSomeReuableRadioButtonTouched:)]) {
  298. [self.delegate didSomeReuableRadioButtonTouched:touchedRbtn];
  299. }
  300. }
  301. - (void)reset {
  302. [_valueArray removeAllObjects];
  303. }
  304. - (id)valueForChecked {
  305. id resultValue = nil;
  306. for (id avalue in _valueArray) {
  307. if ([objc_getAssociatedObject(avalue, ksCustomRadioButtonStatus) boolValue]) {
  308. resultValue = avalue;
  309. }
  310. }
  311. return resultValue;
  312. }
  313. #pragma mark - CustomRadioButton Delegate
  314. - (void)didCheckRadioButton:(id)sender {
  315. [self someRadioButtonTouched:sender];
  316. }
  317. @end