UITextView实现图片、视频和表情与插入删除和删除。

32 篇文章 0 订阅
7 篇文章 0 订阅

表情是特殊的串。详细使用见
《表情包组件》
通过UITextView插入NSTextAttachment来显示图片。很不幸NSTextAttachment只能展示图片,不能展示视频。可以通过类继承来实现把视频链接存入它的子类,展示只能按照视频的首帧图展示。
视频的和图片的上产可以通过第三方组件LFImagePickerController选择视频和图片,视频可以可以拿到视频的首帧图和NSData类型的视频数据。
然后把视频或图像上传服务器,服务器返回它的地址。
最后解析UITextView的attributedText,组装h5格式字符串发送给后台。
至于在其它客户端的展示只能使用标准h5进程组件wkwebview来展示了,这样视频图片文字都能正常展示了。这个下一篇文章介绍,防止文章又臭又长。
注意:咱们常用的TZImagePickerController的demo无法拿到视频数据流,只能拿到PHAsset,无法拿到云上的视频,我折腾了半天通过PHAsset也没有拿到视频流,若你牛你可以自己继续探索,反正我是放弃了。别说些理论上的东西或网上查出的东西,我只相信实践是检验真理的唯一标准,自己实际搞出来才是真的正确。其实有很多技术就隔一层窗户纸,但是哪怕差一个属性设置。若不知道导致不能真正实现也是白搭。有现成的LFImagePickerController帮你搞定一切,不用你为这绞尽脑汁。
DYTextAttachment.h文件

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSInteger, DYFileType)
{
    DYFileTypeText = 0,//第一种状态
    DYFileTypeImage = 1,//第二种状态
    DYFileTypeVideo = 2 //第三种状态
};

@interface DYTextAttachment : NSTextAttachment
@property(strong, nonatomic) NSString *emojiTag;
@property(assign, nonatomic) CGSize emojiSize;  //For emoji image size
@property (nonatomic, assign) BOOL isVideo;

@property(strong, nonatomic) NSString *inputStr;
@property(strong, nonatomic) NSString *dataFilePath;
@property(nonatomic, assign) DYFileType dyFileType;
@end

DYTextAttachment.m文件

#import "DYTextAttachment.h"

@implementation DYTextAttachment
- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex {
    return CGRectMake(0, 0, _emojiSize.width, _emojiSize.height);
}
@end

获取图片或视频并组装数据发送图片或视频上传

- (void)lf_imagePickerController:(LFImagePickerController *)picker didFinishPickingResult:(NSArray <LFResultObject /* <LFResultImage/LFResultVideo> */*> *)results;
{
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0];
    NSString *thumbnailFilePath = [documentPath stringByAppendingPathComponent:@"thumbnail"];
    NSString *originalFilePath = [documentPath stringByAppendingPathComponent:@"original"];
    
    NSFileManager *fileManager = [NSFileManager new];
    if (![fileManager fileExistsAtPath:thumbnailFilePath])
    {
        [fileManager createDirectoryAtPath:thumbnailFilePath withIntermediateDirectories:YES attributes:nil error:nil];
    }
    if (![fileManager fileExistsAtPath:originalFilePath])
    {
        [fileManager createDirectoryAtPath:originalFilePath withIntermediateDirectories:YES attributes:nil error:nil];
    }
    NSMutableArray <UIImage *>*images = [@[] mutableCopy];
    BOOL flag = NO;
    for (NSInteger i = 0; i < results.count; i++) {
        LFResultObject *result = results[i];
        if ([result isKindOfClass:[LFResultImage class]]) {
            
            LFResultImage *resultImage = (LFResultImage *)result;
            NSLog(@"resultImage.originalImage:%@", resultImage.originalImage);
            NSInteger i = 0;
//            for(i = 0; i<photos.count;i++)
            if(resultImage.originalImage)
            {
                flag = YES;
//                UIImage *image = photos[i];
                self.model.imageData = resultImage.originalData;
                self.model.image = resultImage.originalImage;// [self getCompressImageWithImage:resultImage.originalImage];
                self.model.dyFileType = DYFileTypeImage;
                [self excuteQA_UploadCommand];
            }
        } else if ([result isKindOfClass:[LFResultVideo class]]) {
            
            LFResultVideo *resultVideo = (LFResultVideo *)result;
            if(resultVideo.data)
            {
                flag = YES;
                self.model.imageData = resultVideo.data;
                self.model.image =  [self getCompressImageWithImage:resultVideo.coverImage]; //resultVideo.coverImage; 
                self.model.dyFileType = DYFileTypeVideo;
                [self excuteQA_UploadCommand];
            }
            NSLog(@"🎉🚀Info name:%@ -- infoLength:%fK -- videoLength:%fK -- infoSize:%@", resultVideo.info.name, resultVideo.info.byte/1000.0, resultVideo.data.length/1000.0, NSStringFromCGSize(resultVideo.info.size));
        } else {
            /** 无法处理的数据 */
            NSLog(@"%@", result.error);
        }
    }
}

图像或视频上传,然后把图片地址和图片,类型封装DYTextAttachment对象插入UITextView的textStorage并移动光标。至于删除通过键盘的删除键操作就可以了。

-(void)excuteQA_UploadCommand
{
    @weakify(self);
    
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];

    [dict setObject:[DataStore sharedDataStore].UID forKey:@"UID"];
    [BITLoadingView show];
    [[NetWorkEngine shareNetWorkEngine] postDataFromServerWithUrlStr:@"http://huaxin.jtaqkt.com/MApi/StudyApi.asmx/QA_Upload" Paremeters:dict isPhoto:(self.model.dyFileType == DYFileTypeImage) data:self.model.imageData successOperation:^(id response) {
        @strongify(self);
        [BITLoadingView hide];
        CBPShopHomeResultHeadEntity *shopHomeResultHeadEntity = [CBPShopHomeResultHeadEntity mj_objectWithKeyValues:response];
        if(1 == shopHomeResultHeadEntity.message)
        {
            if(shopHomeResultHeadEntity.data && [shopHomeResultHeadEntity.data isKindOfClass:[NSDictionary class]])
            {
                CBPShopHomeResultHeadEntity *shopHomeResultHeadEntity1 = [CBPShopHomeResultHeadEntity mj_objectWithKeyValues:shopHomeResultHeadEntity.data];
                DYTextAttachment *textAttachment = [[DYTextAttachment alloc] init];
                textAttachment.dataFilePath = shopHomeResultHeadEntity1.FilePath;
                textAttachment.image = self.model.image;//[self getCompressImageWithImage:resultImage.originalImage];
                
                textAttachment.emojiSize = CGSizeMake(textAttachment.image.size.width, textAttachment.image.size.height);
                textAttachment.bounds = CGRectMake(0, 0, textAttachment.image.size.width, textAttachment.image.size.height);
//                textAttachment.contents = self.model.imageData;
                textAttachment.dyFileType = self.model.dyFileType;
                textAttachment.bounds = CGRectMake(0, 0, textAttachment.image.size.width, textAttachment.image.size.height);
                NSAttributedString *str = [NSAttributedString attributedStringWithAttachment:textAttachment];
                //Insert emoji image
                [self.inputTextView.textStorage insertAttributedString:str atIndex:self.inputTextView.selectedRange.location];
                self.inputTextView.selectedRange = NSMakeRange(self.inputTextView.selectedRange.location+1, 0); //
                [self.rightBarButton setTitleColor:BGColorHex(ED5058) forState:UIControlStateNormal];
                self.rightBarButton.userInteractionEnabled = YES;
                self.describeTitleLabel.hidden = YES;
            }
        }
        else
        {
            [[BITNoticeView currentNotice] showErrorNotice:shopHomeResultHeadEntity.messagestr];
        }
    } failoperation:^(NSError *error) {
        @strongify(self);
        [BITLoadingView hide];
        [[BITNoticeView currentNotice] showErrorNotice:error.domain];
    }];
}

为了解决横屏视频的首帧横向显示不全,可以通过图片尺寸压缩显示。当然选取的是图像,第三方控件替你尺寸压缩好了,不用你自己再压缩一遍。

-(UIImage *)getCompressImageWithImage:(UIImage *)image
{
    if(image.size.width > (FULL_WIDTH-COMMON_EDGE_DISTANCE*2))
    {
        // 创建一个bitmap的context
        // 并把它设置成为当前正在使用的context
        UIGraphicsBeginImageContext(CGSizeMake((FULL_WIDTH-COMMON_EDGE_DISTANCE*2), (FULL_WIDTH-COMMON_EDGE_DISTANCE*2)*image.size.height/image.size.width));
        [image drawInRect:CGRectMake(0, 0, (FULL_WIDTH-COMMON_EDGE_DISTANCE*2) , (FULL_WIDTH-COMMON_EDGE_DISTANCE*2)*image.size.height/image.size.width)];
        // 从当前context中创建一个改变大小后的图片
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        // 使当前的context出堆栈
        UIGraphicsEndImageContext();
        NSData *data = UIImageJPEGRepresentation(newImage, 0.8);
//        self.model.imageData = data;
        UIImage *image1 = [UIImage imageWithData:data];
        return image1;
    }
    else
    {
        self.model.imageData = UIImageJPEGRepresentation(image, 0.8);
        return image;
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,您需要将 YYLabel 添加到 UITableViewCell 中。 您可以通过在 UITableViewCell 子类中创建 YYLabel 实例并将其添加到 contentView 中来完成此操作。 您可以使用自动布局或手动布局将 YYLabel 放置在所需的位置上。 接下来,您需要创建 NSMutableAttributedString,其中包含 UITextView 和其他文本。 然后,您可以使用 NSMutableAttributedString 的 insert 方法将 UITextView 作为附件添加到文本中。 以下是一个示例代码片段: ```swift let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 100, height: 50)) textView.text = "This is a UITextView" let attachment = NSTextAttachment() attachment.bounds = CGRect(x: 0, y: 0, width: 100, height: 50) attachment.setAttachmentContent(textView) let attributedString = NSMutableAttributedString(string: "This is a YYLabel with a UITextView attachment") attributedString.insert(NSAttributedString(attachment: attachment), at: 21) yyLabel.attributedText = attributedString ``` 最后,您需要处理 UITextView 和 UITableView 之间的交互。您需要将 UITextView 的 isEditable 属性设置为 false,以防止用户编辑文本。您还需要在 UITableViewDelegate 中实现 heightForRowAt 和 estimatedHeightForRowAt 方法来动态计算 UITableViewCell 的高度,以适应包含 UITextView 的 YYLabel。 以下是一个示例 UITableViewDelegate 实现: ```swift class MyTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() tableView.register(MyTableViewCell.self, forCellReuseIdentifier: "cell") } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell // Configure the cell... return cell } override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! MyTableViewCell cell.configure(with: "This is a YYLabel with a UITextView attachment") return cell.systemLayoutSizeFitting(CGSize(width: tableView.frame.width, height: UIView.layoutFittingCompressedSize.height)).height } override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension } } ``` 请注意,此示例实现了一个名为 MyTableViewCell 的 UITableViewCell 子类,该子类包含一个名为 yyLabel 的 YYLabel 实例。 该子类还实现了一个名为 configure(with:) 的方法,该方法接受一个字符串参数,并在 YYLabel 中设置带有 UITextView 附件的 NSMutableAttributedString。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值