FUSwitch.m 17 KB

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