SGQRCodeScanView.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. //
  2. // SGQRCodeScanView.m
  3. // SGQRCodeExample
  4. //
  5. // Created by kingsic on 2017/8/23.
  6. // Copyright © 2017年 kingsic All rights reserved.
  7. //
  8. #import "SGQRCodeScanView.h"
  9. /** 扫描内容的 W 值 */
  10. #define scanBorderW 0.7 * self.frame.size.width
  11. /** 扫描内容的 x 值 */
  12. #define scanBorderX 0.5 * (1 - 0.7) * self.frame.size.width
  13. /** 扫描内容的 Y 值 */
  14. #define scanBorderY 0.5 * (self.frame.size.height - scanBorderW)
  15. @interface SGQRCodeScanView ()
  16. @property (nonatomic, strong) UIView *contentView;
  17. @property (nonatomic, strong) NSTimer *timer;
  18. @property (nonatomic, strong) UIImageView *scanningline;
  19. @end
  20. @implementation SGQRCodeScanView
  21. - (instancetype)initWithFrame:(CGRect)frame {
  22. if (self = [super initWithFrame:frame]) {
  23. self.backgroundColor = [UIColor clearColor];
  24. [self initialization];
  25. }
  26. return self;
  27. }
  28. - (void)awakeFromNib {
  29. [super awakeFromNib];
  30. [self initialization];
  31. }
  32. - (void)initialization {
  33. _scanAnimationStyle = ScanAnimationStyleDefault;
  34. _borderColor = [UIColor whiteColor];
  35. _cornerLocation = CornerLoactionDefault;
  36. _cornerColor = [UIColor colorWithRed:85/255.0f green:183/255.0 blue:55/255.0 alpha:1.0];
  37. _cornerWidth = 2.0;
  38. _backgroundAlpha = 0.5;
  39. _animationTimeInterval = 0.02;
  40. _scanImageName = @"QRCodeScanLine";
  41. }
  42. - (UIView *)contentView {
  43. if (!_contentView) {
  44. _contentView = [[UIView alloc] init];
  45. _contentView.frame = CGRectMake(scanBorderX, scanBorderY, scanBorderW, scanBorderW);
  46. _contentView.clipsToBounds = YES;
  47. _contentView.backgroundColor = [UIColor clearColor];
  48. }
  49. return _contentView;
  50. }
  51. - (void)drawRect:(CGRect)rect {
  52. [super drawRect:rect];
  53. /// 边框 frame
  54. CGFloat borderW = scanBorderW;
  55. CGFloat borderH = borderW;
  56. CGFloat borderX = scanBorderX;
  57. CGFloat borderY = scanBorderY;
  58. CGFloat borderLineW = 0.2;
  59. /// 空白区域设置
  60. [[[UIColor blackColor] colorWithAlphaComponent:self.backgroundAlpha] setFill];
  61. UIRectFill(rect);
  62. // 获取上下文,并设置混合模式 -> kCGBlendModeDestinationOut
  63. CGContextRef context = UIGraphicsGetCurrentContext();
  64. CGContextSetBlendMode(context, kCGBlendModeDestinationOut);
  65. // 设置空白区
  66. UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(borderX + 0.5 * borderLineW, borderY + 0.5 *borderLineW, borderW - borderLineW, borderH - borderLineW)];
  67. [bezierPath fill];
  68. // 执行混合模式
  69. CGContextSetBlendMode(context, kCGBlendModeNormal);
  70. /// 边框设置
  71. UIBezierPath *borderPath = [UIBezierPath bezierPathWithRect:CGRectMake(borderX, borderY, borderW, borderH)];
  72. borderPath.lineCapStyle = kCGLineCapButt;
  73. borderPath.lineWidth = borderLineW;
  74. [self.borderColor set];
  75. [borderPath stroke];
  76. CGFloat cornerLenght = 20;
  77. /// 左上角小图标
  78. UIBezierPath *leftTopPath = [UIBezierPath bezierPath];
  79. leftTopPath.lineWidth = self.cornerWidth;
  80. [self.cornerColor set];
  81. CGFloat insideExcess = fabs(0.5 * (self.cornerWidth - borderLineW));
  82. CGFloat outsideExcess = 0.5 * (borderLineW + self.cornerWidth);
  83. if (self.cornerLocation == CornerLoactionInside) {
  84. [leftTopPath moveToPoint:CGPointMake(borderX + insideExcess, borderY + cornerLenght + insideExcess)];
  85. [leftTopPath addLineToPoint:CGPointMake(borderX + insideExcess, borderY + insideExcess)];
  86. [leftTopPath addLineToPoint:CGPointMake(borderX + cornerLenght + insideExcess, borderY + insideExcess)];
  87. } else if (self.cornerLocation == CornerLoactionOutside) {
  88. [leftTopPath moveToPoint:CGPointMake(borderX - outsideExcess, borderY + cornerLenght - outsideExcess)];
  89. [leftTopPath addLineToPoint:CGPointMake(borderX - outsideExcess, borderY - outsideExcess)];
  90. [leftTopPath addLineToPoint:CGPointMake(borderX + cornerLenght - outsideExcess, borderY - outsideExcess)];
  91. } else {
  92. [leftTopPath moveToPoint:CGPointMake(borderX, borderY + cornerLenght)];
  93. [leftTopPath addLineToPoint:CGPointMake(borderX, borderY)];
  94. [leftTopPath addLineToPoint:CGPointMake(borderX + cornerLenght, borderY)];
  95. }
  96. [leftTopPath stroke];
  97. /// 左下角小图标
  98. UIBezierPath *leftBottomPath = [UIBezierPath bezierPath];
  99. leftBottomPath.lineWidth = self.cornerWidth;
  100. [self.cornerColor set];
  101. if (self.cornerLocation == CornerLoactionInside) {
  102. [leftBottomPath moveToPoint:CGPointMake(borderX + cornerLenght + insideExcess, borderY + borderH - insideExcess)];
  103. [leftBottomPath addLineToPoint:CGPointMake(borderX + insideExcess, borderY + borderH - insideExcess)];
  104. [leftBottomPath addLineToPoint:CGPointMake(borderX + insideExcess, borderY + borderH - cornerLenght - insideExcess)];
  105. } else if (self.cornerLocation == CornerLoactionOutside) {
  106. [leftBottomPath moveToPoint:CGPointMake(borderX + cornerLenght - outsideExcess, borderY + borderH + outsideExcess)];
  107. [leftBottomPath addLineToPoint:CGPointMake(borderX - outsideExcess, borderY + borderH + outsideExcess)];
  108. [leftBottomPath addLineToPoint:CGPointMake(borderX - outsideExcess, borderY + borderH - cornerLenght + outsideExcess)];
  109. } else {
  110. [leftBottomPath moveToPoint:CGPointMake(borderX + cornerLenght, borderY + borderH)];
  111. [leftBottomPath addLineToPoint:CGPointMake(borderX, borderY + borderH)];
  112. [leftBottomPath addLineToPoint:CGPointMake(borderX, borderY + borderH - cornerLenght)];
  113. }
  114. [leftBottomPath stroke];
  115. /// 右上角小图标
  116. UIBezierPath *rightTopPath = [UIBezierPath bezierPath];
  117. rightTopPath.lineWidth = self.cornerWidth;
  118. [self.cornerColor set];
  119. if (self.cornerLocation == CornerLoactionInside) {
  120. [rightTopPath moveToPoint:CGPointMake(borderX + borderW - cornerLenght - insideExcess, borderY + insideExcess)];
  121. [rightTopPath addLineToPoint:CGPointMake(borderX + borderW - insideExcess, borderY + insideExcess)];
  122. [rightTopPath addLineToPoint:CGPointMake(borderX + borderW - insideExcess, borderY + cornerLenght + insideExcess)];
  123. } else if (self.cornerLocation == CornerLoactionOutside) {
  124. [rightTopPath moveToPoint:CGPointMake(borderX + borderW - cornerLenght + outsideExcess, borderY - outsideExcess)];
  125. [rightTopPath addLineToPoint:CGPointMake(borderX + borderW + outsideExcess, borderY - outsideExcess)];
  126. [rightTopPath addLineToPoint:CGPointMake(borderX + borderW + outsideExcess, borderY + cornerLenght - outsideExcess)];
  127. } else {
  128. [rightTopPath moveToPoint:CGPointMake(borderX + borderW - cornerLenght, borderY)];
  129. [rightTopPath addLineToPoint:CGPointMake(borderX + borderW, borderY)];
  130. [rightTopPath addLineToPoint:CGPointMake(borderX + borderW, borderY + cornerLenght)];
  131. }
  132. [rightTopPath stroke];
  133. /// 右下角小图标
  134. UIBezierPath *rightBottomPath = [UIBezierPath bezierPath];
  135. rightBottomPath.lineWidth = self.cornerWidth;
  136. [self.cornerColor set];
  137. if (self.cornerLocation == CornerLoactionInside) {
  138. [rightBottomPath moveToPoint:CGPointMake(borderX + borderW - insideExcess, borderY + borderH - cornerLenght - insideExcess)];
  139. [rightBottomPath addLineToPoint:CGPointMake(borderX + borderW - insideExcess, borderY + borderH - insideExcess)];
  140. [rightBottomPath addLineToPoint:CGPointMake(borderX + borderW - cornerLenght - insideExcess, borderY + borderH - insideExcess)];
  141. } else if (self.cornerLocation == CornerLoactionOutside) {
  142. [rightBottomPath moveToPoint:CGPointMake(borderX + borderW + outsideExcess, borderY + borderH - cornerLenght + outsideExcess)];
  143. [rightBottomPath addLineToPoint:CGPointMake(borderX + borderW + outsideExcess, borderY + borderH + outsideExcess)];
  144. [rightBottomPath addLineToPoint:CGPointMake(borderX + borderW - cornerLenght + outsideExcess, borderY + borderH + outsideExcess)];
  145. } else {
  146. [rightBottomPath moveToPoint:CGPointMake(borderX + borderW, borderY + borderH - cornerLenght)];
  147. [rightBottomPath addLineToPoint:CGPointMake(borderX + borderW, borderY + borderH)];
  148. [rightBottomPath addLineToPoint:CGPointMake(borderX + borderW - cornerLenght, borderY + borderH)];
  149. }
  150. [rightBottomPath stroke];
  151. }
  152. #pragma mark - - - 添加定时器
  153. - (void)addTimer {
  154. CGFloat scanninglineX = 0;
  155. CGFloat scanninglineY = 0;
  156. CGFloat scanninglineW = 0;
  157. CGFloat scanninglineH = 0;
  158. if (self.scanAnimationStyle == ScanAnimationStyleGrid) {
  159. [self addSubview:self.contentView];
  160. [_contentView addSubview:self.scanningline];
  161. scanninglineW = scanBorderW;
  162. scanninglineH = scanBorderW;
  163. scanninglineX = 0;
  164. scanninglineY = - scanBorderW;
  165. _scanningline.frame = CGRectMake(scanninglineX, scanninglineY, scanninglineW, scanninglineH);
  166. } else {
  167. [self addSubview:self.scanningline];
  168. scanninglineW = scanBorderW;
  169. scanninglineH = 12;
  170. scanninglineX = scanBorderX;
  171. scanninglineY = scanBorderY;
  172. _scanningline.frame = CGRectMake(scanninglineX, scanninglineY, scanninglineW, scanninglineH);
  173. }
  174. self.timer = [NSTimer timerWithTimeInterval:self.animationTimeInterval target:self selector:@selector(beginRefreshUI) userInfo:nil repeats:YES];
  175. [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
  176. }
  177. #pragma mark - - - 移除定时器
  178. - (void)removeTimer {
  179. [self.timer invalidate];
  180. self.timer = nil;
  181. [_scanningline removeFromSuperview];
  182. _scanningline = nil;
  183. }
  184. #pragma mark - - - 执行定时器方法
  185. - (void)beginRefreshUI {
  186. __block CGRect frame = _scanningline.frame;
  187. static BOOL flag = YES;
  188. __weak typeof(self) weakSelf = self;
  189. if (self.scanAnimationStyle == ScanAnimationStyleGrid) {
  190. if (flag) {
  191. frame.origin.y = - scanBorderW;
  192. flag = NO;
  193. [UIView animateWithDuration:self.animationTimeInterval animations:^{
  194. frame.origin.y += 2;
  195. weakSelf.scanningline.frame = frame;
  196. } completion:nil];
  197. } else {
  198. if (_scanningline.frame.origin.y >= - scanBorderW) {
  199. CGFloat scanContent_MaxY = - scanBorderW + self.frame.size.width - 2 * scanBorderX;
  200. if (_scanningline.frame.origin.y >= scanContent_MaxY) {
  201. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  202. frame.origin.y = - scanBorderW;
  203. weakSelf.scanningline.frame = frame;
  204. flag = YES;
  205. });
  206. } else {
  207. [UIView animateWithDuration:self.animationTimeInterval animations:^{
  208. frame.origin.y += 2;
  209. weakSelf.scanningline.frame = frame;
  210. } completion:nil];
  211. }
  212. } else {
  213. flag = !flag;
  214. }
  215. }
  216. } else {
  217. if (flag) {
  218. frame.origin.y = scanBorderY;
  219. flag = NO;
  220. [UIView animateWithDuration:self.animationTimeInterval animations:^{
  221. frame.origin.y += 2;
  222. weakSelf.scanningline.frame = frame;
  223. } completion:nil];
  224. } else {
  225. if (_scanningline.frame.origin.y >= scanBorderY) {
  226. CGFloat scanContent_MaxY = scanBorderY + self.frame.size.width - 2 * scanBorderX;
  227. if (_scanningline.frame.origin.y >= scanContent_MaxY - 10) {
  228. frame.origin.y = scanBorderY;
  229. weakSelf.scanningline.frame = frame;
  230. flag = YES;
  231. } else {
  232. [UIView animateWithDuration:self.animationTimeInterval animations:^{
  233. frame.origin.y += 2;
  234. weakSelf.scanningline.frame = frame;
  235. } completion:nil];
  236. }
  237. } else {
  238. flag = !flag;
  239. }
  240. }
  241. }
  242. }
  243. - (UIImageView *)scanningline {
  244. if (!_scanningline) {
  245. _scanningline = [[UIImageView alloc] init];
  246. /// 静态库 url 的获取
  247. NSURL *url = [[NSBundle mainBundle] URLForResource:@"SGQRCode" withExtension:@"bundle"];
  248. if (!url) {
  249. /// 动态库 url 的获取
  250. url = [[NSBundle bundleForClass:[self class]] URLForResource:@"SGQRCode" withExtension:@"bundle"];
  251. }
  252. NSBundle *bundle = [NSBundle bundleWithURL:url];
  253. UIImage *image = [UIImage imageNamed:self.scanImageName inBundle:bundle compatibleWithTraitCollection:nil];
  254. if (!image) {
  255. image = [UIImage imageNamed:self.scanImageName];
  256. }
  257. _scanningline.image = image;
  258. }
  259. return _scanningline;
  260. }
  261. #pragma mark - - - set
  262. - (void)setScanAnimationStyle:(ScanAnimationStyle)scanAnimationStyle {
  263. _scanAnimationStyle = scanAnimationStyle;
  264. }
  265. - (void)setScanImageName:(NSString *)scanImageName {
  266. _scanImageName = scanImageName;
  267. }
  268. - (void)setBorderColor:(UIColor *)borderColor {
  269. _borderColor = borderColor;
  270. }
  271. - (void)setCornerLocation:(CornerLoaction)cornerLocation {
  272. _cornerLocation = cornerLocation;
  273. }
  274. - (void)setCornerColor:(UIColor *)cornerColor {
  275. _cornerColor = cornerColor;
  276. }
  277. - (void)setCornerWidth:(CGFloat)cornerWidth {
  278. _cornerWidth = cornerWidth;
  279. }
  280. - (void)setBackgroundAlpha:(CGFloat)backgroundAlpha {
  281. _backgroundAlpha = backgroundAlpha;
  282. }
  283. - (void)setAnimationTimeInterval:(NSTimeInterval)animationTimeInterval {
  284. _animationTimeInterval = animationTimeInterval;
  285. }
  286. @end