VideoTextFiled.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. //
  2. // VideoTextFiled.m
  3. // DeviceManageIOSApp
  4. //
  5. // Created by rushanting on 2017/5/22.
  6. // Copyright © 2017年 tencent. All rights reserved.
  7. //
  8. #import "VideoTextFiled.h"
  9. #import "UIView+Additions.h"
  10. #import "ColorMacro.h"
  11. @interface VideoTextFiled () <UITextViewDelegate, UITextFieldDelegate>
  12. {
  13. UILabel* _textLabel; //文字输入Label
  14. UIImageView* _borderView; //用来显示边框或样式背景
  15. UIButton* _deleteBtn; //删除铵钮
  16. UIButton* _styleBtn; //样式操作按钮,目前只改字体颜色
  17. UIButton* _scaleRotateBtn; //单手操作放大,旋转按钮
  18. //自字义键盘上的输入显示
  19. UITextView* _inputTextView;
  20. UIButton* _inputConfirmBtn;
  21. //用来作输助呼出键盘
  22. UITextField* _hiddenTextField;
  23. BOOL _isInputting;
  24. //气泡背景
  25. UIImageView * _bubbleView;
  26. //己旋转角度
  27. CGFloat _rotateAngle;
  28. NSInteger _styleIndex;
  29. CGRect _textNormalizationFrame;
  30. CGRect _initFrame;
  31. BOOL _hasSetBubble;
  32. }
  33. @end
  34. @implementation VideoTextFiled
  35. - (id)initWithFrame:(CGRect)frame
  36. {
  37. if (self = [super initWithFrame:frame]) {
  38. _styleIndex = 0;
  39. _hasSetBubble = NO;
  40. _textNormalizationFrame = CGRectMake(0, 0, 1, 1);
  41. _initFrame = frame;
  42. _borderView = [UIImageView new];
  43. _borderView.layer.borderWidth = 1;
  44. _borderView.layer.borderColor = UIColorFromRGB(0x0accac).CGColor;
  45. _borderView.userInteractionEnabled = YES;
  46. _borderView.backgroundColor = [UIColor clearColor];
  47. [self addSubview:_borderView];
  48. _bubbleView = [UIImageView new];
  49. [_borderView addSubview:_bubbleView];
  50. _textLabel = [UILabel new];
  51. _textLabel.text = NSLocalizedString(@"VideoTextFiled.ClickEditText", nil);
  52. _textLabel.textColor = UIColor.blackColor;
  53. _textLabel.shadowOffset = CGSizeMake(2, 2);
  54. _textLabel.font = [UIFont systemFontOfSize:18];
  55. _textLabel.numberOfLines = 0;
  56. _textLabel.textAlignment = NSTextAlignmentCenter;
  57. UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)];
  58. singleTap.numberOfTapsRequired = 1;
  59. _textLabel.userInteractionEnabled = YES;
  60. [_textLabel sizeToFit];
  61. [_textLabel addGestureRecognizer:singleTap];
  62. [_borderView addSubview:_textLabel];
  63. _deleteBtn = [UIButton new];
  64. [_deleteBtn setImage:[UIImage imageNamed:@"videotext_delete"] forState:UIControlStateNormal];
  65. [_deleteBtn addTarget:self action:@selector(onDeleteBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
  66. [self addSubview:_deleteBtn];
  67. _styleBtn = [UIButton new];
  68. [_styleBtn setImage:[UIImage imageNamed:@"videotext_style"] forState:UIControlStateNormal];
  69. [_styleBtn addTarget:self action:@selector(onStyleBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
  70. [self addSubview:_styleBtn];
  71. _scaleRotateBtn = [UIButton new];
  72. [_scaleRotateBtn setImage:[UIImage imageNamed:@"videotext_rotate"] forState:UIControlStateNormal];
  73. UIPanGestureRecognizer* panGensture = [[UIPanGestureRecognizer alloc] initWithTarget:self action: @selector (handlePanSlide:)];
  74. [self addSubview:_scaleRotateBtn];
  75. [_scaleRotateBtn addGestureRecognizer:panGensture];
  76. UIView* inputAccessoryView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 40)];
  77. UIView* labelBgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, inputAccessoryView.width - 40, inputAccessoryView.height)];
  78. labelBgView.backgroundColor = UIColor.whiteColor;
  79. labelBgView.alpha = 0.5;
  80. [inputAccessoryView addSubview:labelBgView];
  81. _inputTextView = [[UITextView alloc] initWithFrame:CGRectMake(10, 0, inputAccessoryView.width - 50, inputAccessoryView.height)];
  82. _inputTextView.textColor = UIColorFromRGB(0xFFFFFF);
  83. _inputTextView.font = [UIFont systemFontOfSize:18];
  84. _inputTextView.textAlignment = NSTextAlignmentLeft;
  85. _inputTextView.delegate = self;
  86. _inputTextView.editable = YES;
  87. _inputTextView.backgroundColor = UIColor.clearColor;
  88. [inputAccessoryView addSubview:_inputTextView];
  89. _inputConfirmBtn = [[UIButton alloc] initWithFrame:CGRectMake(_inputTextView.right, 0, 40, inputAccessoryView.height)];
  90. _inputConfirmBtn.backgroundColor = UIColorFromRGB(0x0accac);
  91. [_inputConfirmBtn setImage:[UIImage imageNamed:@"videotext_confirm"] forState:UIControlStateNormal];
  92. [_inputConfirmBtn addTarget:self action:@selector(onInputConfirmBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
  93. [inputAccessoryView addSubview:_inputConfirmBtn];
  94. _hiddenTextField = [[UITextField alloc] initWithFrame:CGRectZero];
  95. _hiddenTextField.inputAccessoryView = inputAccessoryView;
  96. [self addSubview:_hiddenTextField];
  97. UIPanGestureRecognizer* selfPanGensture = [[UIPanGestureRecognizer alloc] initWithTarget:self action: @selector (handlePanSlide:)];
  98. [self addGestureRecognizer:selfPanGensture];
  99. UIPinchGestureRecognizer* pinchGensture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
  100. [self addGestureRecognizer:pinchGensture];
  101. UIRotationGestureRecognizer* rotateGensture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotate:)];
  102. [self addGestureRecognizer:rotateGensture];
  103. [[NSNotificationCenter defaultCenter] addObserver:self
  104. selector:@selector(changeFirstResponder)
  105. name:UIKeyboardDidShowNotification
  106. object:nil];
  107. [[NSNotificationCenter defaultCenter] addObserver:self
  108. selector:@selector(textViewBeginChangeValue)
  109. name:UITextViewTextDidBeginEditingNotification
  110. object:_inputTextView];
  111. [[NSNotificationCenter defaultCenter] addObserver:self
  112. selector:@selector(textViewDidChangeValue:)
  113. name:UITextViewTextDidChangeNotification
  114. object:_inputTextView];
  115. _rotateAngle = 0.f;
  116. }
  117. return self;
  118. }
  119. - (void)layoutSubviews
  120. {
  121. [super layoutSubviews];
  122. CGPoint center = [self convertPoint:self.center fromView:self.superview];
  123. _borderView.bounds = CGRectMake(0, 0, self.bounds.size.width - 25, self.bounds.size.height - 25);
  124. _borderView.center = center;
  125. _bubbleView.frame = CGRectMake(0, 0, _borderView.bounds.size.width, _borderView.bounds.size.height);
  126. _textLabel.center = CGPointMake(_bubbleView.bounds.size.width * (_textNormalizationFrame.origin.x + _textNormalizationFrame.size.width / 2), _bubbleView.bounds.size.height * (_textNormalizationFrame.origin.y + _textNormalizationFrame.size.height / 2));
  127. _textLabel.bounds = CGRectMake(0, 0, _bubbleView.bounds.size.width * _textNormalizationFrame.size.width, _bubbleView.bounds.size.height * _textNormalizationFrame.size.height);
  128. _deleteBtn.center = CGPointMake(_borderView.x, _borderView.y);
  129. _deleteBtn.bounds = CGRectMake(0, 0, 50, 50);
  130. _styleBtn.center = CGPointMake(_borderView.right, _borderView.top);
  131. _styleBtn.bounds = CGRectMake(0, 0, 50, 50);
  132. _scaleRotateBtn.center = CGPointMake(_borderView.right, _borderView.bottom);
  133. _scaleRotateBtn.bounds = CGRectMake(0, 0, 50, 50);
  134. if (_hasSetBubble) {
  135. [self calculateTextLabelFont];
  136. }
  137. }
  138. - (void)calculateTextLabelFont
  139. {
  140. CGRect rect = [_textLabel.text boundingRectWithSize:CGSizeMake(_textLabel.width, MAXFLOAT) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName:_textLabel.font} context:nil];
  141. if (rect.size.height > _textLabel.height) {
  142. _textLabel.font = [UIFont systemFontOfSize:_textLabel.font.pointSize - 0.1];
  143. [self calculateTextLabelFont];
  144. }
  145. }
  146. - (NSString*)text
  147. {
  148. return _textLabel.text;
  149. }
  150. //生成字幕图片
  151. - (UIImage*)textImage
  152. {
  153. _borderView.layer.borderWidth = 0;
  154. [_borderView setNeedsDisplay];
  155. CGRect rect = _borderView.bounds;
  156. UIView *rotatedViewBox = [[UIView alloc]initWithFrame:CGRectMake(0, 0, rect.size.width , rect.size.height)];
  157. CGAffineTransform t = CGAffineTransformMakeRotation(_rotateAngle);
  158. rotatedViewBox.transform = t;
  159. CGSize rotatedSize = rotatedViewBox.frame.size;
  160. UIGraphicsBeginImageContextWithOptions(rotatedSize, NO, 0.f);
  161. CGContextRef context = UIGraphicsGetCurrentContext();
  162. CGContextTranslateCTM(context, rotatedSize.width/2, rotatedSize.height/2);
  163. CGContextRotateCTM(context, _rotateAngle);
  164. //[_textLabel drawTextInRect:CGRectMake(-rect.size.width / 2, -rect.size.height / 2, rect.size.width, rect.size.height)];
  165. [_borderView drawViewHierarchyInRect:CGRectMake(-rect.size.width / 2, -rect.size.height / 2, rect.size.width, rect.size.height) afterScreenUpdates:YES];
  166. UIImage *rotatedImg = UIGraphicsGetImageFromCurrentImageContext();
  167. UIGraphicsEndImageContext();
  168. _borderView.layer.borderWidth = 1;
  169. _borderView.layer.borderColor = UIColorFromRGB(0x0accac).CGColor;
  170. return rotatedImg;
  171. }
  172. //设置气泡
  173. - (void)setTextBubbleImage:(UIImage *)image textNormalizationFrame:(CGRect)frame
  174. {
  175. _bubbleView.image = image;
  176. if (image != nil) {
  177. _textNormalizationFrame = frame;
  178. [self calculateTextLabelFont];
  179. _hasSetBubble = YES;
  180. }else{
  181. _hasSetBubble = NO;
  182. }
  183. self.transform = CGAffineTransformRotate(self.transform, -_rotateAngle);
  184. _rotateAngle = 0;
  185. }
  186. //字幕图在视频预览view的frame
  187. - (CGRect)textFrameOnView:(UIView *)view
  188. {
  189. CGRect frame = CGRectMake(_borderView.x, _borderView.y, _borderView.bounds.size.width, _borderView.bounds.size.height);
  190. if (![view.subviews containsObject:self]) {
  191. [view addSubview:self];
  192. CGRect rc = [self convertRect:frame toView:view];
  193. [self removeFromSuperview];
  194. return rc;
  195. }
  196. return [self convertRect:frame toView:view];
  197. }
  198. - (CGRect)textRect
  199. {
  200. CGRect rect = [_textLabel.text boundingRectWithSize:CGSizeMake(MAXFLOAT, 0) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName:_textLabel.font} context:nil];
  201. //限制最小的文字框大小
  202. if (rect.size.width < 30) {
  203. rect.size.width = 30;
  204. } else if (rect.size.height < 10) {
  205. rect.size.height = 10;
  206. }
  207. return rect;
  208. }
  209. - (void)resignFirstResponser
  210. {
  211. if (!_isInputting)
  212. return;
  213. _isInputting = NO;
  214. [_inputTextView resignFirstResponder];
  215. }
  216. - (void)changeFirstResponder
  217. {
  218. if (_isInputting) {
  219. _inputTextView.text = _textLabel.text;
  220. [_inputTextView becomeFirstResponder];
  221. } else {
  222. if (_hiddenTextField.isFirstResponder) {
  223. [_hiddenTextField resignFirstResponder];
  224. } else {
  225. [self resignFirstResponder];
  226. [_hiddenTextField resignFirstResponder];
  227. }
  228. }
  229. }
  230. #pragma mark - GestureRecognizer handle
  231. - (void)onTap:(UITapGestureRecognizer*)recognizer
  232. {
  233. _isInputting = YES;
  234. [_hiddenTextField becomeFirstResponder];
  235. }
  236. - (void)handlePanSlide:(UIPanGestureRecognizer*)recognizer
  237. {
  238. //拖动
  239. if (recognizer.view == self) {
  240. CGPoint translation = [recognizer translationInView:self.superview];
  241. CGPoint center = CGPointMake(recognizer.view.center.x + translation.x,
  242. recognizer.view.center.y + translation.y);
  243. if (center.x < 0) {
  244. center.x = 0;
  245. }
  246. else if (center.x > self.superview.width) {
  247. center.x = self.superview.width;
  248. }
  249. if (center.y < 0) {
  250. center.y = 0;
  251. }
  252. else if (center.y > self.superview.height) {
  253. center.y = self.superview.height;
  254. }
  255. recognizer.view.center = center;
  256. [recognizer setTranslation:CGPointZero inView:self.superview];
  257. }
  258. else if (recognizer.view == _scaleRotateBtn) {
  259. CGPoint translation = [recognizer translationInView:self];
  260. if (recognizer.state == UIGestureRecognizerStateChanged) {
  261. //放大
  262. CGFloat delta = translation.x / 10;
  263. CGFloat newFontSize = MAX(10.0f, MIN(150.f, _textLabel.font.pointSize + delta));
  264. _textLabel.font = [UIFont systemFontOfSize:newFontSize];
  265. if (!_hasSetBubble) {
  266. _textLabel.bounds = [self textRect];
  267. self.bounds = CGRectMake(0, 0, _textLabel.bounds.size.width + 50, _textLabel.bounds.size.height + 40);
  268. }else{
  269. self.bounds = CGRectMake(0, 0, self.bounds.size.width + translation.x, self.bounds.size.height + translation.x);
  270. }
  271. //旋转
  272. CGPoint newCenter = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y);
  273. CGPoint anthorPoint = _textLabel.center;
  274. CGFloat height = newCenter.y - anthorPoint.y;
  275. CGFloat width = newCenter.x - anthorPoint.x;
  276. CGFloat angle1 = atan(height / width);
  277. height = recognizer.view.center.y - anthorPoint.y;
  278. width = recognizer.view.center.x - anthorPoint.x;
  279. CGFloat angle2 = atan(height / width);
  280. CGFloat angle = angle1 - angle2;
  281. self.transform = CGAffineTransformRotate(self.transform, angle);
  282. _rotateAngle += angle;
  283. }
  284. [recognizer setTranslation:CGPointZero inView:self];
  285. }
  286. }
  287. //双手指放大
  288. - (void)handlePinch:(UIPinchGestureRecognizer*)recognizer
  289. {
  290. CGFloat newFontSize = MAX(10.0f, MIN(150.f, _textLabel.font.pointSize * recognizer.scale));
  291. // set font size
  292. _textLabel.font = [_textLabel.font fontWithSize:newFontSize];
  293. if (!_hasSetBubble) {
  294. CGRect rect = [self textRect];
  295. rect = [_textLabel convertRect:rect toView:self];
  296. _textLabel.bounds = CGRectMake(0, 0, rect.size.width, rect.size.height);
  297. self.bounds = CGRectMake(0, 0, _textLabel.bounds.size.width + 50, _textLabel.bounds.size.height + 40);
  298. }else{
  299. self.bounds = CGRectMake(0, 0, self.bounds.size.width * recognizer.scale, self.bounds.size.height * recognizer.scale);
  300. }
  301. recognizer.scale = 1;
  302. }
  303. //双手指旋转
  304. - (void)handleRotate:(UIRotationGestureRecognizer*)recognizer
  305. {
  306. recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);
  307. _rotateAngle += recognizer.rotation;
  308. recognizer.rotation = 0;
  309. }
  310. #pragma mark - UI event handle
  311. - (void)onInputConfirmBtnClicked:(UIButton*)sender
  312. {
  313. _isInputting = NO;
  314. [_inputTextView resignFirstResponder];
  315. [_hiddenTextField resignFirstResponder];
  316. _textLabel.text = _inputTextView.text;
  317. if (!_hasSetBubble) {
  318. _textLabel.bounds = [self textRect];
  319. self.bounds = CGRectMake(0, 0, _textLabel.bounds.size.width + 50, _textLabel.bounds.size.height + 40);
  320. }else{
  321. [self calculateTextLabelFont];
  322. }
  323. [self.delegate onTextInputDone:_textLabel.text];
  324. }
  325. -(void)textViewBeginChangeValue{
  326. [self.delegate onTextInputBegin];;
  327. }
  328. -(void)textViewDidChangeValue:(NSNotification *)obj{
  329. UITextView *textView = (UITextView *)obj.object;
  330. NSString *string = textView.text;
  331. if(string.length > 0){
  332. [_inputConfirmBtn setEnabled:YES];
  333. }else{
  334. [_inputConfirmBtn setEnabled:NO];
  335. }
  336. }
  337. - (void)onDeleteBtnClicked:(UIButton*)sender
  338. {
  339. [self.delegate onRemoveTextField:self];
  340. [self removeFromSuperview];
  341. }
  342. - (void)onStyleBtnClicked:(UIButton*)sender
  343. {
  344. [self.delegate onBubbleTap];
  345. }
  346. - (void)dealloc
  347. {
  348. [[NSNotificationCenter defaultCenter] removeObserver:self];
  349. }
  350. @end