TOPasscodeFixedInputView.m 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. //
  2. // TOPasscodeFixedInputView.h
  3. //
  4. // Copyright 2017 Timothy Oliver. All rights reserved.
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to
  8. // deal in the Software without restriction, including without limitation the
  9. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. // sell copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
  21. // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. #import "TOPasscodeFixedInputView.h"
  23. #import "TOPasscodeCircleView.h"
  24. #import "TOPasscodeCircleImage.h"
  25. @interface TOPasscodeFixedInputView ()
  26. @property (nonatomic, strong, readwrite) NSArray<TOPasscodeCircleView *> *circleViews;
  27. @property (nonatomic, strong) UIImage *circleImage;
  28. @property (nonatomic, strong) UIImage *highlightedCircleImage;
  29. @end
  30. @implementation TOPasscodeFixedInputView
  31. #pragma mark - Object Creation -
  32. - (instancetype)initWithLength:(NSInteger)length
  33. {
  34. if (self = [self initWithFrame:CGRectZero]) {
  35. _length = length;
  36. }
  37. return self;
  38. }
  39. - (instancetype)initWithFrame:(CGRect)frame
  40. {
  41. if (self = [super initWithFrame:frame]) {
  42. _circleSpacing = 25.0f;
  43. _circleDiameter = 16.0f;
  44. _length = 4;
  45. }
  46. return self;
  47. }
  48. #pragma mark - View Configuration -
  49. - (void)sizeToFit
  50. {
  51. // Resize the view to encompass the circles
  52. CGRect frame = self.frame;
  53. frame.size.width = (_circleDiameter * _length) + (_circleSpacing * (_length - 1)) + 2.0f;
  54. frame.size.height = _circleDiameter + 2.0f;
  55. self.frame = CGRectIntegral(frame);
  56. }
  57. - (void)layoutSubviews
  58. {
  59. CGRect frame = CGRectZero;
  60. frame.size = (CGSize){self.circleDiameter + 2.0f, self.circleDiameter + 2.0f};
  61. for (TOPasscodeCircleView *circleView in self.circleViews) {
  62. circleView.frame = frame;
  63. frame.origin.x += self.circleDiameter + self.circleSpacing;
  64. }
  65. }
  66. #pragma mark - State Configuration -
  67. - (void)setHighlightedLength:(NSInteger)highlightedLength animated:(BOOL)animated
  68. {
  69. NSInteger i = 0;
  70. for (TOPasscodeCircleView *circleView in self.circleViews) {
  71. [circleView setHighlighted:(i < highlightedLength) animated:animated];
  72. i++;
  73. }
  74. }
  75. #pragma mark - Circle View Configuration -
  76. - (void)setCircleViewsForLength:(NSInteger)length
  77. {
  78. NSMutableArray *circleViews = [NSMutableArray array];
  79. if (self.circleViews) {
  80. [circleViews addObjectsFromArray:self.circleViews];
  81. }
  82. [UIView performWithoutAnimation:^{
  83. while (circleViews.count != length) {
  84. // Remove any extra circle views
  85. if (circleViews.count > length) {
  86. TOPasscodeCircleView *lastCircle = circleViews.lastObject;
  87. [lastCircle removeFromSuperview];
  88. [circleViews removeLastObject];
  89. continue;
  90. }
  91. // Add any new circle views
  92. TOPasscodeCircleView *newCircleView = [[TOPasscodeCircleView alloc] init];
  93. [self setImagesOfCircleView:newCircleView];
  94. [self addSubview:newCircleView];
  95. [circleViews addObject:newCircleView];
  96. }
  97. self.circleViews = [NSArray arrayWithArray:circleViews];
  98. [self setNeedsLayout];
  99. [self layoutIfNeeded];
  100. }];
  101. }
  102. - (void)setCircleImagesForDiameter:(CGFloat)diameter
  103. {
  104. self.circleImage = [TOPasscodeCircleImage hollowCircleImageOfSize:diameter strokeWidth:1.2f padding:1.0f];
  105. self.highlightedCircleImage = [TOPasscodeCircleImage circleImageOfSize:diameter inset:0.5f padding:1.0f antialias:YES];
  106. for (TOPasscodeCircleView *circleView in self.circleViews) {
  107. [self setImagesOfCircleView:circleView];
  108. }
  109. }
  110. - (void)setImagesOfCircleView:(TOPasscodeCircleView *)circleView
  111. {
  112. circleView.circleImage = self.circleImage;
  113. circleView.highlightedCircleImage = self.highlightedCircleImage;
  114. }
  115. #pragma mark - Accessors -
  116. - (NSArray<TOPasscodeCircleView *> *)circleViews
  117. {
  118. if (_circleViews) { return _circleViews; }
  119. _circleViews = [NSArray array];
  120. [self setCircleViewsForLength:self.length];
  121. [self setCircleImagesForDiameter:self.circleDiameter];
  122. return _circleViews;
  123. }
  124. - (void)setCircleDiameter:(CGFloat)circleDiameter
  125. {
  126. if (circleDiameter == _circleDiameter) { return; }
  127. _circleDiameter = circleDiameter;
  128. [self setCircleImagesForDiameter:_circleDiameter];
  129. [self sizeToFit];
  130. }
  131. - (void)setLength:(NSInteger)length
  132. {
  133. if (_length == length) { return; }
  134. _length = length;
  135. [self setCircleViewsForLength:length];
  136. }
  137. - (void)setHighlightedLength:(NSInteger)highlightedLength
  138. {
  139. [self setHighlightedLength:highlightedLength animated:NO];
  140. }
  141. @end