// // RichTextEditViewController.m // RichTextEditDemo // // Created by aron on 2017/7/19. // Copyright © 2017年 aron. All rights reserved. // #import "RichTextEditViewController.h" #import #import #import "UtilMacro.h" #import "MMFileUploadUtil.h" #import "MMRichContentUtil.h" #import "MMRichTextConfig.h" #import "MMDraftUtil.h" #import "MMRichTitleModel.h" #import "MMRichTextModel.h" #import "MMRichImageModel.h" #import "MMDraftModel.h" #import "MMRichTitleCell.h" #import "MMRichTextCell.h" #import "MMRichImageCell.h" #import "SmartBar.h" #import "LYLPhotoTailoringTool.h" #import "RichFileCell.h" #import "RichModel.h" #import "FWZGetNoteBookTool.h" #import "FWZFileGetTool.h" #define bottomOffsetHeight convertLength(49) #define BARHEIGHT 42.5f @interface RichTextEditViewController () { BOOL _isRefreshShow; } @property (nonatomic, strong) UITableView* tableView; @property (nonatomic, strong) UILabel *refreshTipLabel; @property (strong, nonatomic) SmartBar *SmartBar; @property (nonatomic, strong) UIView *editToolbar; @property (nonatomic, strong) MMRichTitleModel* titleModel; @property (nonatomic, strong) NSMutableArray* datas; @property (nonatomic, strong) NSIndexPath* activeIndexPath; @property (nonatomic, copy) NSString* tid;///<论坛ID @property (nonatomic, strong) MMDraftModel* draft; @property (nonatomic, assign) BOOL shouldShowAccessoryView; @property (nonatomic, assign) BOOL isOnUploading; @end @implementation RichTextEditViewController - (instancetype)initWithTid:(NSString*)tid { self = [super init]; if (self) { _tid = tid; } return self; } - (instancetype)initWithDraft:(MMDraftModel*)draft { self = [super init]; if (self) { _tid = draft.tid; _draft = draft; } return self; } - (SmartBar *)SmartBar { if (!_SmartBar) { _SmartBar = [[SmartBar alloc] init]; } return _SmartBar; } - (void)viewDidLoad { [super viewDidLoad]; self.title = @"编辑文章"; self.view.backgroundColor = [UIColor whiteColor]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(onUpload)]; UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; button.backgroundColor = [UIColor clearColor]; [button addTarget:self action:@selector(backButtonTapped) forControlEvents:UIControlEventTouchUpInside]; button.frame = CGRectMake(0, 0, 40, 40); [button setTitle:@"Back" forState:UIControlStateNormal]; self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button]; // register cell [self.tableView registerClass:MMRichTitleCell.class forCellReuseIdentifier:NSStringFromClass(MMRichTitleCell.class)]; [self.tableView registerClass:MMRichTextCell.class forCellReuseIdentifier:NSStringFromClass(MMRichTextCell.class)]; [self.tableView registerClass:MMRichImageCell.class forCellReuseIdentifier:NSStringFromClass(MMRichImageCell.class)]; [self.tableView registerClass:RichFileCell.class forCellReuseIdentifier:NSStringFromClass(RichFileCell.class)]; // Datas if (_draft) { if ((MMRichTitleModel*)_draft.titleModel) { _titleModel = (MMRichTitleModel*)_draft.titleModel; } else { _titleModel = [MMRichTitleModel new]; } _datas = [NSMutableArray array]; if (_draft.contentModels) { [_datas addObjectsFromArray:_draft.contentModels]; } else { [_datas addObject:[MMRichTextModel new]]; } } else { _titleModel = [MMRichTitleModel new]; _datas = [NSMutableArray array]; [_datas addObject:[MMRichTextModel new]]; } self.SmartBar.delegate = self; [self.view addSubview:self.SmartBar]; [self.SmartBar mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.mas_equalTo(self.view); make.height.mas_offset(BARHEIGHT); if (@available(iOS 11.0, *)) { make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(BARHEIGHT); } else { make.bottom.equalTo(self.view.mas_bottom).offset(BARHEIGHT); } }]; [self.view addSubview:self.tableView]; [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.top.right.mas_equalTo(self.view); make.bottom.mas_equalTo(self.SmartBar.mas_top); }]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } #pragma mark - KeyBoard - (void)keyBoardWillShow:(NSNotification *)note { // 获取用户信息 NSDictionary *userInfo = [NSDictionary dictionaryWithDictionary:note.userInfo]; // 获取键盘高度 CGRect keyBoardBounds = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGFloat keyBoardHeight = keyBoardBounds.size.height; // 获取键盘动画时间 CGFloat animationTime = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]; // 定义好动作 WS(weakSelf); [UIView animateWithDuration:animationTime animations:^{ [weakSelf.SmartBar mas_updateConstraints:^(MASConstraintMaker *make) { if (@available(iOS 11.0, *)) { make.bottom.equalTo(weakSelf.view.mas_safeAreaLayoutGuideBottom).offset(-keyBoardHeight); } else { make.bottom.equalTo(weakSelf.view.mas_bottom).offset(-keyBoardHeight); } }]; [weakSelf.view layoutIfNeeded]; } completion:^(BOOL finished) { }]; } - (void)keyBoardWillHide:(NSNotification *)note { // 获取用户信息 NSDictionary *userInfo = [NSDictionary dictionaryWithDictionary:note.userInfo]; // 获取键盘动画时间 CGFloat animationTime = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]; WS(weakSelf); [UIView animateWithDuration:animationTime animations:^{ [weakSelf.SmartBar mas_updateConstraints:^(MASConstraintMaker *make) { if (@available(iOS 11.0, *)) { make.bottom.equalTo(weakSelf.view.mas_safeAreaLayoutGuideBottom).offset(BARHEIGHT); } else { make.bottom.equalTo(weakSelf.view.mas_bottom).offset(BARHEIGHT); } }]; [weakSelf.view layoutIfNeeded]; } completion:^(BOOL finished) { }]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; /// 禁用返回手势 if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.enabled = NO; } } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // 开启返回手势 if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.enabled = YES; } } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; } - (UITableView *)tableView { if (!_tableView) { UITableView* tableView = [UITableView new]; tableView.delegate = self; tableView.dataSource = self; // tableView.estimatedRowHeight = 200; // tableView.rowHeight = UITableViewAutomaticDimension; tableView.separatorStyle = UITableViewCellSeparatorStyleNone; [tableView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTableViewTap)]]; tableView.contentInset = UIEdgeInsetsMake(0, 0, bottomOffsetHeight, 0); _tableView = tableView; } return _tableView; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; NSLog(@"===dealloc==="); } - (void)updateImages:(NSArray *)images { NSMutableArray *imageArr = [NSMutableArray array]; for (UIImage *image in images) { [imageArr addObject:UIImageJPEGRepresentation(image,1.0f)]; } WS(weakSelf); NSString *urlString = [[NSString alloc] initWithFormat:@"%@%@",BaseUrl,Modify_UserImages_Post]; [[HttpManager sharedHttpManager] HeaderUploadUrl:urlString parameters:@{} pictureArray:imageArr pictureKey:@"file" success:^(id _Nonnull responseObject) { NSArray * dataArray = responseObject; NSMutableArray * addArray = [NSMutableArray array]; for (NSInteger i = 0; i < dataArray.count; i ++) { NSDictionary * dict = dataArray[i]; MMRichImageModel * model = [[MMRichImageModel alloc] init]; model.remoteImageUrlString = dict[@"AbsolutePath"]; model.image = images[i]; [addArray addObject:model]; } [weakSelf handleInsertModelArray:addArray]; } failure:^(NSError * _Nonnull error) { SHOWERROR([ZYCTool handerResultData:error]); }]; } - (void)handleInsertModelArray:(NSArray *)array{ WS(weakSelf); __block NSBlockOperation *operation; __block NSBlockOperation *operation1; NSMutableArray * operArray = [NSMutableArray array]; for (NSInteger i = 0; i < array.count; i ++) { RichModel * model = array[i]; operation = [NSBlockOperation blockOperationWithBlock:^{ dispatch_semaphore_t sema = dispatch_semaphore_create(0); NSLog(@"上传成功================="); if (!weakSelf.activeIndexPath) { weakSelf.activeIndexPath = [NSIndexPath indexPathForRow:0 inSection:1]; } NSIndexPath* addIndexPath = [NSIndexPath indexPathForRow:weakSelf.activeIndexPath.row + 1 inSection:weakSelf.activeIndexPath.section]; NSIndexPath* nextIndexPath = [NSIndexPath indexPathForRow:weakSelf.activeIndexPath.row + 2 inSection:weakSelf.activeIndexPath.section]; if (weakSelf.activeIndexPath.row == (weakSelf.datas.count - 1)) { [weakSelf.datas addObject:model]; dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf.tableView reloadData]; [weakSelf addTextNodeAtIndexPath:nextIndexPath textContent:nil]; dispatch_semaphore_signal(sema); }); }else{ dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf.tableView beginUpdates]; [weakSelf.datas insertObject:model atIndex:addIndexPath.row]; [weakSelf.tableView insertRowsAtIndexPaths:@[addIndexPath] withRowAnimation:UITableViewRowAnimationNone]; [weakSelf.tableView endUpdates]; [weakSelf.tableView scrollToRowAtIndexPath:addIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO]; if (addIndexPath.row < weakSelf.datas.count - 1) { NSIndexPath* nextIndexPath = [NSIndexPath indexPathForRow:addIndexPath.row + 1 inSection:addIndexPath.section]; id nextData = weakSelf.datas[nextIndexPath.row]; if ([nextData isKindOfClass:[MMRichTextModel class]]) { // Image节点-后面:下面是text,光标移动到下面一行,并且在最前面添加一个换行,定位光标在最前面 [weakSelf.tableView scrollToRowAtIndexPath:nextIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; MMRichTextModel* textModel = ((MMRichTextModel*)nextData); textModel.selectedRange = NSMakeRange(0, 0); textModel.shouldUpdateSelectedRange = YES; [weakSelf positionAtIndex:nextIndexPath]; } else if ([nextData isKindOfClass:[MMRichImageModel class]]) { // 添加文字到下一行 [weakSelf addTextNodeAtIndexPath:nextIndexPath textContent:@""]; }else{ [weakSelf addTextNodeAtIndexPath:nextIndexPath textContent:@""]; } } else { // 添加文字到下一行 NSIndexPath* nextIndexPath = [NSIndexPath indexPathForRow:addIndexPath.row + 1 inSection:addIndexPath.section]; [weakSelf addTextNodeAtIndexPath:nextIndexPath textContent:@""]; [weakSelf positionAtIndex:nextIndexPath]; } dispatch_semaphore_signal(sema); }); } dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); }]; if (i > 0) { [operation addDependency:operation1]; //请求3依赖请求2 } [operArray addObject:operation]; operation1 = operation; } NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperations:operArray waitUntilFinished:NO]; } #pragma mark backbtntap - (void)backButtonTapped { // 保存草稿箱 if (_draft) { if ([MMRichContentUtil validateTitle:_titleModel] || [MMRichContentUtil validataContentNotEmptyWithRichContents:_datas]) { MMDraftModel* draftData = [MMDraftUtil draftModelWithTitleModel:_titleModel contents:_datas tid:_tid draftId:_draft.draftId]; [MMDraftUtil saveDraftData:draftData]; } else { // 删除草稿箱 [MMDraftUtil delateDraftData:_draft]; } } else { if ([MMRichContentUtil validateTitle:_titleModel] || [MMRichContentUtil validataContentNotEmptyWithRichContents:_datas]) { MMDraftModel* draftData = [MMDraftUtil draftModelWithTitleModel:_titleModel contents:_datas tid:_tid draftId:0]; [MMDraftUtil saveDraftData:draftData]; } } [self.navigationController popViewControllerAnimated:YES]; } #pragma mark - ......::::::: ui actoin :::::::...... - (void)onUpload { if (_isOnUploading) { return; } // 验证输入 // 1、验证内容 if (![MMRichContentUtil validataContentNotEmptyWithRichContents:_datas]) { UIAlertView* alert = [[UIAlertView alloc] initWithTitle:nil message:@"输入内容" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil, nil]; [alert show]; return; } // 2、验证title if (![MMRichContentUtil validateTitle:_titleModel]) { UIAlertView* alert = [[UIAlertView alloc] initWithTitle:nil message:@"输入标题" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil, nil]; [alert show]; return; } // 3、验证内容是否超过上限 if (![MMRichContentUtil validataContentNotOverflowWithRichContents:_datas]) { UIAlertView* alert = [[UIAlertView alloc] initWithTitle:nil message:@"输入内容" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil, nil]; [alert show]; return; } // 4、验证图片时候上传成功 if (![MMRichContentUtil validateImagesWithRichContents:self.datas]) { // 还有图片没上传或者图片失败的情况 return; } // 发送内容 _isOnUploading = YES; NSString* html = [MMRichContentUtil htmlContentFromRichContents:self.datas]; NSArray* images = [MMRichContentUtil imagesFromRichContents:self.datas]; // 处理发送... // FIXME: ZYT TODO 处理发送... } - (void)onTableViewTap { NSIndexPath* lastIndexPath = [NSIndexPath indexPathForRow:_datas.count - 1 inSection:1]; UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:lastIndexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { [((MMRichTextCell*)cell) mm_beginEditing]; } else if ([cell isKindOfClass:[MMRichImageCell class]]) { [((MMRichImageCell*)cell) mm_beginEditing]; }else{ [((RichFileCell*)cell) mm_beginEditing]; } } #pragma mark - Node Handler - (void)addTextNodeAtIndexPath:(NSIndexPath*)indexPath textContent:(NSString*)textContent { WS(weakSelf); dispatch_async(dispatch_get_main_queue(), ^{ MMRichTextModel* textModel = [MMRichTextModel new]; textModel.textContent = [textContent isEqualToString:@"\n"] ? @"" : textContent == nil ? @"" : textContent; textModel.textContentHeight = [MMRichContentUtil computeHeightInTextVIewWithContent:textModel.textContent]; [weakSelf.tableView beginUpdates]; [weakSelf.datas insertObject:textModel atIndex:indexPath.row]; [weakSelf.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; [weakSelf.tableView endUpdates]; [weakSelf.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO]; }); // 定位到新增的元素 [self positionAtIndex:indexPath]; } - (void)deleteItemAtIndexPathes:(NSArray*)actionIndexPathes shouldPositionPrevious:(BOOL)shouldPositionPrevious { if (actionIndexPathes.count > 0) { // 处理删除 for (NSInteger i = actionIndexPathes.count - 1; i >= 0; i--) { NSIndexPath* actionIndexPath = actionIndexPathes[i]; id obj = _datas[actionIndexPath.row]; if ([obj isKindOfClass:[MMRichImageModel class]]) { [MMDraftUtil deleteImageContent:(MMRichImageModel*)obj]; } [_datas removeObjectAtIndex:actionIndexPath.row]; } [self.tableView beginUpdates]; [self.tableView deleteRowsAtIndexPaths:actionIndexPathes withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; // 定位动到上一行 if (shouldPositionPrevious) { [self positionToPreItemAtIndexPath:actionIndexPathes.firstObject]; } } } - (void)deleteItemAtIndexPath:(NSIndexPath*)actionIndexPath shouldPositionPrevious:(BOOL)shouldPositionPrevious { // 定位动到上一行 if (shouldPositionPrevious) { [self positionToPreItemAtIndexPath:actionIndexPath]; } // 处理删除 [_datas removeObjectAtIndex:actionIndexPath.row]; [self.tableView beginUpdates]; [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:actionIndexPath.row inSection:actionIndexPath.section]] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; } /** 定位到指定的元素 */ - (void)positionAtIndex:(NSIndexPath*)indexPath { UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { [((MMRichTextCell*)cell) mm_beginEditing]; } else if ([cell isKindOfClass:[MMRichImageCell class]]) { [((MMRichImageCell*)cell) mm_beginEditing]; }else{ [((RichFileCell*)cell) mm_beginEditing]; } } // 定位动到上一行 - (void)positionToPreItemAtIndexPath:(NSIndexPath*)actionIndexPath { NSIndexPath* preIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row - 1 inSection:actionIndexPath.section]; [self positionAtIndex:preIndexPath]; } // 定位动到上一行 - (void)positionToNextItemAtIndexPath:(NSIndexPath*)actionIndexPath { NSIndexPath* preIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row + 1 inSection:actionIndexPath.section]; [self positionAtIndex:preIndexPath]; } #pragma mark - SmartBarDelegete - (void)didSelectBarAddBtnIsShow:(BOOL)isShow { [self.view endEditing:YES]; } - (void)didSelectBarKeyBtnIsShow:(BOOL)isShow { [self.view endEditing:YES]; } - (void)didSelectBarWithType:(SmartBarType)type { WS(weakSelf); switch (type) { case SmartBarPhoto: { [self chatBarDidPhotoAction]; } break; case SmartBarCamera: { [[LYLPhotoTailoringTool sharedTool] selectPhotoWithPhoroOrCamera:SelectPhotoWithTypePhoroOrCamera2 crop:YES showImgBlock:^(NSString *imageUrlStr) { } choosImgBlock:^(UIImage *image) { [weakSelf updateImages:@[image]]; }]; } break; case SmartBarNotes: { [[FWZGetNoteBookTool sharedTool] openNoteBookListChooseNoteBookBlock:^(NSMutableArray * _Nonnull noteArr) { NSLog(@"SmartBarNotes %@",noteArr); [weakSelf disSelectNoteBook:noteArr]; }]; } break; case SmartBarCollection: { [[FWZGetNoteBookTool sharedTool] openCollectListChooseCollectBlock:^(NSMutableArray * _Nonnull collectArr) { NSLog(@"SmartBarCollection %@",collectArr); [weakSelf disSelectCollect:collectArr]; }]; } break; case SmartBarFile: { WS(weakSelf); [[FWZFileGetTool sharedTool] openFileWithCrop:YES showImgBlock:^(NSString * _Nonnull fileUrlStr) { } choosFileBlock:^(NSData * _Nonnull fileData, NSString * _Nonnull fileName) { SHOWLOADING [[HttpManager sharedHttpManager] HeaderUploadFileUrl:Host(Modify_UserImages_Post) parameters:@{} fileData:fileData fileKey:@"file" fileName:fileName mimeType:@"multipart/form-data" success:^(id _Nonnull responseObject) { REMOVESHOW NSLog(@"上传成功的文件%@",responseObject); [weakSelf fileSizeWithData:fileData withDict:responseObject[0]]; } failure:^(NSError * _Nonnull error) { REMOVESHOW }]; }]; } break; default: break; } } - (void)disSelectNoteBook:(NSMutableArray*_Nonnull )noteArr{ RichModel * model = [[RichModel alloc] init]; NSMutableArray * array = [NSMutableArray array]; for (MyNoteBookSubModel *dataModel in noteArr ) { switch (dataModel.AttributeValue) { case 1: { model.Id = dataModel.MiddleId; model.AvatarUrl = dataModel.AvatarUrl; model.Author = dataModel.Name; model.Name = dataModel.Name; model.Title = dataModel.Title; model.type = CollectDataType_Note; } break; case 2: { model.Id = dataModel.MiddleId; model.AvatarUrl = dataModel.AvatarUrl; model.Author = dataModel.Name; model.Name = dataModel.Name; model.Title = dataModel.Title; model.type = CollectDataType_NoteFile; } break; default: break; } [array addObject:model]; } [self handleInsertModelArray:array]; } - (void)disSelectCollect:(NSMutableArray * _Nonnull) collectArr{ RichModel * model = [[RichModel alloc] init]; NSMutableArray * array = [NSMutableArray array]; for (MyFavoriteSubModel *dataModel in collectArr ) { switch (dataModel.AttributeValue) { case 1: { model.Id = dataModel.MiddleId; model.AvatarUrl = dataModel.AvatarUrl; model.Author = dataModel.Name; model.Name = dataModel.Name; model.Title = dataModel.Title; model.type = CollectDataType_Collect; } break; case 2: { RichModel * model = [[RichModel alloc] init]; model.Id = dataModel.MiddleId; model.AvatarUrl = dataModel.AvatarUrl; model.Author = dataModel.Name; model.Name = dataModel.Name; model.Title = dataModel.Title; model.type = CollectDataType_CollectFile; } break; default: break; } } [self handleInsertModelArray:array]; } - (void)fileSizeWithData:(NSData *)fileData withDict:(NSDictionary *)dict { unsigned long long size = [fileData length]; NSString * fileZise; if (size >= pow(10, 9)) { // size >= 1GB fileZise = [NSString stringWithFormat:@"%.2fGB", size / pow(10, 9)]; } else if (size >= pow(10, 6)) { // 1GB > size >= 1MB fileZise = [NSString stringWithFormat:@"%.2fMB", size / pow(10, 6)]; } else if (size >= pow(10, 3)) { // 1MB > size >= 1KB fileZise = [NSString stringWithFormat:@"%.2fKB", size / pow(10, 3)]; } else { // 1KB > size fileZise = [NSString stringWithFormat:@"%lluB", size]; } [self didSelectFile:dict withSize:fileZise]; } - (void)didSelectFile:(NSDictionary *)dict withSize:(NSString *)fileSize { RichModel * model = [[RichModel alloc] init]; model.Id = [dict[@"FileId"] integerValue]; model.AvatarUrl = dict[@"AbsolutePath"]; model.Author =dict[@"FileName"]; model.Name = dict[@"FileName"]; model.Title = dict[@"FileName"]; model.type = CollectDataType_File; [self handleInsertModelArray:@[model]]; } - (void)chatBarDidPhotoAction { WS(weakSelf); [self.view endEditing:YES]; TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:9 delegate:nil]; [imagePickerVc setNavLeftBarButtonSettingBlock:^(UIButton *leftButton){ leftButton.hidden = YES; }]; imagePickerVc.showSelectBtn = NO; imagePickerVc.allowCrop = YES; imagePickerVc.cropRect = CGRectMake(0, (SCREEN_HEIGHT - SCREEN_WIDTH) * 0.5, SCREEN_WIDTH, SCREEN_WIDTH); imagePickerVc.allowTakePicture = NO; imagePickerVc.allowTakeVideo = NO; imagePickerVc.allowPickingOriginalPhoto = NO; imagePickerVc.allowPickingGif = NO; [imagePickerVc setIsStatusBarDefault:YES]; [imagePickerVc setNaviTitleColor:[UIColor blackColor]]; [imagePickerVc setBarItemTextColor:[UIColor blackColor]]; [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray *photos, NSArray *assets, BOOL isSelectOriginalPhoto) { PHAsset *asset = assets.firstObject; switch (asset.mediaType) { case PHAssetMediaTypeVideo: { } break; case PHAssetMediaTypeImage: { [weakSelf updateImages:photos]; } break; case PHAssetMediaTypeAudio: break; case PHAssetMediaTypeUnknown: break; default: break; } }]; [self presentViewController:imagePickerVc animated:YES completion:nil]; } #pragma mark - ......::::::: RichTextEditDelegate :::::::...... - (void)mm_preInsertTextLineAtIndexPath:(NSIndexPath*)actionIndexPath textContent:(NSString*)textContent { UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:actionIndexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { // 不处理 } else if ([cell isKindOfClass:[MMRichImageCell class]]) { NSIndexPath* preIndexPath = nil; if (actionIndexPath.row > 0) { preIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row - 1 inSection:actionIndexPath.section]; id preData = _datas[preIndexPath.row]; if ([preData isKindOfClass:[MMRichTextModel class]]) { // Image节点-前面:上面是text,光标移动到上面一行,并且在最后添加一个换行,定位光标在最后将 [self.tableView scrollToRowAtIndexPath:preIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; // 设置为编辑模式 UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:preIndexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { [((MMRichTextCell*)cell) mm_beginEditing]; } else if ([cell isKindOfClass:[MMRichImageCell class]]) { [((MMRichImageCell*)cell) mm_beginEditing]; }else{ [((RichFileCell*)cell) mm_beginEditing]; } } else if ([preData isKindOfClass:[MMRichImageModel class]]) { // Image节点-前面:上面是图片或者空,在上面添加一个Text节点,光标移动到上面一行, [self addTextNodeAtIndexPath:actionIndexPath textContent:textContent]; }else{ [self addTextNodeAtIndexPath:actionIndexPath textContent:textContent]; } } else { // 上面为空,添加一个新的单元格 [self addTextNodeAtIndexPath:actionIndexPath textContent:textContent]; } }else{ NSIndexPath* preIndexPath = nil; if (actionIndexPath.row > 0) { preIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row - 1 inSection:actionIndexPath.section]; id preData = _datas[preIndexPath.row]; if ([preData isKindOfClass:[MMRichTextModel class]]) { // Image节点-前面:上面是text,光标移动到上面一行,并且在最后添加一个换行,定位光标在最后将 [self.tableView scrollToRowAtIndexPath:preIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; // 设置为编辑模式 UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:preIndexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { [((MMRichTextCell*)cell) mm_beginEditing]; } else if ([cell isKindOfClass:[MMRichImageCell class]]) { [((MMRichImageCell*)cell) mm_beginEditing]; }else{ [((RichFileCell*)cell) mm_beginEditing]; } } else if ([preData isKindOfClass:[MMRichImageModel class]]) { // Image节点-前面:上面是图片或者空,在上面添加一个Text节点,光标移动到上面一行, [self addTextNodeAtIndexPath:actionIndexPath textContent:textContent]; }else{ [self addTextNodeAtIndexPath:actionIndexPath textContent:textContent]; } } else { // 上面为空,添加一个新的单元格 [self addTextNodeAtIndexPath:actionIndexPath textContent:textContent]; } } } - (void)mm_postInsertTextLineAtIndexPath:(NSIndexPath*)actionIndexPath textContent:(NSString *)textContent { UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:actionIndexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { // 不处理 } else if ([cell isKindOfClass:[MMRichImageCell class]]) { NSIndexPath* nextIndexPath = nil; nextIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row + 1 inSection:actionIndexPath.section]; if (actionIndexPath.row < _datas.count-1) { id nextData = _datas[nextIndexPath.row]; if ([nextData isKindOfClass:[MMRichTextModel class]]) { // Image节点-后面:下面是text,光标移动到下面一行,并且在最前面添加一个换行,定位光标在最前面 [self.tableView scrollToRowAtIndexPath:nextIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; // 添加文字到下一行 MMRichTextModel* textModel = ((MMRichTextModel*)nextData); textModel.textContent = [NSString stringWithFormat:@"%@%@", textContent, textModel.textContent]; textModel.textContentHeight = [MMRichContentUtil computeHeightInTextVIewWithContent:textModel.textContent]; if ([textContent isEqualToString:@"\n"]) { textModel.selectedRange = NSMakeRange(0, 0); } else { textModel.selectedRange = NSMakeRange(textContent.length, 0); } textModel.shouldUpdateSelectedRange = YES; // 设置为编辑模式 UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:nextIndexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { [((MMRichTextCell*)cell) mm_beginEditing]; } else if ([cell isKindOfClass:[MMRichImageCell class]]) { [((MMRichImageCell*)cell) mm_beginEditing]; }else{ [((RichFileCell*)cell) mm_beginEditing]; } } else if ([nextData isKindOfClass:[MMRichImageModel class]]) { // Image节点-后面:下面是图片或者空,在下面添加一个Text节点,光标移动到下面一行 [self addTextNodeAtIndexPath:nextIndexPath textContent:textContent]; }else{ [self addTextNodeAtIndexPath:nextIndexPath textContent:textContent]; } } else { // Image节点-后面:下面是图片或者空,在下面添加一个Text节点,光标移动到下面一行 [self addTextNodeAtIndexPath:nextIndexPath textContent:textContent]; } }else{ NSIndexPath* nextIndexPath = nil; nextIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row + 1 inSection:actionIndexPath.section]; if (actionIndexPath.row < _datas.count - 1) { id nextData = _datas[nextIndexPath.row]; if ([nextData isKindOfClass:[MMRichTextModel class]]) { // Image节点-后面:下面是text,光标移动到下面一行,并且在最前面添加一个换行,定位光标在最前面 [self.tableView scrollToRowAtIndexPath:nextIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; // 添加文字到下一行 MMRichTextModel* textModel = ((MMRichTextModel*)nextData); textModel.textContent = [NSString stringWithFormat:@"%@%@", textContent, textModel.textContent]; textModel.textContentHeight = [MMRichContentUtil computeHeightInTextVIewWithContent:textModel.textContent]; if ([textContent isEqualToString:@"\n"]) { textModel.selectedRange = NSMakeRange(0, 0); } else { textModel.selectedRange = NSMakeRange(textContent.length, 0); } textModel.shouldUpdateSelectedRange = YES; // 设置为编辑模式 UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:nextIndexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { [((MMRichTextCell*)cell) mm_beginEditing]; } else if ([cell isKindOfClass:[MMRichImageCell class]]) { [((MMRichImageCell*)cell) mm_beginEditing]; }else{ [((RichFileCell*)cell) mm_beginEditing]; } } else if ([nextData isKindOfClass:[MMRichImageModel class]]) { // Image节点-后面:下面是图片或者空,在下面添加一个Text节点,光标移动到下面一行 [self addTextNodeAtIndexPath:nextIndexPath textContent:textContent]; }else { // Image节点-后面:下面是图片或者空,在下面添加一个Text节点,光标移动到下面一行 [self addTextNodeAtIndexPath:nextIndexPath textContent:textContent]; } }else { // Image节点-后面:下面是图片或者空,在下面添加一个Text节点,光标移动到下面一行 [self addTextNodeAtIndexPath:nextIndexPath textContent:textContent]; } } } - (void)mm_preDeleteItemAtIndexPath:(NSIndexPath*)actionIndexPath { UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:actionIndexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { // 处理Text节点 if (actionIndexPath.row < _datas.count) { if (actionIndexPath.row <= 0) { MMRichTextModel* textModel = (MMRichTextModel*)_datas[actionIndexPath.row]; if (_datas.count == 1) { // Text节点-当前的Text为空-前面-没有其他元素-:不处理 // Text节点-当前的Text不为空-前面-没有其他元素-:不处理 } else { if (textModel.textContent.length == 0) { // Text节点-当前的Text为空-前面-有其他元素-:删除这一行,定位光标到下面图片的最后 [self positionToNextItemAtIndexPath:actionIndexPath]; [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:NO]; } else { // Text节点-当前的Text不为空-前面-有其他元素-:不处理 } } } else { MMRichTextModel* textModel = (MMRichTextModel*)_datas[actionIndexPath.row]; if (textModel.textContent.length == 0) { // Text节点-当前的Text为空-前面-有其他元素-:删除这一行,定位光标到上面图片的最后 [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:YES]; } else { // 当前节点不为空 // Text节点-当前的Text不为空-前面-:上面是图片,定位光标到上面图片的最后 // Text节点不存在相邻的情况,所以直接定位上上一个元素即可 [self positionToPreItemAtIndexPath:actionIndexPath]; } } } } else if ([cell isKindOfClass:[MMRichImageCell class]]) { // 处理Image节点 if (actionIndexPath.row < _datas.count) { if (actionIndexPath.row <= 0) { // Image节点-前面-上面为空:不处理 // 第一行不处理 } else { NSIndexPath* preIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row - 1 inSection:actionIndexPath.section]; if (preIndexPath.row < _datas.count) { id preData = _datas[preIndexPath.row]; if ([preData isKindOfClass:[MMRichTextModel class]]) { if (((MMRichTextModel*)preData).textContent.length == 0) { // mage节点-前面-上面为Text(为空):删除上面Text节点 [self deleteItemAtIndexPath:preIndexPath shouldPositionPrevious:NO]; } else { [self positionToPreItemAtIndexPath:actionIndexPath]; } } else if ([preData isKindOfClass:[MMRichImageModel class]]) { [self positionToPreItemAtIndexPath:actionIndexPath]; }else{ [self positionToPreItemAtIndexPath:actionIndexPath]; } } } } }else{ if (actionIndexPath.row < _datas.count) { if (actionIndexPath.row <= 0) { // Image节点-前面-上面为空:不处理 // 第一行不处理 } else { NSIndexPath* preIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row - 1 inSection:actionIndexPath.section]; if (preIndexPath.row < _datas.count) { id preData = _datas[preIndexPath.row]; if ([preData isKindOfClass:[MMRichTextModel class]]) { if (((MMRichTextModel*)preData).textContent.length == 0) { // mage节点-前面-上面为Text(为空):删除上面Text节点 [self deleteItemAtIndexPath:preIndexPath shouldPositionPrevious:NO]; } else { [self positionToPreItemAtIndexPath:actionIndexPath]; } } else if ([preData isKindOfClass:[MMRichImageModel class]]) { [self positionToPreItemAtIndexPath:actionIndexPath]; }else{ [self positionToPreItemAtIndexPath:actionIndexPath]; } } } } } } - (void)mm_PostDeleteItemAtIndexPath:(NSIndexPath*)actionIndexPath { UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:actionIndexPath]; if ([cell isKindOfClass:[MMRichTextCell class]]) { // 不处理 // Text节点-当前的Text不为空-后面-:正常删除 // Text节点-当前的Text为空-后面-:正常删除,和第三种情况:为空的情况处理一样 } else if ([cell isKindOfClass:[MMRichImageCell class]]) { // 处理Image节点 if (actionIndexPath.row < _datas.count) { // 处理第一个节点 if (actionIndexPath.row <= 0) { if (_datas.count > 1) { // Image节点-后面-上面为空-列表多于一个元素:删除当前节点,光标放在后面元素之前 [self positionToNextItemAtIndexPath:actionIndexPath]; [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:NO]; } else { // Image节点-后面-上面为空-列表只有一个元素:添加一个Text节点,删除当前Image节点,光标放在添加的Text节点上 [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:NO]; [self addTextNodeAtIndexPath:actionIndexPath textContent:nil]; } } else { // 处理非第一个节点 NSIndexPath* preIndexPath = nil; if (actionIndexPath.row > 0) { preIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row - 1 inSection:actionIndexPath.section]; id preData = _datas[preIndexPath.row]; if ([preData isKindOfClass:[MMRichTextModel class]]) { NSIndexPath* nextIndexPath = nil; if (actionIndexPath.row < _datas.count - 1) { nextIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row + 1 inSection:actionIndexPath.section]; } if (nextIndexPath) { id nextData = _datas[nextIndexPath.row]; if ([nextData isKindOfClass:[MMRichTextModel class]]) { // Image节点-后面-上面为Text-下面为Text:删除Image节点,合并下面的Text到上面,删除下面Text节点,定位到上面元素的后面 ((MMRichTextModel*)preData).textContent = [NSString stringWithFormat:@"%@\n%@", ((MMRichTextModel*)preData).textContent, ((MMRichTextModel*)nextData).textContent]; ((MMRichTextModel*)preData).textContentHeight = [MMRichContentUtil computeHeightInTextVIewWithContent:((MMRichTextModel*)preData).textContent]; ((MMRichTextModel*)preData).selectedRange = NSMakeRange(((MMRichTextModel*)preData).textContent.length, 0); ((MMRichTextModel*)preData).shouldUpdateSelectedRange = YES; [self deleteItemAtIndexPathes:@[actionIndexPath, nextIndexPath] shouldPositionPrevious:YES]; } else { // Image节点-后面-上面为Text-下面为图片或者空:删除Image节点,定位到上面元素的后面 [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:YES]; } } else { // Image节点-后面-上面为Text-下面为图片或者空:删除Image节点,定位到上面元素的后面 [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:YES]; } } else if ([preData isKindOfClass:[MMRichImageModel class]]) { // Image节点-后面-上面为图片:删除Image节点,定位到上面元素的后面 [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:YES]; }else{ [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:YES]; } } } } }else{ if (actionIndexPath.row < _datas.count) { // 处理第一个节点 if (actionIndexPath.row <= 0) { if (_datas.count > 1) { // Image节点-后面-上面为空-列表多于一个元素:删除当前节点,光标放在后面元素之前 [self positionToNextItemAtIndexPath:actionIndexPath]; [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:NO]; } else { // Image节点-后面-上面为空-列表只有一个元素:添加一个Text节点,删除当前Image节点,光标放在添加的Text节点上 [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:NO]; [self addTextNodeAtIndexPath:actionIndexPath textContent:nil]; } } else { // 处理非第一个节点 NSIndexPath* preIndexPath = nil; if (actionIndexPath.row > 0) { preIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row - 1 inSection:actionIndexPath.section]; id preData = _datas[preIndexPath.row]; if ([preData isKindOfClass:[MMRichTextModel class]]) { NSIndexPath* nextIndexPath = nil; if (actionIndexPath.row < _datas.count - 1) { nextIndexPath = [NSIndexPath indexPathForRow:actionIndexPath.row + 1 inSection:actionIndexPath.section]; } if (nextIndexPath) { id nextData = _datas[nextIndexPath.row]; if ([nextData isKindOfClass:[MMRichTextModel class]]) { // Image节点-后面-上面为Text-下面为Text:删除Image节点,合并下面的Text到上面,删除下面Text节点,定位到上面元素的后面 ((MMRichTextModel*)preData).textContent = [NSString stringWithFormat:@"%@\n%@", ((MMRichTextModel*)preData).textContent, ((MMRichTextModel*)nextData).textContent]; ((MMRichTextModel*)preData).textContentHeight = [MMRichContentUtil computeHeightInTextVIewWithContent:((MMRichTextModel*)preData).textContent]; ((MMRichTextModel*)preData).selectedRange = NSMakeRange(((MMRichTextModel*)preData).textContent.length, 0); ((MMRichTextModel*)preData).shouldUpdateSelectedRange = YES; [self deleteItemAtIndexPathes:@[actionIndexPath, nextIndexPath] shouldPositionPrevious:YES]; } else { // Image节点-后面-上面为Text-下面为图片或者空:删除Image节点,定位到上面元素的后面 [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:YES]; } } else { // Image节点-后面-上面为Text-下面为图片或者空:删除Image节点,定位到上面元素的后面 [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:YES]; } } else if ([preData isKindOfClass:[MMRichImageModel class]]) { // Image节点-后面-上面为图片:删除Image节点,定位到上面元素的后面 [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:YES]; }else{ [self deleteItemAtIndexPath:actionIndexPath shouldPositionPrevious:YES]; } } } } } } // 更新ActionIndexpath - (void)mm_updateActiveIndexPath:(NSIndexPath*)activeIndexPath { _activeIndexPath = activeIndexPath; NSLog(@"mm_updateActiveIndexPath ===== %@", activeIndexPath); } // 重新加载 - (void)mm_reloadItemAtIndexPath:(NSIndexPath*)actionIndexPath { NSLog(@"======删除图片"); } - (void)mm_uploadFailedAtIndexPath:(NSIndexPath *)actionIndexPath { } - (void)mm_uploadDonedAtIndexPath:(NSIndexPath *)actionIndexPath { } - (void)mm_shouldShowAccessoryView:(BOOL)shouldShow { _shouldShowAccessoryView = shouldShow; } - (BOOL)mm_shouldCellShowPlaceholder { return [MMRichContentUtil shouldShowPlaceHolderFromRichContents:_datas]; } #pragma mark - ......::::::: UITableView Handler :::::::...... - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Title if (section == 0) { return 1; } // Content return _datas.count; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 0) { return _titleModel.cellHeight; } else if (indexPath.section == 1) { id obj = _datas[indexPath.row]; if ([obj isKindOfClass:[MMRichTextModel class]]) { MMRichTextModel* textModel = (MMRichTextModel*)obj; return textModel.textContentHeight; } else if ([obj isKindOfClass:[MMRichImageModel class]]) { MMRichImageModel* imageModel = (MMRichImageModel*)obj; return imageModel.imageContentHeight; }else{ return 128.f; } } return 1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // Title if (indexPath.section == 0) { MMRichTitleCell* cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(MMRichTitleCell.class)]; cell.delegate = self; [cell updateWithData:_titleModel indexPath:indexPath]; return cell; } // Content id obj = _datas[indexPath.row]; if ([obj isKindOfClass:[MMRichTextModel class]]) { MMRichTextCell* cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(MMRichTextCell.class)]; cell.delegate = self; [cell updateWithData:obj indexPath:indexPath]; return cell; } if ([obj isKindOfClass:[MMRichImageModel class]]) { MMRichImageCell* cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(MMRichImageCell.class)]; cell.delegate = self; [cell updateWithData:obj]; return cell; } if ([obj isKindOfClass:[RichModel class]]) { RichFileCell* cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(RichFileCell.class)]; cell.delegate = self; [cell updateWithData:obj]; return cell; } static NSString* cellID = @"cellId"; UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellID]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; } return cell; } - (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { return NO; } @end