ZQTCustomSwitch.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. //
  2. // ZQTCustomSwitch.m
  3. // ZQTCustomSwitch
  4. //
  5. // Created by 赵群涛 on 16/5/25.
  6. // Copyright © 2016年 ZQT. All rights reserved.
  7. //
  8. #import "ZQTCustomSwitch.h"
  9. #define LQXSwitchMaxHeight 80.0f
  10. #define LQXSwitchMinHeight 20.0f
  11. #define LQXSwitchMinWidth 40.0f
  12. @interface ZQTCustomSwitch ()
  13. @property (nonatomic, strong) UIView *containerView;
  14. @property (nonatomic, strong) UIView *onContentView;
  15. @property (nonatomic, strong) UIView *offContentView;
  16. @property (nonatomic, strong) UIColor *onColor;
  17. @property (nonatomic, assign) NSInteger ballSize;
  18. @property (nonatomic, strong) UIFont * font;
  19. @property (nonatomic, strong) UIColor *offColor;
  20. @property (nonatomic, strong) UIView *knobView;
  21. @property (nonatomic, strong) UILabel *onLabel;
  22. @property (nonatomic, strong) UILabel *offLabel;
  23. - (void)commonInit;
  24. - (CGRect)roundRect:(CGRect)frameOrBounds;
  25. - (void)handleTapTapGestureRecognizerEvent:(UITapGestureRecognizer *)recognizer;
  26. - (void)handlePanGestureRecognizerEvent:(UIPanGestureRecognizer *)recognizer;
  27. @end
  28. @implementation ZQTCustomSwitch
  29. - (id)initWithFrame:(CGRect)frame onColor:(UIColor *)onColor offColor:(UIColor *)offColor font:(UIFont *)font ballSize:(NSInteger )ballSize
  30. {
  31. self = [super initWithFrame:[self roundRect:frame]];
  32. if (self) {
  33. self.ballSize = ballSize;
  34. self.font = font;
  35. self.onColor = onColor;
  36. self.offColor = offColor;
  37. [self commonInit];
  38. }
  39. return self;
  40. }
  41. - (id)initWithCoder:(NSCoder *)aDecoder
  42. {
  43. self = [super initWithCoder:aDecoder];
  44. if (self) {
  45. [self commonInit];
  46. }
  47. return self;
  48. }
  49. - (void)setBounds:(CGRect)bounds
  50. {
  51. [super setBounds:[self roundRect:bounds]];
  52. [self setNeedsLayout];
  53. }
  54. - (void)setFrame:(CGRect)frame
  55. {
  56. [super setFrame:[self roundRect:frame]];
  57. [self setNeedsLayout];
  58. }
  59. - (void)setOnText:(NSString *)onText
  60. {
  61. if (_onText != onText) {
  62. _onText = onText;
  63. _onLabel.text = onText;
  64. }
  65. }
  66. - (void)setOffText:(NSString *)offText
  67. {
  68. if (_offText != offText) {
  69. _offText = offText;
  70. _offLabel.text = offText;
  71. }
  72. }
  73. - (void)setOnTintColor:(UIColor *)onTintColor
  74. {
  75. if (_onTintColor != onTintColor) {
  76. _onTintColor = onTintColor;
  77. _onContentView.backgroundColor = onTintColor;
  78. }
  79. }
  80. - (void)setTintColor:(UIColor *)tintColor
  81. {
  82. if (_tintColor != tintColor) {
  83. _tintColor = tintColor;
  84. _offContentView.backgroundColor = tintColor;
  85. }
  86. }
  87. - (void)setThumbTintColor:(UIColor *)thumbTintColor
  88. {
  89. if (_thumbTintColor != thumbTintColor) {
  90. _thumbTintColor = thumbTintColor;
  91. _knobView.backgroundColor = _thumbTintColor;
  92. }
  93. }
  94. -(void)setTextColor:(UIColor *)textColor{
  95. if (_textColor != textColor) {
  96. _textColor = textColor;
  97. _offLabel.textColor = _textColor;
  98. _onLabel.textColor = _textColor;
  99. }
  100. }
  101. - (void)layoutSubviews
  102. {
  103. [super layoutSubviews];
  104. self.containerView.frame = self.bounds;
  105. CGFloat r = CGRectGetHeight(self.containerView.bounds) / 2.0;
  106. self.containerView.layer.cornerRadius = r;
  107. self.containerView.layer.masksToBounds = YES;
  108. CGFloat margin = (CGRectGetHeight(self.bounds) - self.ballSize) / 2.0;
  109. if (!self.isOn) {
  110. // frame of off status
  111. self.onContentView.frame = CGRectMake(-1 * CGRectGetWidth(self.containerView.bounds),
  112. 0,
  113. CGRectGetWidth(self.containerView.bounds),
  114. CGRectGetHeight(self.containerView.bounds));
  115. self.offContentView.frame = CGRectMake(0,
  116. 0,
  117. CGRectGetWidth(self.containerView.bounds),
  118. CGRectGetHeight(self.containerView.bounds));
  119. self.knobView.frame = CGRectMake(margin,
  120. margin,
  121. self.ballSize,
  122. self.ballSize);
  123. } else {
  124. // frame of on status
  125. self.onContentView.frame = CGRectMake(0,
  126. 0,
  127. CGRectGetWidth(self.containerView.bounds),
  128. CGRectGetHeight(self.containerView.bounds));
  129. self.offContentView.frame = CGRectMake(0,
  130. CGRectGetWidth(self.containerView.bounds),
  131. CGRectGetWidth(self.containerView.bounds),
  132. CGRectGetHeight(self.containerView.bounds));
  133. self.knobView.frame = CGRectMake(CGRectGetWidth(self.containerView.bounds) - margin - self.ballSize,
  134. margin,
  135. self.ballSize,
  136. self.ballSize);
  137. }
  138. CGFloat lHeight = 20.0f;
  139. CGFloat lMargin = r - (sqrtf(powf(r, 2) - powf(lHeight / 2.0, 2))) + margin;
  140. self.onLabel.frame = CGRectMake(lMargin,
  141. r - lHeight / 2.0,
  142. CGRectGetWidth(self.onContentView.bounds) - lMargin - self.ballSize - 2 * margin,
  143. lHeight);
  144. self.offLabel.frame = CGRectMake(self.ballSize + 2 * margin,
  145. r - lHeight / 2.0,
  146. CGRectGetWidth(self.onContentView.bounds) - lMargin - self.ballSize - 2 * margin,
  147. lHeight);
  148. }
  149. - (void)setOn:(BOOL)on
  150. {
  151. [self setOn:on animated:NO];
  152. }
  153. - (void)setOn:(BOOL)on animated:(BOOL)animated
  154. {
  155. if (_on == on) {
  156. return;
  157. }
  158. _on = on;
  159. CGFloat margin = (CGRectGetHeight(self.bounds) - self.ballSize) / 2.0;
  160. if (!animated) {
  161. if (!self.isOn) {
  162. // frame of off status
  163. self.onContentView.frame = CGRectMake(-1 * CGRectGetWidth(self.containerView.bounds),
  164. 0,
  165. CGRectGetWidth(self.containerView.bounds),
  166. CGRectGetHeight(self.containerView.bounds));
  167. self.offContentView.frame = CGRectMake(0,
  168. 0,
  169. CGRectGetWidth(self.containerView.bounds),
  170. CGRectGetHeight(self.containerView.bounds));
  171. self.knobView.frame = CGRectMake(margin,
  172. margin,
  173. self.ballSize,
  174. self.ballSize);
  175. } else {
  176. // frame of on status
  177. self.onContentView.frame = CGRectMake(0,
  178. 0,
  179. CGRectGetWidth(self.containerView.bounds),
  180. CGRectGetHeight(self.containerView.bounds));
  181. self.offContentView.frame = CGRectMake(0,
  182. CGRectGetWidth(self.containerView.bounds),
  183. CGRectGetWidth(self.containerView.bounds),
  184. CGRectGetHeight(self.containerView.bounds));
  185. self.knobView.frame = CGRectMake(CGRectGetWidth(self.containerView.bounds) - margin - self.ballSize,
  186. margin,
  187. self.ballSize,
  188. self.ballSize);
  189. }
  190. } else {
  191. if (self.isOn) {
  192. [UIView animateWithDuration:0.25
  193. animations:^{
  194. self.knobView.frame = CGRectMake(CGRectGetWidth(self.containerView.bounds) - margin - self.ballSize,
  195. margin,
  196. self.ballSize,
  197. self.ballSize);
  198. }
  199. completion:^(BOOL finished){
  200. self.onContentView.frame = CGRectMake(0,
  201. 0,
  202. CGRectGetWidth(self.containerView.bounds),
  203. CGRectGetHeight(self.containerView.bounds));
  204. self.offContentView.frame = CGRectMake(0,
  205. CGRectGetWidth(self.containerView.bounds),
  206. CGRectGetWidth(self.containerView.bounds),
  207. CGRectGetHeight(self.containerView.bounds));
  208. }];
  209. } else {
  210. [UIView animateWithDuration:0.25
  211. animations:^{
  212. self.knobView.frame = CGRectMake(margin,
  213. margin,
  214. self.ballSize,
  215. self.ballSize);
  216. }
  217. completion:^(BOOL finished){
  218. self.onContentView.frame = CGRectMake(-1 * CGRectGetWidth(self.containerView.bounds),
  219. 0,
  220. CGRectGetWidth(self.containerView.bounds),
  221. CGRectGetHeight(self.containerView.bounds));
  222. self.offContentView.frame = CGRectMake(0,
  223. 0,
  224. CGRectGetWidth(self.containerView.bounds),
  225. CGRectGetHeight(self.containerView.bounds));
  226. }];
  227. }
  228. }
  229. [self sendActionsForControlEvents:UIControlEventValueChanged];
  230. }
  231. #pragma mark - Private API
  232. - (void)commonInit
  233. {
  234. self.backgroundColor = [UIColor clearColor];
  235. _onTintColor = self.onColor;
  236. _tintColor = self.offColor;
  237. _thumbTintColor = [UIColor colorWithWhite:1.0 alpha:1.0];
  238. _textFont = self.font;
  239. _textColor = [UIColor whiteColor];
  240. _containerView = [[UIView alloc] initWithFrame:self.bounds];
  241. _containerView.backgroundColor = [UIColor clearColor];
  242. [self addSubview:_containerView];
  243. _onContentView = [[UIView alloc] initWithFrame:self.bounds];
  244. _onContentView.backgroundColor = _onTintColor;
  245. [_containerView addSubview:_onContentView];
  246. _offContentView = [[UIView alloc] initWithFrame:self.bounds];
  247. _offContentView.backgroundColor = _tintColor;
  248. [_containerView addSubview:_offContentView];
  249. _knobView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.ballSize, self.ballSize)];
  250. _knobView.backgroundColor = _thumbTintColor;
  251. _knobView.layer.cornerRadius = self.ballSize / 2.0;
  252. [_containerView addSubview:_knobView];
  253. _onLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  254. _onLabel.backgroundColor = [UIColor clearColor];
  255. _onLabel.textAlignment = NSTextAlignmentCenter;
  256. _onLabel.textColor = _textColor;
  257. _onLabel.font = _font;
  258. _onLabel.text = _onText;
  259. [_onContentView addSubview:_onLabel];
  260. _offLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  261. _offLabel.backgroundColor = [UIColor clearColor];
  262. _offLabel.textAlignment = NSTextAlignmentCenter;
  263. _offLabel.textColor = _textColor;
  264. _offLabel.font = _font;
  265. _offLabel.text = _offText;
  266. [_offContentView addSubview:_offLabel];
  267. UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self
  268. action:@selector(handleTapTapGestureRecognizerEvent:)];
  269. [self addGestureRecognizer:tapGesture];
  270. UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self
  271. action:@selector(handlePanGestureRecognizerEvent:)];
  272. [self addGestureRecognizer:panGesture];
  273. }
  274. - (CGRect)roundRect:(CGRect)frameOrBounds
  275. {
  276. CGRect newRect = frameOrBounds;
  277. if (newRect.size.height > LQXSwitchMaxHeight) {
  278. newRect.size.height = LQXSwitchMaxHeight;
  279. }
  280. if (newRect.size.height < LQXSwitchMinHeight) {
  281. newRect.size.height = LQXSwitchMinHeight;
  282. }
  283. if (newRect.size.width < LQXSwitchMinWidth) {
  284. newRect.size.width = LQXSwitchMinWidth;
  285. }
  286. return newRect;
  287. }
  288. - (void)handleTapTapGestureRecognizerEvent:(UITapGestureRecognizer *)recognizer
  289. {
  290. if (recognizer.state == UIGestureRecognizerStateEnded) {
  291. if (self.delegate && [self.delegate respondsToSelector:@selector(handleGestureRecognizerWithSwithOn:)]) {
  292. [self.delegate handleGestureRecognizerWithSwithOn:!self.isOn];
  293. }
  294. [self setOn:!self.isOn animated:NO];
  295. }
  296. }
  297. - (void)handlePanGestureRecognizerEvent:(UIPanGestureRecognizer *)recognizer
  298. {
  299. CGFloat margin = (CGRectGetHeight(self.bounds) - self.ballSize) / 2.0;
  300. CGFloat offset = 6.0f;
  301. switch (recognizer.state) {
  302. case UIGestureRecognizerStateBegan:{
  303. if (!self.isOn) {
  304. [UIView animateWithDuration:0.25
  305. animations:^{
  306. self.knobView.frame = CGRectMake(margin,
  307. margin,
  308. self.ballSize + offset,
  309. self.ballSize);
  310. }];
  311. } else {
  312. [UIView animateWithDuration:0.25
  313. animations:^{
  314. self.knobView.frame = CGRectMake(CGRectGetWidth(self.containerView.bounds) - margin - (self.ballSize + offset),
  315. margin,
  316. self.ballSize + offset,
  317. self.ballSize);
  318. }];
  319. }
  320. break;
  321. }
  322. case UIGestureRecognizerStateCancelled:
  323. case UIGestureRecognizerStateFailed: {
  324. if (!self.isOn) {
  325. [UIView animateWithDuration:0.25
  326. animations:^{
  327. self.knobView.frame = CGRectMake(margin,
  328. margin,
  329. self.ballSize,
  330. self.ballSize);
  331. }];
  332. } else {
  333. [UIView animateWithDuration:0.25
  334. animations:^{
  335. self.knobView.frame = CGRectMake(CGRectGetWidth(self.containerView.bounds) - self.ballSize,
  336. margin,
  337. self.ballSize,
  338. self.ballSize);
  339. }];
  340. }
  341. break;
  342. }
  343. case UIGestureRecognizerStateChanged:{
  344. break;
  345. }
  346. case UIGestureRecognizerStateEnded:
  347. if (self.delegate && [self.delegate respondsToSelector:@selector(handleGestureRecognizerWithSwithOn:)]) {
  348. [self.delegate handleGestureRecognizerWithSwithOn:!self.isOn];
  349. }
  350. [self setOn:!self.isOn animated:YES];
  351. break;
  352. case UIGestureRecognizerStatePossible:
  353. break;
  354. }
  355. }
  356. @end