• Stars
    star
    271
  • Rank 151,717 (Top 3 %)
  • Language
    Objective-C
  • Created almost 8 years ago
  • Updated over 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

因为公司有很多模块,几乎每个模块都需要发布视频、语言、照片。所以在很多库的基础上,搭建了一个集合,其中包括带placeHolder的TextView、录制小视频、录制音频、选择照片或拍照。其中包括了很多网络上的资源,只是做了集合,在此留个记录,也希望对一些有需求的朋友有帮助。

ImageAndVideoAnsRecord

效果图

##import "ViewController.m" PlaceholderTextView* titleTexView; // placeHolder的textView, PlaceholderTextView* contentTextView; showVideoView* showVideo; //添加照片、视频、语音按钮

使用 PlaceholderTextView

 titleTexView = [[PlaceholderTextView alloc]initWithFrame:CGRectMake(12, 10, kScreenWidth-24, 35)];
titleTexView.delegate = self;
titleTexView.font = [UIFont systemFontOfSize:15.f];
titleTexView.textColor = [UIColor blackColor];
titleTexView.textAlignment = NSTextAlignmentLeft;
titleTexView.editable = YES;
titleTexView.placeholderColor = [UIColor darkTextColor];
titleTexView.placeholder = @"标题(必填)";
[showScrollView addSubview:titleTexView];

showVideoView

showVideo = [[showVideoView alloc]initWithFrame:CGRectMake(0, contentTextView.frame.origin.y+contentTextView.frame.size.height+5, kScreenWidth, 78)];
[showScrollView addSubview:showVideo];

#pragma mark 🎱 发布前检查数据 包括各种视频、照片、语音的收集,方便上传服务器

- (BOOL)collectModelInformation

##import "showVideoView.h"

@property (nonatomic,strong)NSMutableArray* imgeArray;  // 图片数组
@property (nonatomic,strong)KZVideoModel*  videoModel;   // 视频Model
@property (nonatomic,strong)KZVideoPlayer *player;       //视频播放Player
@property (nonatomic,strong)LGMessageModel *messageModel;  //语音录制Model



@property (nonatomic, strong) UIButton* addImageButton;   //添加照片按钮
@property (nonatomic, strong) UIButton* addVideoButton;   //添加视频按钮
@property (nonatomic, strong) UIButton* addRecordButton;  //添加语音按钮

##import "showVideoView.m" @property (nonatomic, assign) BOOL isVideo; //是否已添加视频 @property (nonatomic, assign) BOOL isPhoto; //是否已添加照片 @property (nonatomic, assign) BOOL isRecord; //是否已添加语音 在点击按钮时改变对应的is属性,在set方法中对相应的按钮位置更新

###照片 #pragma mark 🎱 添加照片

默认6张,可以修改

- (void)addImageButtonAction:(UIButton*)sender

#pragma mark 🎱 显示照片

照片在Collection中显示,方便完成增删

collectionCell 中有 普通照片、添加照片按钮、添加视频按钮,根据CircleCellModel中cirModelState属性判断 对应的方法在其viewController里实现

- (void)addImageToshowCirclectionView:(NSArray*)imageArray{



circleCollectionView.hidden = NO;

CGFloat circleCollectionHeight = 60;


if (photoNumber >0) { //不是第一次添加照片
    
    photoNumber = photoNumber + imageArray.count;
    
    [self deleteAddPhotoButton];
    //        [self delete_addVideoButton];
    
    //没有视频就是3张照片,若有视频就是2张
    if (photoNumber > 3) { // circleCollection变两行,刷新tableview
       //            superViewController.photoHeight = 220;
        
        circleCollectionHeight = collectionViewHeight*2;
        
        self.height = self.height + collectionViewHeight;
       //            [self changeSuperScrollViewContentSize:self.height];
        
        if (photoNumber >= 6) {  //多次添加照片总数超过限制,截取7-self.imgeArray.count个元素拼接
            
            NSRange range = NSMakeRange(0, 6 - circleCollectionView.photoArray.count);
            NSArray* tempArray = [imageArray subarrayWithRange:range];
            [self.imgeArray addObjectsFromArray:tempArray];
            
            for (int i = 0; i < tempArray.count; i++) {
                
                CircleCellModel *circelModel = [[CircleCellModel alloc]init];
                
                if ([tempArray[i] isKindOfClass:[ZZPhoto class]]) {
                    
                    ZZPhoto* model = tempArray[i];
                    
                    circelModel.photoImage = model.originImage;
                    
                }else if([tempArray[i] isKindOfClass:[ZZCamera class]]){
                    
                    
                    ZZCamera* model = tempArray[i];
                    
                    circelModel.photoImage = model.image;
                }else{
                    
                    circelModel.photoImage = tempArray[i];
                }
                
                circelModel.state = CirModelStateNormal;
                [circleCollectionView.photoArray addObject:circelModel];
                
            }
            
            
            photoNumber = 6;
            
        }else{
             
            [self.imgeArray addObjectsFromArray:imageArray];
            
            for (int i = 0; i < imageArray.count; i++) {
                CircleCellModel *circelModel = [[CircleCellModel alloc]init];
                
                if ([imageArray[i] isKindOfClass:[ZZPhoto class]]) {
                    
                    ZZPhoto* model = imageArray[i];
                    
                    circelModel.photoImage = model.originImage;
                    
                }else if([imageArray[i] isKindOfClass:[ZZCamera class]]){
                    
                    
                    ZZCamera* model = imageArray[i];
                    
                    circelModel.photoImage = model.image;
                }else{
                    
                    circelModel.photoImage = imageArray[i];
                }
                circelModel.state = CirModelStateNormal;
                [circleCollectionView.photoArray addObject:circelModel];
            }
            
            //最后放一张pluse
            CircleCellModel *cirModel = [[CircleCellModel alloc]init];
            cirModel.photoImage = [UIImage imageNamed:@"plus"];
            cirModel.state = CirModelStateAdd;
            
            [circleCollectionView.photoArray addObject:cirModel];
            
            
        }
    }else{
        
        [self.imgeArray addObjectsFromArray:imageArray];
        
        for (int i = 0; i < imageArray.count; i++) {
            
            CircleCellModel *circelModel = [[CircleCellModel alloc]init];
            
            if ([imageArray[i] isKindOfClass:[ZZPhoto class]]) {
                
                ZZPhoto* model = imageArray[i];
                
                circelModel.photoImage = model.originImage;
                
            }else if([imageArray[i] isKindOfClass:[ZZCamera class]]){
                
                
                ZZCamera* model = imageArray[i];
                
                circelModel.photoImage = model.image;
            }else{
                
                circelModel.photoImage = imageArray[i];
            }
            
            circelModel.state = CirModelStateNormal;
            [circleCollectionView.photoArray addObject:circelModel];
            
        }
        
        //最后放一张pluse
        CircleCellModel *cirModel = [[CircleCellModel alloc]init];
        cirModel.photoImage = [UIImage imageNamed:@"plus"];
        cirModel.state = CirModelStateAdd;
        
        [circleCollectionView.photoArray addObject:cirModel];
        
    }
    
}else{  //第一次添加照片
    
    
    photoNumber = photoNumber + imageArray.count;
    
    [circleCollectionView.photoArray removeAllObjects];
    
    if(self.imgeArray.count <=0){
        
        [self.imgeArray addObjectsFromArray:imageArray];
    }
    
    //没有视频就是3张照片,若有视频就是2张
    
    if (photoNumber > 3) { // circleCollection变两行,刷新tableview
       //            superViewController.photoHeight = 220;
        
        circleCollectionHeight = collectionViewHeight*2;

        
    }
    
    for (int i = 0; i < self.imgeArray.count; i++) {
        CircleCellModel *circelModel = [[CircleCellModel alloc]init];
        if ([imageArray[i] isKindOfClass:[ZZPhoto class]]) {
            
            ZZPhoto* model = imageArray[i];
            
            circelModel.photoImage = model.originImage;
            
        }else if([imageArray[i] isKindOfClass:[ZZCamera class]]){
            
            
            ZZCamera* model = imageArray[i];
            
            circelModel.photoImage = model.image;
        }else{
            
            circelModel.photoImage = imageArray[i];
            
        }
        circelModel.state = CirModelStateNormal;
        [circleCollectionView.photoArray addObject:circelModel];
        
    }
    
    if ( photoNumber < 6 ) {
        
        //最后放一张pluse
        CircleCellModel *cirModel = [[CircleCellModel alloc]init];
        cirModel.photoImage = [UIImage imageNamed:@"plus"];
        cirModel.state = CirModelStateAdd;
        
        [circleCollectionView.photoArray addObject:cirModel];
        
    }else{
        
        //            if (photoNumber >= 7) {  //多次添加照片总数超过限制,截取7-self.imgeArray.count个元素拼接
        
        NSRange range = NSMakeRange(0, 6 - circleCollectionView.photoArray.count);
        NSArray* tempArray = [imageArray subarrayWithRange:range];
        [self.imgeArray addObjectsFromArray:tempArray];
        
        for (int i = 0; i < tempArray.count; i++) {
            
            CircleCellModel *circelModel = [[CircleCellModel alloc]init];
            
            if ([tempArray[i] isKindOfClass:[ZZPhoto class]]) {
                
                ZZPhoto* model = tempArray[i];
                
                circelModel.photoImage = model.originImage;
                
            }else if([tempArray[i] isKindOfClass:[ZZCamera class]]){
                
                
                ZZCamera* model = tempArray[i];
                
                circelModel.photoImage = model.image;
            }else{
                
                circelModel.photoImage = tempArray[i];
            }
            
            circelModel.state = CirModelStateNormal;
            [circleCollectionView.photoArray addObject:circelModel];
            
        }
    }
    
    self.height = self.height + circleCollectionHeight;
    
    self.isPhoto = YES;
}
//    [self chanageCircleCollectonFrame];

[circleCollectionView mas_updateConstraints:^(MASConstraintMaker *make) {
    
    make.height.mas_equalTo(circleCollectionHeight);
    
    if (_isRecord) {
        
        make.top.equalTo(playButton.mas_bottom).offset(10);
    }else{
        
        make.top.equalTo(self.mas_top);
    }
}];
//    [self refreshButtonFrame];

[circleCollectionView reloadData];

}

###视频 #pragma mark 🎱添加视频

- (void)_addVideoButtonAction:(UIButton*)sender{

KZVideoViewController *videoVC = [[KZVideoViewController alloc] init];
videoVC.delegate = self;
[videoVC startAnimationWithType:KZVideoViewShowTypeSingle];
}

实现KZVideoViewControllerDelegate

#pragma mark 🎱 视频录制或选择后回调

- (void)videoViewController:(KZVideoViewController *)videoController didRecordVideo:(KZVideoModel *)videoModel{

//    [self refreshButtonFrame];

//    _addVideoButton.hidden = YES;

//    [self delete_addVideoButton];

[circleCollectionView reloadData];

_videoModel = videoModel;

[self playerVideo:videoModel];
}

#pragma mark 🎱 视频播放

- (void)playerVideo:(KZVideoModel*)videoModel{
NSURL *videoUrl = [NSURL fileURLWithPath:videoModel.videoAbsolutePath];

if (_player == nil) {
    
    if (videoUrl) {
        
        _player = [[KZVideoPlayer alloc] initWithFrame:CGRectMake(12, self.top, 102, 80) videoUrl:videoUrl];
        
    }
}
_player.layer.masksToBounds = NO;
_player.backgroundColor = [UIColor blackColor];
[self.superview addSubview:_player];
[_player mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(self.mas_left).offset(12);
    make.top.equalTo(self.mas_top);
    make.width.mas_equalTo(102);
    make.height.mas_equalTo(80);
}];



UIButton* deletVideo  = [[UIButton alloc]initWithFrame:CGRectMake(_player.width-20 , 0, 20, 20)];
[deletVideo setImage:[UIImage imageNamed:@"delete28"] forState:UIControlStateNormal];
[_player addSubview:deletVideo];
[deletVideo addTarget:self action:@selector(deleteVideoButtonAction:) forControlEvents:UIControlEventTouchUpInside];

//    [self chanageCircleCollectonFrame];

self.isVideo = YES;
}

###语音

 定时60S,可修改      //录音储存路径  

#define DocumentPath  		[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
_addRecordButton = [[UIButton alloc]initWithFrame:CGRectMake(_addVideoButton.right+5, _addVideoButton.top, _addVideoButton.width, _addVideoButton.height)];
[_addRecordButton setImage:[UIImage imageNamed:@"second_sounding_d"] forState:UIControlStateNormal];
[_addRecordButton addTarget:self action:@selector(startRecordVoice) forControlEvents:UIControlEventTouchDown];  // 开始录音
[_addRecordButton addTarget:self action:@selector(cancelRecordVoice) forControlEvents:UIControlEventTouchUpOutside];// 取消录音
[_addRecordButton addTarget:self action:@selector(confirmRecordVoice) forControlEvents:UIControlEventTouchUpInside];// 录音结束
[_addRecordButton addTarget:self action:@selector(updateCancelRecordVoice) forControlEvents:UIControlEventTouchDragExit]; // 更新录音显示状态,手指向上滑动后 提示松开取消录音
[_addRecordButton addTarget:self action:@selector(updateContinueRecordVoice) forControlEvents:UIControlEventTouchDragEnter]; //更新录音状态,手指重新滑动到范围内,提示向上取消录音

将生成的caf格式的视频转换成mp3格式,方便与安卓共用,但是会有比较严重的失真,如果安卓不是需求尽量不要转

- (NSString*)formatConversionToMp3{

NSString *cafFilePath = self.messageModel.soundFilePath;    //caf文件路径

NSString* fileName = [NSString stringWithFormat:@"/voice-%5.2f.mp3", [[NSDate date] timeIntervalSince1970] ];//存储mp3文件的路径

NSString *mp3FilePath = [[DocumentPath stringByAppendingPathComponent:@"SoundFile"] stringByAppendingPathComponent:fileName];

@try {
    CGFloat read, write;
    
    FILE *pcm = fopen([cafFilePath cStringUsingEncoding:1], "rb");  //source 被转换的音频文件位置
    fseek(pcm, 4*1024, SEEK_CUR);                                   //skip file header
    FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb");  //output 输出生成的Mp3文件位置
    
    const int PCM_SIZE = 8192;
    const int MP3_SIZE = 8192;
    short int pcm_buffer[PCM_SIZE*2];
    unsigned char mp3_buffer[MP3_SIZE];
    
    lame_t lame = lame_init();
    lame_set_in_samplerate(lame, 11025.0);
    lame_set_VBR(lame, vbr_default);
    lame_init_params(lame);
    
    do {
        read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
        if (read == 0)
            write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
        else
            write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
        
        fwrite(mp3_buffer, write, 1, mp3);
        
    } while (read != 0);
    
    lame_close(lame);
    fclose(mp3);
    fclose(pcm);
}
@catch (NSException *exception) {
    NSLog(@"%@",[exception description]);
}
@finally {
    
    
}

// 将caf 文件删除
[[NSFileManager defaultManager] removeItemAtPath:self.messageModel.soundFilePath error:nil];

NSLog(@"mp3FilePath :: :::::≥≥≥®%@",mp3FilePath);
return  mp3FilePath;
}

#TIP: 之前设定的是照片和视频不能同时发布,但是布局和逻辑已经做好了,如果需要可以修改showVideoView.m中

- (void)setIsPhoto:(BOOL)isPhoto;
//添加视频按钮可以使用
_addVideoButton.enabled = NO;
[_addVideoButton setImage:[UIImage imageNamed:@"second_video_s"] forState:UIControlStateNormal];

注释掉就可以了