UGCKitVideoTextFiled.m 16 KB

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