CustomRadioGroup.m 14 KB

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