SYJUISwitch.m 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. //
  2. // SYJUISwitch.m
  3. // SYJUISwitch
  4. //
  5. // Created by syj on 2021/8/17.
  6. //
  7. #import "SYJUISwitch.h"
  8. @interface SYJUISwitch ()
  9. @property (nonatomic, strong) UIView *bgColorView; //背景色
  10. @property (nonatomic, strong) UIImageView *thumbImageView; //滑块
  11. @property (nonatomic, assign) CGSize tempThumbSize;
  12. @property (nonatomic, assign) BOOL tempIsOn;
  13. @property (nonatomic, assign) NSInteger moveCount; //记录移动次数
  14. @end
  15. @implementation SYJUISwitch
  16. - (id)initWithFrame:(CGRect)frame
  17. {
  18. self = [super initWithFrame:frame];
  19. if (self) {
  20. [self initUI];
  21. }
  22. return self;
  23. }
  24. - (id)initWithCoder:(NSCoder *)aDecoder {
  25. if( (self = [super initWithCoder:aDecoder]) ){
  26. [self layoutIfNeeded];
  27. [self initUI];
  28. }
  29. return self;
  30. }
  31. - (void)initUI {
  32. self.backgroundColor = UIColor.clearColor;
  33. CGRect selfFrame = CGRectZero;
  34. if (CGRectEqualToRect(self.frame, CGRectZero)) {
  35. selfFrame = CGRectMake(0, 0, 51, 31);
  36. } else {
  37. selfFrame = self.frame;
  38. }
  39. self.frame = selfFrame;
  40. _onTintColor = [UIColor colorWithRed:103/255.0 green:204/255.0 blue:103/255.0 alpha:1];
  41. _offTintColor = [UIColor colorWithRed:212/255.0 green:212/255.0 blue:212/255.0 alpha:1];
  42. _thumbTintColor = UIColor.whiteColor;
  43. _thumbLeftSpace = 2;
  44. _thumbTopSpace = 2;
  45. _thumbSize = CGSizeMake(self.bounds.size.height - _thumbLeftSpace*2, self.bounds.size.height - _thumbTopSpace*2);
  46. _tailLength = 7;
  47. [self addSubview:self.bgColorView];
  48. [self addSubview:self.thumbImageView];
  49. }
  50. #pragma mark - Touch方法
  51. - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
  52. _moveCount = 0;
  53. _tempIsOn = self.isOn;
  54. _tempThumbSize = _thumbSize;
  55. _thumbSize.width = _thumbSize.width + _tailLength;
  56. [self updateThumbFrame:self.on animated:YES];
  57. [self sendActionsForControlEvents:UIControlEventEditingDidBegin];
  58. return YES;
  59. }
  60. - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
  61. CGPoint location = [touch locationInView:self];
  62. // NSLog(@"x = %f",location.x);
  63. if (location.x <= 0) {
  64. if ([self currentPositionIsOn]) {
  65. [self updateThumbFrame:NO animated:YES];
  66. [self updateUI:NO animated:YES];
  67. _moveCount += 1;
  68. }
  69. } else if (location.x >= self.bounds.size.width) {
  70. if ([self currentPositionIsOn] == NO) {
  71. [self updateThumbFrame:YES animated:YES];
  72. [self updateUI:YES animated:YES];
  73. _moveCount += 1;
  74. }
  75. }
  76. // [self sendActionsForControlEvents:UIControlEventEditingChanged];
  77. return YES;
  78. }
  79. - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
  80. [self endTracking];
  81. }
  82. - (void)cancelTrackingWithEvent:(nullable UIEvent *)event {
  83. [self endTracking];
  84. }
  85. - (void)endTracking {
  86. _thumbSize = _tempThumbSize;
  87. BOOL isOn = !self.isOn;
  88. if (_moveCount >= 2) {
  89. isOn = [self currentPositionIsOn];
  90. }
  91. [self setOn:isOn animated:YES];
  92. if (_tempIsOn != self.isOn) {
  93. [self sendActionsForControlEvents:UIControlEventValueChanged];
  94. }
  95. _moveCount = 0;
  96. }
  97. - (BOOL)currentPositionIsOn {
  98. BOOL isOn = self.thumbImageView.center.x >= self.bounds.size.width/2.0;
  99. return isOn;
  100. }
  101. - (void)layoutSubviews {
  102. [super layoutSubviews];
  103. self.bgColorView.frame = self.bounds;
  104. self.bgColorView.layer.cornerRadius = self.bgColorView.frame.size.height/2.0;
  105. CGFloat x = self.on ? self.bounds.size.width - self.thumbSize.width - self.thumbLeftSpace : self.thumbLeftSpace;
  106. self.thumbImageView.frame = CGRectMake(x, self.thumbTopSpace, self.thumbSize.width, self.thumbSize.height);
  107. self.thumbImageView.layer.cornerRadius = self.thumbImageView.frame.size.height/2.0;
  108. }
  109. #pragma mark - Update
  110. - (void)updateThumbFrame:(BOOL)on animated:(BOOL)animated {
  111. void (^taskBlock) (void) = ^{
  112. CGFloat x = on ? self.bounds.size.width - self.thumbSize.width - self.thumbLeftSpace : self.thumbLeftSpace;
  113. self.thumbImageView.frame = CGRectMake(x, self.thumbTopSpace, self.thumbSize.width, self.thumbSize.height);
  114. self.thumbImageView.layer.cornerRadius = self.thumbImageView.frame.size.height/2.0;
  115. };
  116. if (animated) {
  117. [UIView animateKeyframesWithDuration:0.2 delay:0 options:UIViewKeyframeAnimationOptionAllowUserInteraction animations:^{
  118. taskBlock();
  119. } completion:^(BOOL finished) {
  120. }];
  121. } else {
  122. taskBlock();
  123. }
  124. }
  125. - (void)updateUI:(BOOL)on animated:(BOOL)animated {
  126. void (^taskBlock) (void) = ^{
  127. if (on) {
  128. self.bgColorView.backgroundColor = self.onTintColor;
  129. if (self.onImage) {
  130. self.thumbImageView.image = self.onImage;
  131. } else {
  132. self.thumbImageView.image = nil;
  133. }
  134. } else {
  135. self.bgColorView.backgroundColor = self.offTintColor;
  136. if (self.offImage) {
  137. self.thumbImageView.image = self.offImage;
  138. } else {
  139. self.thumbImageView.image = nil;
  140. }
  141. }
  142. self.thumbImageView.backgroundColor = self.thumbTintColor;
  143. };
  144. if (animated) {
  145. [UIView animateKeyframesWithDuration:0.2 delay:0 options:UIViewKeyframeAnimationOptionAllowUserInteraction animations:^{
  146. taskBlock();
  147. } completion:^(BOOL finished) {
  148. }];
  149. } else {
  150. taskBlock();
  151. }
  152. }
  153. - (void)updateThumbPosition:(BOOL)on animated:(BOOL)animated {
  154. void (^taskBlock) (void) = ^{
  155. // CGFloat x = on ? self.bounds.size.width - self.thumbSize.width - self.thumbLeftSpace : self.thumbLeftSpace;
  156. // self.thumbImageView.frame = CGRectMake(x, self.thumbImageView.frame.origin.y, self.thumbSize.width, self.thumbSize.height);
  157. self.thumbImageView.bounds = CGRectMake(0, 0, self.thumbSize.width, self.thumbSize.height);
  158. CGPoint center = self.thumbImageView.center;
  159. if (on) {
  160. center.x = self.bounds.size.width - self.thumbImageView.frame.size.width/2.0 - self.thumbLeftSpace;
  161. } else {
  162. center.x = self.thumbImageView.frame.size.width/2.0 + self.thumbLeftSpace;
  163. }
  164. self.thumbImageView.center = center;
  165. };
  166. if (animated) {
  167. [UIView animateKeyframesWithDuration:0.2 delay:0 options:UIViewKeyframeAnimationOptionAllowUserInteraction animations:^{
  168. taskBlock();
  169. } completion:^(BOOL finished) {
  170. }];
  171. } else {
  172. taskBlock();
  173. }
  174. }
  175. #pragma mark - Set
  176. - (void)setOnTintColor:(UIColor *)onTintColor {
  177. _onTintColor = onTintColor;
  178. [self updateUI:self.on animated:YES];
  179. }
  180. - (void)setOffTintColor:(UIColor *)offTintColor {
  181. _offTintColor = offTintColor;
  182. [self updateUI:self.on animated:YES];
  183. }
  184. - (void)setThumbTintColor:(UIColor *)thumbTintColor {
  185. _thumbTintColor = thumbTintColor;
  186. [self updateUI:self.on animated:YES];
  187. }
  188. - (void)setOnImage:(UIImage *)onImage {
  189. _onImage = onImage;
  190. [self updateUI:self.on animated:YES];
  191. }
  192. - (void)setOffImage:(UIImage *)offImage {
  193. _offImage = offImage;
  194. [self updateUI:self.on animated:YES];
  195. }
  196. - (void)setThumbLeftSpace:(CGFloat)thumbLeftSpace {
  197. _thumbLeftSpace = thumbLeftSpace;
  198. [self updateThumbFrame:self.on animated:NO];
  199. }
  200. - (void)setThumbTopSpace:(CGFloat)thumbTopSpace {
  201. _thumbTopSpace = thumbTopSpace;
  202. [self updateThumbFrame:self.on animated:NO];
  203. }
  204. - (void)setThumbSize:(CGSize)thumbSize {
  205. _thumbSize = thumbSize;
  206. [self updateThumbFrame:self.on animated:NO];
  207. }
  208. - (void)setThumbLeftSpace:(CGFloat)thumbLeftSpace animated:(BOOL)animated {
  209. _thumbLeftSpace = thumbLeftSpace;
  210. [self updateThumbFrame:self.on animated:animated];
  211. }
  212. - (void)setThumbTopSpace:(CGFloat)thumbTopSpace animated:(BOOL)animated {
  213. _thumbTopSpace = thumbTopSpace;
  214. [self updateThumbFrame:self.on animated:animated];
  215. }
  216. - (void)setThumbSize:(CGSize)thumbSize animated:(BOOL)animated {
  217. _thumbSize = thumbSize;
  218. [self updateThumbFrame:self.on animated:animated];
  219. }
  220. - (void)setOn:(BOOL)on {
  221. [self setOn:on animated:NO];
  222. }
  223. - (void)setOn:(BOOL)on animated:(BOOL)animated {
  224. _on = on;
  225. [self updateThumbFrame:on animated:animated];
  226. [self updateUI:on animated:animated];
  227. // NSLog(@"%@", on ? @"开":@"关");
  228. }
  229. - (void)setEnabled:(BOOL)enabled {
  230. self.alpha = enabled ? 1.f : .5f;
  231. [super setEnabled:enabled];
  232. }
  233. /// 忽略返回手势,防止与侧滑手势冲突
  234. - (BOOL)ignorePopGesture {
  235. return YES;
  236. }
  237. - (UIView *)bgColorView {
  238. if (!_bgColorView) {
  239. _bgColorView = [UIView new];
  240. _bgColorView.layer.masksToBounds = YES;
  241. _bgColorView.backgroundColor = self.offTintColor;
  242. _bgColorView.userInteractionEnabled = NO;
  243. }
  244. return _bgColorView;
  245. }
  246. - (UIImageView *)thumbImageView {
  247. if (!_thumbImageView) {
  248. _thumbImageView = [[UIImageView alloc] init];
  249. _thumbImageView.backgroundColor = self.thumbTintColor;
  250. _thumbImageView.layer.shadowColor = [UIColor blackColor].CGColor;
  251. _thumbImageView.layer.shadowOffset = CGSizeMake(0.0, 3.0);
  252. _thumbImageView.layer.shadowRadius = 3.0;
  253. _thumbImageView.layer.shadowOpacity = 0.3;
  254. _thumbImageView.layer.masksToBounds = YES;
  255. _thumbImageView.userInteractionEnabled = NO;
  256. }
  257. return _thumbImageView;
  258. }
  259. @end