PanoramaGuideView.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. //
  2. // PanoramaGuideView.m
  3. // LenzCameraNativeModuleForRN
  4. //
  5. // Created by 王昭威 on 2023/1/25.
  6. //
  7. #import "PanoramaGuideView.h"
  8. #import <YYText/NSAttributedString+YYText.h>
  9. #import <AVFoundation/AVFoundation.h>
  10. #import <YYText/YYLabel.h>
  11. #import <MetalKit/MetalKit.h>
  12. #import "Renderer.h"
  13. #import "LenzHeader.h"
  14. CGFloat const PanoramaGuideViewWOrH = 120;
  15. @interface PanoramaGuideViewPreviewContainer : MTKView
  16. @end
  17. @implementation PanoramaGuideViewPreviewContainer
  18. @end
  19. @interface PanoramaGuideView() <MTKViewDelegate>
  20. @property (nonatomic, strong) PanoramaGuideViewPreviewContainer* container;
  21. @property (nonatomic, assign) CGFloat aspect;
  22. @property (nonatomic, assign) CGFloat offset;
  23. @property (nonatomic, strong) NSTimer* timer;
  24. @property (nonatomic, strong) UIImageView *whiteArrow;
  25. @property (nonatomic, strong) UIView* line;
  26. @property (nonatomic, weak) UIView* superV;
  27. @property (nonatomic, strong)YYLabel *label;
  28. @property (nonatomic) UIImageView *showImageView;
  29. @property (nonatomic) PanoramaArrowDir lastArrowDir;
  30. @property (nonatomic) NSNumber *offSetTop;
  31. @property (nonatomic) NSNumber *offSetLeft;
  32. @end
  33. @implementation PanoramaGuideView
  34. - (instancetype)init{
  35. self = [super init];
  36. self.backgroundColor = [UIColor jk_colorWithHexString:@"#000000" andAlpha:0.5];
  37. [self addSubview:self.showImageView];
  38. self.offSetTop = @((120-38)/2);
  39. self.offSetLeft = @((120-38)/2);
  40. return self;
  41. }
  42. - (void)willMoveToSuperview:(nullable UIView *)newSuperview;{
  43. [super willMoveToSuperview:newSuperview];
  44. self.superV = newSuperview;
  45. }
  46. - (void)updatePreviewAspect:(CGFloat)aspect{
  47. if(aspect > 0.01){
  48. self.aspect = 1.0 / aspect;
  49. }
  50. else{
  51. self.aspect = 1;
  52. }
  53. [self.container mas_remakeConstraints:^(MASConstraintMaker *make) {
  54. make.left.top.equalTo(self).offset(self.offset);
  55. make.height.equalTo(self);
  56. // it means aspect > 0
  57. make.width.equalTo(self.container.mas_height).multipliedBy(self.aspect);
  58. }];
  59. }
  60. - (void)updateOffset:(CGFloat)offset{
  61. self.offset = offset;
  62. [self.container mas_remakeConstraints:^(MASConstraintMaker *make) {
  63. make.left.equalTo(self).offset(self.offset);
  64. make.top.equalTo(self);
  65. make.height.equalTo(self);
  66. make.width.equalTo(self.container.mas_height).multipliedBy(self.aspect);
  67. }];
  68. }
  69. - (void)direction:(PanoramaOrientationViewDirectionEnum)dir{
  70. [self insertSubview:self.line atIndex:0];
  71. self.line.hidden = YES;
  72. [self.superV addSubview:self.label];
  73. [self addSubview:self.whiteArrow];
  74. [self.line mas_remakeConstraints:^(MASConstraintMaker *make) {
  75. switch (dir) {
  76. case PanoramaOrientationViewLeft:
  77. case PanoramaOrientationViewRight:
  78. {
  79. make.left.right.offset(0);
  80. make.height.offset(0.5);
  81. make.centerY.mas_equalTo(self);
  82. }
  83. break;
  84. case PanoramaOrientationViewUp:
  85. case PanoramaOrientationViewDown:
  86. {
  87. make.top.bottom.offset(0);
  88. make.width.offset(0.5);
  89. make.centerX.mas_equalTo(self);
  90. }
  91. break;
  92. default:
  93. break;
  94. }
  95. }];
  96. [self.label mas_remakeConstraints:^(MASConstraintMaker *make) {
  97. switch (dir) {
  98. case PanoramaOrientationViewLeft:
  99. case PanoramaOrientationViewRight: // 横
  100. {
  101. make.top.mas_equalTo(self.mas_bottom).offset(5);
  102. make.centerX.mas_equalTo(self.superV);
  103. make.height.offset(20);
  104. make.width.offset(160);
  105. self.label.verticalForm = NO;
  106. }
  107. break;
  108. case PanoramaOrientationViewUp:
  109. case PanoramaOrientationViewDown: // 上下
  110. {
  111. make.right.mas_equalTo(self.mas_left).offset(-5);
  112. make.centerY.mas_equalTo(self.superV);
  113. make.width.offset(20);
  114. make.height.offset(160);
  115. self.label.verticalForm = YES;
  116. }
  117. break;
  118. default:
  119. break;
  120. }
  121. }];
  122. [self.showImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
  123. switch (dir) {
  124. case PanoramaOrientationViewUp: {
  125. make.left.right.top.mas_equalTo(0);
  126. make.height.mas_equalTo(0);
  127. make.height.mas_lessThanOrEqualTo(self);
  128. }
  129. break;
  130. case PanoramaOrientationViewDown: {
  131. make.left.right.bottom.mas_equalTo(0);
  132. make.height.mas_equalTo(0);
  133. }
  134. break;
  135. case PanoramaOrientationViewLeft: {
  136. make.left.top.bottom.mas_equalTo(0);
  137. make.width.mas_equalTo(0);
  138. make.width.mas_lessThanOrEqualTo(self);
  139. }
  140. break;
  141. case PanoramaOrientationViewRight: {
  142. make.top.right.bottom.mas_equalTo(0);
  143. make.width.mas_equalTo(0);
  144. make.width.mas_lessThanOrEqualTo(self);
  145. }
  146. break;
  147. default:
  148. break;
  149. }
  150. }];
  151. [UIView animateWithDuration:0.2 animations:^{
  152. __block UIImage *arrow = nil;
  153. /// 白色的箭头
  154. [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  155. switch (dir) {
  156. case PanoramaOrientationViewLeft: //左
  157. {
  158. make.centerY.mas_equalTo(self);
  159. make.left.offset(0);
  160. arrow = [UIImage loadNamed:@"ai_right_arrow"];
  161. }
  162. break;
  163. case PanoramaOrientationViewRight: // 右
  164. {
  165. make.centerY.mas_equalTo(self);
  166. make.right.offset(0);
  167. arrow = [UIImage loadNamed:@"ai_left_arrow"];
  168. }
  169. break;
  170. case PanoramaOrientationViewUp: //上
  171. {
  172. make.centerX.mas_equalTo(self);
  173. make.top.offset(0);
  174. arrow = [UIImage loadNamed:@"ai_down_arrow"];
  175. }
  176. break;
  177. case PanoramaOrientationViewDown: // 下
  178. {
  179. make.centerX.mas_equalTo(self);
  180. make.bottom.offset(0);
  181. arrow = [UIImage loadNamed:@"ai_up_arrow"];
  182. }
  183. break;
  184. default:
  185. break;
  186. }
  187. }];
  188. self.whiteArrow.image = arrow;
  189. [self setNeedsLayout];
  190. [self layoutIfNeeded];
  191. } completion:^(BOOL finished) {
  192. self.line.hidden = NO;
  193. }];
  194. }
  195. - (void)showImageWith:(UIImage * _Nullable)image dir:(PanoramaOrientationViewDirectionEnum)dir {
  196. // if (!image) {
  197. // dispatch_async(dispatch_get_main_queue(), ^{
  198. // self.showImageView.image = nil;
  199. // });
  200. // return;
  201. // }
  202. dispatch_async(dispatch_get_main_queue(), ^{
  203. CGFloat imageWH = 0;
  204. if (image) {
  205. if (dir == PanoramaOrientationViewDown || dir == PanoramaOrientationViewUp) {
  206. imageWH = (PanoramaGuideViewWOrH * image.size.height)/image.size.width;
  207. } else {
  208. imageWH = (PanoramaGuideViewWOrH * image.size.width)/image.size.height;
  209. }
  210. } else {
  211. self.offSetTop = @((120-38)/2);
  212. self.offSetLeft = @((120-38)/2);
  213. }
  214. // UIImage *resultImage = [self showDir:dir image:image];
  215. self.showImageView.image = image;
  216. [UIView animateWithDuration:.15 animations:^{
  217. switch (dir) {
  218. case PanoramaOrientationViewDown: {
  219. [self.showImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
  220. make.height.mas_equalTo(imageWH);
  221. make.height.mas_lessThanOrEqualTo(self);
  222. make.left.right.bottom.mas_equalTo(0);
  223. }];
  224. [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  225. make.bottom.offset(-imageWH);
  226. make.left.mas_equalTo(self.offSetLeft.doubleValue);
  227. // make.centerX.mas_equalTo(self);
  228. }];
  229. }
  230. break;
  231. case PanoramaOrientationViewUp:{
  232. [self.showImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
  233. make.left.right.top.mas_equalTo(0);
  234. make.height.mas_equalTo(imageWH);
  235. make.height.mas_lessThanOrEqualTo(self);
  236. }];
  237. [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  238. make.top.offset(imageWH);
  239. // make.centerX.mas_equalTo(self);
  240. make.left.mas_equalTo(self.offSetLeft.doubleValue);
  241. }];
  242. }
  243. break;
  244. case PanoramaOrientationViewRight: {
  245. [self.showImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
  246. make.width.mas_equalTo(imageWH);
  247. make.width.mas_lessThanOrEqualTo(self);
  248. make.top.right.bottom.mas_equalTo(0);
  249. }];
  250. [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  251. make.right.offset(-imageWH);
  252. // make.centerY.mas_equalTo(self);
  253. make.top.mas_equalTo(self.offSetTop.doubleValue);
  254. }];
  255. }
  256. break;
  257. case PanoramaOrientationViewLeft:{
  258. [self.showImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
  259. make.width.mas_equalTo(imageWH);
  260. make.width.mas_lessThanOrEqualTo(self);
  261. make.left.top.bottom.mas_equalTo(0);
  262. }];
  263. [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  264. make.left.offset(imageWH);
  265. // make.centerY.mas_equalTo(self);
  266. make.top.mas_equalTo(self.offSetTop.doubleValue);
  267. }];
  268. }
  269. break;
  270. default:
  271. break;
  272. }
  273. [self setNeedsLayout];
  274. [self layoutIfNeeded];
  275. }];
  276. });
  277. }
  278. - (void)updateArrowWith:(PanoramaArrowDir)arrowDir dir:(PanoramaOrientationViewDirectionEnum)dir {
  279. // self.lastArrowDir = arrowDir;
  280. dispatch_async(dispatch_get_main_queue(), ^{
  281. if (!self.showImageView.image) {
  282. return;
  283. }
  284. CGFloat imageWidth = self.showImageView.image.size.width;
  285. CGFloat imageHight = self.showImageView.image.size.height;
  286. if (dir == PanoramaOrientationViewDown || dir == PanoramaOrientationViewUp) {
  287. if (arrowDir == PanoramaArrowDirCenter) {
  288. self.offSetLeft = @((120-38)/2);
  289. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  290. // make.bottom.offset(-(PanoramaGuideViewWOrH * imageWidth)/imageHight);
  291. //// make.centerX.mas_equalTo(self);
  292. // make.left.mas_offset(self.offSetLeft.doubleValue);
  293. // }];
  294. } else if (arrowDir == PanoramaArrowDirLeft) {
  295. self.offSetLeft = @(0);
  296. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  297. // make.bottom.offset(-(PanoramaGuideViewWOrH * imageWidth)/imageHight);
  298. //// make.left.mas_equalTo(self).mas_offset(10);
  299. // make.left.mas_offset(self.offSetLeft.doubleValue);
  300. //
  301. // }];
  302. } else if (arrowDir == PanoramaArrowDirRight) {
  303. self.offSetLeft = @(120-38);
  304. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  305. // make.bottom.offset(-(PanoramaGuideViewWOrH * imageWidth)/imageHight);
  306. //// make.right.mas_equalTo(self).mas_offset(-10);
  307. // make.left.mas_offset(self.offSetLeft.doubleValue);
  308. //
  309. // }];
  310. }
  311. }
  312. // else if (dir == PanoramaOrientationViewUp) {
  313. // if (arrowDir == PanoramaArrowDirCenter) {
  314. // self.offSetTop = @((120-38)/2);
  315. //
  316. //// [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  317. //// make.top.offset((PanoramaGuideViewWOrH * imageWidth)/imageHight);
  318. ////// make.centerX.mas_equalTo(self);
  319. //// make.top.mas_offset(self.offSetTop.doubleValue);
  320. //// }];
  321. // } else if (arrowDir == PanoramaArrowDirLeft) {
  322. // self.offSetTop = @((120-38)/2);
  323. //
  324. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  325. // make.top.offset((PanoramaGuideViewWOrH * imageWidth)/imageHight);
  326. // make.left.mas_equalTo(self).mas_offset(10);
  327. // }];
  328. // } else if (arrowDir == PanoramaArrowDirRight) {
  329. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  330. // make.top.offset((PanoramaGuideViewWOrH * imageWidth)/imageHight);
  331. // make.right.mas_equalTo(self).mas_offset(-10);
  332. // }];
  333. // }
  334. //
  335. // }
  336. else if (dir == PanoramaOrientationViewLeft || dir == PanoramaOrientationViewRight) {
  337. if (arrowDir == PanoramaArrowDirCenter) {
  338. self.offSetTop = @((120-38)/2);
  339. //
  340. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  341. // make.left.offset((PanoramaGuideViewWOrH * imageWidth)/imageHight);
  342. //// make.centerY.mas_equalTo(self);
  343. // make.top.mas_offset(self.offSetTop.doubleValue);
  344. //
  345. // }];
  346. } else if (arrowDir == PanoramaArrowDirUp) {
  347. self.offSetTop = @(0);
  348. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  349. // make.left.offset((PanoramaGuideViewWOrH * imageWidth)/imageHight);
  350. //// make.top.mas_equalTo(self).mas_offset(10);
  351. // make.top.mas_offset(self.offSetTop.doubleValue);
  352. //
  353. // }];
  354. } else if (arrowDir == PanoramaArrowDirDown) {
  355. self.offSetTop = @(120-38);
  356. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  357. // make.left.offset((PanoramaGuideViewWOrH * imageWidth)/imageHight);
  358. //// make.bottom.mas_equalTo(self).mas_offset(-10);
  359. // make.top.mas_offset(self.offSetTop.doubleValue);
  360. //
  361. // }];
  362. }
  363. }
  364. // else if (dir == PanoramaOrientationViewRight) {
  365. // if (arrowDir == PanoramaArrowDirCenter) {
  366. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  367. // make.left.offset((PanoramaGuideViewWOrH * imageWidth)/imageHight);
  368. // make.centerY.mas_equalTo(self);
  369. // }];
  370. // } else if (arrowDir == PanoramaArrowDirUp) {
  371. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  372. // make.left.offset((PanoramaGuideViewWOrH * imageWidth)/imageHight);
  373. // make.top.mas_equalTo(self).mas_offset(10);
  374. // }];
  375. // } else if (arrowDir == PanoramaArrowDirDown) {
  376. // [self.whiteArrow mas_remakeConstraints:^(MASConstraintMaker *make) {
  377. // make.right.offset(-(PanoramaGuideViewWOrH * imageWidth)/imageHight);
  378. // make.bottom.mas_equalTo(self).mas_offset(-10);
  379. // }];
  380. // }
  381. // }
  382. });
  383. }
  384. - (void)clearImage {
  385. dispatch_async(dispatch_get_main_queue(), ^{
  386. self.showImageView.image = nil;
  387. });
  388. }
  389. - (UIImage *)showDir:(PanoramaOrientationViewDirectionEnum)dir image:(UIImage *)image {
  390. switch (dir) {
  391. case PanoramaOrientationViewUp: {
  392. UIImage *flipImage = [UIImage imageWithCGImage:image.CGImage scale:image.scale orientation:UIImageOrientationRight];
  393. return flipImage;
  394. }
  395. break;
  396. case PanoramaOrientationViewDown: {
  397. UIImage *flipImage = [UIImage imageWithCGImage:image.CGImage scale:image.scale orientation:UIImageOrientationLeft];
  398. return flipImage;
  399. }
  400. break;
  401. case PanoramaOrientationViewLeft: {
  402. return image;
  403. }
  404. break;
  405. case PanoramaOrientationViewRight: {
  406. UIImage *flipImage = [UIImage imageWithCGImage:image.CGImage scale:image.scale orientation:UIImageOrientationUpMirrored];
  407. return flipImage;
  408. }
  409. break;
  410. default:
  411. break;
  412. }
  413. return nil;
  414. }
  415. - (void)setHidden:(BOOL)hidden{
  416. [super setHidden:hidden];
  417. self.label.hidden = hidden;
  418. }
  419. - (void)awakeFromNib{
  420. [super awakeFromNib];
  421. self.container = [[PanoramaGuideViewPreviewContainer alloc] initWithFrame:CGRectMake(0, 0, 50, 50) device:[Renderer shared].device];
  422. self.container.clearColor = MTLClearColorMake(0, 0, 0, 1);
  423. self.container.backgroundColor = [UIColor redColor];
  424. [self addSubview:self.container];
  425. self.container.delegate = self;
  426. self.container.sampleCount = 1;
  427. self.container.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
  428. [self.container mas_makeConstraints:^(MASConstraintMaker *make) {
  429. make.left.top.equalTo(self);
  430. make.height.equalTo(self);
  431. make.width.equalTo(@(50));
  432. }];
  433. [[Renderer shared] setup];
  434. }
  435. - (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size{
  436. [[Renderer shared] mtkView:view drawableSizeWillChange:size];
  437. }
  438. - (void)drawInMTKView:(MTKView *)view{
  439. [[Renderer shared] drawInMTKView:view];
  440. }
  441. - (YYLabel *)label{
  442. if (_label == nil) {
  443. NSAttributedString *att = [[NSAttributedString alloc]initWithString:@"请沿箭头方向匀速拍摄"];
  444. _label = [[YYLabel alloc]init];
  445. _label.numberOfLines = 0;
  446. _label.backgroundColor = [UIColor jk_colorWithHexString:@"000000" andAlpha:0.35];
  447. _label.attributedText = att;
  448. _label.textAlignment = NSTextAlignmentCenter;
  449. _label.layer.cornerRadius = 3;
  450. _label.layer.masksToBounds = YES;
  451. _label.textVerticalAlignment = YYTextVerticalAlignmentCenter; // 文字置顶显示
  452. _label.textColor = UIColor.whiteColor;
  453. }
  454. return _label;
  455. }
  456. - (UIImageView *)showImageView {
  457. if (!_showImageView) {
  458. _showImageView = [[UIImageView alloc]init];
  459. _showImageView.contentMode = UIViewContentModeScaleAspectFill;
  460. _showImageView.clipsToBounds = YES;
  461. }
  462. return _showImageView;
  463. }
  464. - (UIView *)line{
  465. if (_line == nil) {
  466. _line = [[UIView alloc]init];
  467. _line.backgroundColor = UIColor.yellowColor;
  468. }
  469. return _line;
  470. }
  471. - (UIImageView *)whiteArrow{
  472. if (_whiteArrow == nil) {
  473. _whiteArrow = [[UIImageView alloc]initWithImage:[UIImage loadNamed:@"ai_right_arrow"]];
  474. }
  475. return _whiteArrow;
  476. }
  477. /*
  478. // Only override drawRect: if you perform custom drawing.
  479. // An empty implementation adversely affects performance during animation.
  480. - (void)drawRect:(CGRect)rect {
  481. // Drawing code
  482. }
  483. */
  484. @end