多媒体和断点续传

来源:互联网 发布:怎么给淘宝刷好评赚钱 编辑:程序博客网 时间:2024/06/16 12:43

1. 根TabBar

RootViewController.m

//  1. 系统相册/拍照//  2. 音频播放//  3. 视须播放//  4. 断点续传[@interface RootViewController : UITabBarController]#import "RootViewController.h"#import "PhotoViewController.h"#import "AudioViewController.h"#import "VideoViewController.h"#import "ResumeDownloadController.h"//给UIViewController做一个扩展方便创建视图控制器//作用:让它具有TabBarItem@interface UIViewController (item)//如果item不加,括号里面的内容为空,表示这是一个匿名类别,匿名类别中加的东西只是为了表示是私有的,而扩展不一样,扩展是让原来的类具有一些额外的功能+ (UIViewController *)viewControllerWithTitle:(NSString *)title image:(UIImage *)image selectedImage:(UIImage *)selectedImage;@end@implementation UIViewController (item)+ (UIViewController *)viewControllerWithTitle:(NSString *)title image:(UIImage *)image selectedImage:(UIImage *)selectedImage{    UITabBarItem *item = [[UITabBarItem alloc] initWithTitle:title image:image selectedImage:selectedImage];    UIViewController *controller = [[self alloc] init];    //这里self代表类本身,因为这是个+方法,出现在+方法中的self代类本身,当然,也可以这样写: [[[self class] alloc] init] autorelease];    controller.tabBarItem = item;    return controller;}@end// -----------------------------------------------@interface RootViewController ()@end@implementation RootViewController- (id)init{    if (self = [super init]) {        [self setUp];    }    return self;}- (void)setUp{    //设置TabBar内容*    NSMutableArray *viewControllers = [NSMutableArray array];    NSArray *array = @[[PhotoViewController class],[AudioViewController class],[VideoViewController class],[ResumeDownloadController class]];    NSArray *titles = @[@"相册",@"音频",@"视频",@"断点续传"];    UIImage *image  = [UIImage imageNamed:@"star@2x.png"];    UIImage *images  = [UIImage imageNamed:@"stared@2x.png"];    NSArray *iconImage = @[image,image,image,image];    NSArray *selectImage = @[images,images,images,images];//图片渲染 ?    for (NSInteger i = 0; i < array.count; i++) {        Class cls = array[i];        UIViewController *controller = [cls viewControllerWithTitle:titles[i] image:iconImage[i] selectedImage:selectImage[i]];//通过我们对UIViewController的扩展方法方便的新建视图控制器对象        [viewControllers addObject:controller];    }    self.viewControllers = viewControllers;}

2. 相册

PhotoViewController.m

/* UIImagePickerController是继承于UINavigationController, 所以它本身是一个导航控制器,不要push它,push导航控制器本身不合理,所以我们一般把它present出来 当我们从系统相册中取出来图片(或者是拍照)的时候,通过代理方法把资源传给我们,所以我们要设置代理并实现代理方法,来获取UIImagePickerController对象给我们的东西,由于UIImagePickerController继承于UINavigationController, 要遵守UINavigationControllerDelegate协议, 不然有警告(其实不理它也没关系)*/#import "PhotoViewController.h"#import <MobileCoreServices/MobileCoreServices.h>//这里面预置一些宏和其他功能 比如kUTTypeImage#import "ImageTool.h"//图片剪裁@interface PhotoViewController ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIActionSheetDelegate>@property (weak, nonatomic) IBOutlet UIImageView *imageView;@end@implementation PhotoViewController- (void)viewDidLoad {    [super viewDidLoad];}//从系统图片库或相册中去图片- (IBAction)getPhotoFromAlbum:(id)sender {    [self loadImagePickerControllerWithSourceType:UIImagePickerControllerSourceTypePhotoLibrary];}//拍照(要真机)- (IBAction)getPhotoFromCamera:(id)sender {    [self loadImagePickerControllerWithSourceType:UIImagePickerControllerSourceTypeCamera];}//给imageView添加一个手势,当点击这个imageView的时候抽发此方法- (IBAction)tapOnImageView:(id)sender {    //菜单栏    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"图片来源" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"相册", @"图片库", @"拍照", nil];    [actionSheet showInView:self.view];}#pragma mark - 调用取图片或是拍照方法*//系统相册取图片或拍照要用UIImagePickerController, 有一个sourceType,这个属性决定是取图片还是拍照- (void)loadImagePickerControllerWithSourceType:(UIImagePickerControllerSourceType)sourceType{    if ([UIImagePickerController isSourceTypeAvailable:sourceType]) {//如果当前机器支持sourceType(比如拍照,模拟器是不支持的)        UIImagePickerController *controller = [[UIImagePickerController alloc] init];        controller.sourceType = sourceType;        controller.allowsEditing = YES;//允许imagePickerController内置编辑功能        controller.delegate = self;        [self presentViewController:controller animated:YES completion:nil];    }}#pragma mark - <UIImagePickerControllerDelegate>//选中了一个资源(choose)- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{    NSLog(@"%@",info);//info存储的就是选中的资源的信息    NSString *mediaType = info[UIImagePickerControllerMediaType];//取选中资源的类型    if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {//如果选中的是图片资源        UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];        //从info中取出图片资源 UIImagePickerControllerEditedImage 编辑后的图片    UIImagePickerControllerOriginalImage 原始图片        self.imageView.image = image;        //图片剪裁*        //[[ImageTool shareTool] resizeImageToSize:CGSizeMake(100, 100) sizeOfImage:image];    }    [picker dismissViewControllerAnimated:YES completion:nil];}//当点击cancel的时候- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{    [picker dismissViewControllerAnimated:YES completion:nil];}#pragma mark - <UIActionSheetDelegate>tap手势 1. (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{    NSLog(@"%ld %@",buttonIndex,[actionSheet buttonTitleAtIndex:buttonIndex]);    switch (buttonIndex) {        case 0://相册        {            [self loadImagePickerControllerWithSourceType:UIImagePickerControllerSourceTypeSavedPhotosAlbum];        }            break;        case 1://图片库        {            [self loadImagePickerControllerWithSourceType:UIImagePickerControllerSourceTypePhotoLibrary];        }            break;        case 2://拍照        {            [self loadImagePickerControllerWithSourceType:UIImagePickerControllerSourceTypeCamera];        }            break;        default:            break;    }}

3. 音频Audio

AudioViewController.m

#import "AudioViewController.h"#import <AVFoundation/AVFoundation.h>#import "ZZLrcParser.h"//歌词解析@interface AudioViewController ()<AVAudioPlayerDelegate>@property (weak, nonatomic) IBOutlet UILabel *lrcLabel;//显示歌词@property (weak, nonatomic) IBOutlet UIProgressView *progressView;@property (weak, nonatomic) IBOutlet UISlider *volumeSlider;//音量@property (nonatomic) AVAudioPlayer *player;//音频播放器,播放本地音乐@property (nonatomic) ZZLrcParser *lrcParser;//歌词解析器对象@property (nonatomic) NSTimer *timer;//定时器@end@implementation AudioViewController- (void)viewDidLoad {    [super viewDidLoad];    [self initLrc];//初始化歌词    [self initPlayer];//初始化播放器}#pragma mark - 初始化歌词- (void)initLrc{    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"北京北京" ofType:@"lrc"];//*在这不要写错后缀    self.lrcParser = [[ZZLrcParser alloc] initWithFilePath:filePath];}#pragma mark - 初始化播放器- (void)initPlayer{    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"北京北京" ofType:@"mp3"];    self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:filePath] error:nil];    self.player.delegate = self;    [self.player prepareToPlay];//准备播放}//播放- (IBAction)play:(id)sender {    [self.player play];//开始播放    if (_timer == nil) {        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES]; // 每隔一小段时间,通过timerAction:方法更新显示的歌词,更新进度条    }    [self.timer setFireDate:[NSDate date]]; // 触发定时器方法,写成[NSDate distantPast]也行}- (void)timerAction:(NSTimer *)timer{    // 1. 更新进度条 player.currentTime当前播放时间 player.duration整个歌曲共占用的时候    self.progressView.progress = self.player.currentTime/self.player.duration;    self.lrcLabel.text = [self.lrcParser lrcByTime:self.player.currentTime];}//暂停- (IBAction)pause:(id)sender {    [self.player pause];    [self.timer setFireDate:[NSDate distantFuture]];//暂停定时器}//停止- (IBAction)stop:(id)sender {    [self.player stop];    self.player.currentTime = 0.0;//播放进度归零    self.progressView.progress = 0.0;//进度条归零    [self.timer invalidate];//定时器置空    self.timer = nil;}//静音 switch- (IBAction)silenceSwitch:(UISwitch *)aSwitch {    self.player.volume =aSwitch.isOn ? 0.0 : self.volumeSlider.value;//条件运算符判断}//声音滑块- (IBAction)volumeSlider:(UISlider *)slider {    self.player.volume = slider.value;//player.volume范围范和默认的slider范围都是[0.0~1.0]}#pragma mark - <AVAudioPlayerDelegate>//当成功播放完成一首歌后,调用方法- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{    NSLog(@"播放完成");}//当系统级别的功能接入(来电话了),播放器被打断时,调用此方法- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{    NSLog(@"来电话播放器被打断");}//当播放器结束被打断,调用该方法 1. (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags{    //继续播放    [self play:nil];}

4. 视频Video

VideoViewController.m

#import "VideoViewController.h"#import <MediaPlayer/MediaPlayer.h>//@interface VideoViewController ()@end@implementation VideoViewController- (void)viewDidLoad {    [super viewDidLoad];}//播放本地视频- (IBAction)playLocalVideo:(id)sender {    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"1" ofType:@"mp4"];    //NSLog(@"%@",filePath);    [self loadMoviePlayWithUrl:filePath];}- (void)loadMoviePlayWithUrl:(NSString *)url {    //MPMoviePlayerViewController 视频播放视图控制器,本身带了一个视图,控制视频的暂停、播放、放大缩小等东西,不可定制    //可以播放本地/服务器上的在线视频    //MPMoviePlayerViewController自带了一个MPMoviePlayerController对象控制视频的播放    NSURL *movieUrl = nil;    if ([url hasPrefix:@"http://"] || [url hasPrefix:@"https://"]) {        movieUrl = [NSURL URLWithString:url];    }else{        movieUrl = [NSURL fileURLWithPath:url];//注意一下,用的是路径    }    MPMoviePlayerViewController *player = [[MPMoviePlayerViewController alloc] initWithContentURL:movieUrl];    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playEnd:) name:MPMoviePlayerPlaybackDidFinishNotification  object:nil]; // 向通知中心注册,当视频播放完成后,回调self的playEnd:方法,视频播放完成后,通知中心发送一个通知给我们(通过playEnd:)    player.moviePlayer.shouldAutoplay = YES;//自动播放    [self presentViewController:player animated:YES completion:nil];}//播放结束- (void)playEnd:(NSNotification *)notification {    // NSLog(@"播放完成");    // NSLog(@"info: %@", notification.userInfo);    // 获取返回的原因    NSInteger type = [notification.userInfo[MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] integerValue];    switch (type) {        case 0:            NSLog(@"正常结束返回");            break;        case 1:            NSLog(@"异常");            break;        case 2:            NSLog(@"点击Done 返回");            break;        default:            break;    }    [[NSNotificationCenter defaultCenter] removeObserver:self];//从通知中心移除}//播放远程视频- (IBAction)palyNetVideo:(id)sender {    [self loadMoviePlayWithUrl:@"http://123.56.117.179:8080/video/ts/lv2.m3u8"];}

5. 断点续传

ResumeDownloadController.m

#import "ResumeDownloadController.h"#import "FileDownload.h"#define URL @"http://dlsw.baidu.com/sw-search-sp/soft/2a/25677/QQ_V4.0.0.1419920162.dmg";@interface ResumeDownloadController ()<FileDownloadDelegate>@property (weak, nonatomic) IBOutlet UIProgressView *progressView;// 进度条@property (weak, nonatomic) IBOutlet UILabel *percentLabel;// 下载百分比@property (nonatomic) FileDownload *downloader;@end@implementation ResumeDownloadController- (void)viewDidLoad {    [super viewDidLoad];}- (FileDownload *)downloader{    if (_downloader == nil) {        _downloader = [[FileDownload alloc] init];        _downloader.urlStr = URL;        _downloader.delegate = self;    }    return _downloader;}//开始下载- (IBAction)start:(id)sender {    [self.downloader start];}//停止下载- (IBAction)stop:(id)sender {    [self.downloader stop];}#pragma mark - <FileDownloadDelegate>- (void)fileDownload:(FileDownload *)downloader failWithError:(NSError *)error {    NSLog(@"%@", error);}- (void)fileDownload:(FileDownload *)downloader downloadSize:(long long)downloadSize totalSize:(long long)totalSize{    //更新进度条    float progress = 1.0 * downloadSize/totalSize;//0.0~1.0    self.progressView.progress = progress;    NSString *str = [NSString stringWithFormat:@"%.2f%%",progress*100];    self.percentLabel.text = str;}- (void)fileDownloadDidFinish:(FileDownload *)downloader {    NSLog(@"Download finish");    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"您已下载完成" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];    [alertView show];    self.progressView.progress = 1.0;    self.percentLabel.text = @"100%";}

5.1 封装下载类

FileDownload.h

#import <Foundation/Foundation.h>@class FileDownload;@protocol FileDownloadDelegate <NSObject>- (void)fileDownload:(FileDownload *)downloader failWithError:(NSError *)error;- (void)fileDownload:(FileDownload *)downloader downloadSize:(long long)downloadSize totalSize:(long long)totalSize; // 每当下载一点数据,通过这个代理方法告诉其他对象- (void)fileDownloadDidFinish:(FileDownload *)downloader;@end@interface FileDownload : NSObject@property (nonatomic, copy) NSString *urlStr;@property (nonatomic, weak) id<FileDownloadDelegate> delegate;- (void)start;// 开始下载- (void)stop;// 停止下载@end

FileDownload.m

#import "FileDownload.h"#import "NSString+util.h"//Md5加密@interface FileDownload ()<NSURLConnectionDataDelegate>@property (nonatomic,copy) NSString *downloadDirPath;// 下载的文件夹路径,这个路径可是指定写死的,也就是说通过ZZFileDownload下载的文件都放在这个文件夹中@property (nonatomic,copy) NSString *filePath;// 文件路径,下载数据写入到filePath中@property (nonatomic) NSFileHandle *writeHandle;// 文件句柄,用它往文件中写入服务器返回过来的数据@property (nonatomic) long long totalFileSize;// 文件总大小@property (nonatomic) long long downloadFileSize;// 当前已下载的文件大小@property (nonatomic) NSURLConnection *connection;// 网络连接类@end@implementation FileDownload// 文件夹路径(指定)- (NSString *)downloadDirPath{    if (_downloadDirPath == nil) {        //获取文件的路径        NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];//取到沙盒里面Document目录        NSString *dirPath = [docPath stringByAppendingPathComponent:@"FileDownload"];//在Document文件夹下存在一个叫ZZFileDownload的文件夹,把我们下载的东西全部放在这个文件夹下,方便管理,        /*         注意:必须写成这样才保证每次运行存储的是同一文件夹的 stringByAppendingPathComponent         */        BOOL flag = [[NSFileManager defaultManager] createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];        if (flag) {            NSLog(@"创建文件夹成功");            _downloadDirPath = dirPath;        }    }    return _downloadDirPath;}//开始下载- (void)start{    if ([self prepareDownload]) {//在向服务器正式下载之前做好准备工作        /*         NSURLConnection实现断点续传 Range头域         Range头域可以请求实体的⼀个或者多个子范围:         表⽰头500个字节:bytes=0-499         表⽰第二个500字节:bytes=500-999         表⽰最后500个字节:bytes=-500         表⽰500字节以后的范围:bytes=500-         第⼀个和最后⼀个字节:bytes=0-0,-1         同时指定⼏个范围:bytes=500-600,601-999         实现断点下载就是在httpRequest中加⼊入 Range 头。         [request addValue:@"bytes=500-" forHTTPHeaderField:@"Range"];         至于能否正常实现断点续传,还要看服务器是否⽀支持。 如果⽀支持,⼀一切没问题。 如果不⽀支持可能出现两种情况,1.不理会你得range值,每次都重         新下载数据;2.直接下载失败。         */        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.urlStr]];        // 重点:设置请求的Range头域,告诉服务器“你给我返回多少多少字节以后的数据”        [request addValue:[NSString stringWithFormat:@"bytes=%llu-", _downloadFileSize] forHTTPHeaderField:@"Range"];        // 注意: @"bytes=%llu-" 中间不能有空格        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];    }}- (BOOL)prepareDownload {    NSLog(@"%@", NSHomeDirectory());// 打印下载的路径,可转为dmg格式的点击同意就可安装    // 1.确保文件存在(根据传过来的urlStr关联文件),如果文件不存在,则创建,并得到文件路径 -> 下载的文件夹/文件名    if (self.urlStr == nil || self.urlStr.length == 0) {        return NO;    }    NSString *fileName = self.urlStr.md5;    NSString *filePath = [self.downloadDirPath stringByAppendingPathComponent:fileName]; // Document/ZZFileDownload/fileName  调这个方法会自动的在gf_list.txt前面加一个/    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath]; // 文件是否存在 判断原来filepath文件是否存在    if (!fileExists) { // 如果不存在,则创建它        /*         // 第一个参数:文件路径(在哪个路径下创建文件)         // 第二个参数:文件创建时给它写入什么内容(NSData *)         // 第三个参数:文件的属性,写为nil用它默认的属性         // 返回值是YES表示创建成功,否则创建失败         // 注意:如果原来文件存在,会把原来文件替换掉,所以一般判断一下原来文件是否已经存在         */        BOOL createSuccess = [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];        if (!createSuccess) {            return NO;        }    }    // 2.根据文件路径获取它的大小    /*     // 获取文件属性     // attributesOfItemAtPath:filePath 返回文件filePath的信息,把这些信息存在一个字典中以键值对的形式返回     error = nil;     NSDictionary *fileInfo = [fileManager attributesOfItemAtPath:filePath error:&error];     NSLog(@"------%@", fileInfo);     NSLog(@"文件大小(以字节为单位):%lld", [fileInfo[NSFileSize] longLongValue]);     // [fileInfo objectForKey:NSFileSize];     // NSFileSize -> key -> 字符串     NSLog(@"获取文件大小方法二(以字节为单位):%lld", [fileInfo fileSize]);     */    _downloadFileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil] fileSize];    // 3.设置写入此文件的文件句柄(等一下要把从服务器上获取的data写入文件中)    /*     // NSFileHandle     // 文件句柄,使用它对文件进行读取,写入,更改     NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath]; // 以只读方式打开文件,不能往里面写入     fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath]; // 以只写方式打开文件,不能读取     fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath]; // 以读写方式打开文件,即可读又可写     */    self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];    return YES;}// 停止下载- (void)stop {    [self.connection cancel], self.connection = nil; // 断开连接    [self.writeHandle closeFile]; // 关闭文件句柄}#pragma mark - <NSURLConnectionDataDelegate>// 失败- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {    if ([self.delegate respondsToSelector:@selector(fileDownload:failWithError:)]) {        [self.delegate fileDownload:self failWithError:error];    }}// 接收到服务器的响应(服务器给我们返回的是响应头信息)// 在每次connection连接只会调用一次该方法- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {    // bytes=500- 获取下载文件的大小expectedContentLength    self.totalFileSize = response.expectedContentLength + self.downloadFileSize;    // 说明我们已经下载完了    if (self.totalFileSize == self.downloadFileSize) {        [self stop];        if ([self.delegate respondsToSelector:@selector(fileDownloadDidFinish:)]) {            [self.delegate fileDownloadDidFinish:self];        }    }}// 接收到服务器返回来的数据(这个方法被调很多次)- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {    //把数据写入文件    [self.writeHandle seekToEndOfFile]; //在文件末尾追加数据    [self.writeHandle writeData:data]; //写入数据    self.downloadFileSize += data.length;    if ([self.delegate respondsToSelector:@selector(fileDownload:downloadSize:totalSize:)]) {        [self.delegate fileDownload:self downloadSize:self.downloadFileSize totalSize:self.totalFileSize];    }}@end

图片剪裁ImageTool.h

#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@interface ImageTool : NSObject// 返回单例的静态方法+ (ImageTool *)shareTool;// 返回特定尺寸的UImage  ,  image参数为原图片,size为要设定的图片大小- (UIImage*)resizeImageToSize:(CGSize)size                 sizeOfImage:(UIImage*)image;// 在指定的视图内进行截屏操作,返回截屏后的图片- (UIImage *)imageWithScreenContentsInView:(UIView *)view;@end

ImageTool.m

#import "ImageTool.h"#import <QuartzCore/QuartzCore.h>@implementation ImageToolstatic ImageTool *_shareImageTool =nil;// 返回单例的静态方法+ (ImageTool *)shareTool{    //确保线程安全    @synchronized(self){        //确保只返回一个实例        if (_shareImageTool == nil) {            _shareImageTool = [[ImageTool alloc] init];        }    }    return _shareImageTool;}- (id)init{    self = [super init];    if (self) {    }    return self;}// 在指定的视图内进行截屏操作,返回截屏后的图片- (UIImage *)imageWithScreenContentsInView:(UIView *)view{    //根据屏幕大小,获取上下文    UIGraphicsBeginImageContext([[UIScreen mainScreen] bounds].size);    [view.layer renderInContext:UIGraphicsGetCurrentContext()];    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();    UIGraphicsEndImageContext();    return viewImage;}- (UIImage*)resizeImageToSize:(CGSize)size                 sizeOfImage:(UIImage*)image{    UIGraphicsBeginImageContext(size);    //获取上下文内容    CGContextRef ctx= UIGraphicsGetCurrentContext();    CGContextTranslateCTM(ctx, 0.0, size.height);    CGContextScaleCTM(ctx, 1.0, -1.0);    //重绘image    CGContextDrawImage(ctx,CGRectMake(0.0f, 0.0f, size.width, size.height), image.CGImage);    //根据指定的size大小得到新的image    UIImage* scaled= UIGraphicsGetImageFromCurrentImageContext();    UIGraphicsEndImageContext();    return scaled;}@end

歌词解析ZZLrcParser.h

#import <Foundation/Foundation.h>@interface ZZLrcItem : NSObject@property (nonatomic) float time;@property (nonatomic, copy) NSString *lrc;- (BOOL)descByTime:(ZZLrcItem *)item;- (void)show;@end// --------------------------------------------------@interface ZZLrcParser : NSObject- (instancetype)initWithFilePath:(NSString *)filePath;@property (nonatomic, copy) NSString *title;    // [ti:歌词(歌曲)标题]@property (nonatomic, copy) NSString *author;  // [ar:歌词作者]@property (nonatomic, copy) NSString *albume;  // [al:歌曲所在唱片集]@property (nonatomic, copy) NSString *editor;  // [by:本LRC文件的创建者]@property (nonatomic, copy) NSString *version; // [ve:歌曲的版本]@property (nonatomic) NSMutableArray *items; // 数组里存放的是一个个ZZLrcItem对象// 给出来时间,我们就知道应该播放哪句歌词- (NSString *)lrcByTime:(float)time;- (void)show;@end

ZZLrcParser.m

#import "ZZLrcParser.h"NSString *const kTitle     = @"ti";NSString *const kAuthor   = @"ar";NSString *const kAlbume   = @"al";NSString *const kEditor   = @"by";NSString *const kVersion = @"ve";@implementation ZZLrcItem- (BOOL)descByTime:(ZZLrcItem *)item {    return self.time > item.time;}- (void)show {    printf("time: %f --> song: %s\n", self.time, [self.lrc UTF8String]);}@end// --------------------------------------------------@implementation ZZLrcParser- (instancetype)initWithFilePath:(NSString *)filePath {    if (self = [super init]) {        self.items = [NSMutableArray array];        NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];        NSArray *array = [content componentsSeparatedByString:@"\n"];        for (NSString  *str in array) {            if (str.length == 0) continue; // @""            unichar c = [str characterAtIndex:1];            if (c <= '9' && c >= '0') {                [self parseTimeString:str]; // 时间歌词            } else {                [self parseFileInfo:str];            }        }    }    return self;}// [02:11.27][01:50.22][00:21.95]穿过幽暗地岁月// [00:06.53]你对自由地向往- (void)parseTimeString:(NSString *)aStr {    NSArray *array = [aStr componentsSeparatedByString:@"]"];    // [02:11.27    // [01:50.22    // [00:21.95    // 穿过幽暗地岁月    NSString *song = [array lastObject];    // 遍历的话不取最后一项(最后一项是歌词项)    for (NSInteger i = 0; i < array.count-1; i++) {        NSString *timeStr = array[i]; // [02:11.27        timeStr = [timeStr substringFromIndex:1]; // 02:11.27        NSArray *arr = [timeStr componentsSeparatedByString:@":"];        NSString *minute = arr[0];        NSString *second = arr[1];        float time = [minute floatValue]*60 + [second floatValue]; // 131.27        ZZLrcItem *item = [[ZZLrcItem alloc] init];        item.time = time; // 131.27        item.lrc = song; // 穿过幽暗地岁月        [_items addObject:item];    }    // 以时间升序排序    [_items sortUsingSelector:@selector(descByTime:)];}- (void)parseFileInfo:(NSString *)aStr {    NSString *newStr = aStr;    newStr = [newStr substringFromIndex:1]; // [ti:蓝莲花] -> ti:蓝莲花]    newStr = [newStr substringToIndex:newStr.length-1]; // ti:蓝莲花    NSArray *arr = [newStr componentsSeparatedByString:@":"];    NSString *type = arr[0]; // ti    NSString *content = arr[1]; // 蓝莲花    if ([type isEqualToString:kTitle]) {        self.title = content;    } else if ([type isEqualToString:kAuthor]) {        self.author = content;    } else if ([type isEqualToString:kAlbume]) {        self.albume = content;    } else if ([type isEqualToString:kEditor]) {        self.author = content;    } else if ([type isEqualToString:kVersion]) {        self.version = content;    }}- (NSString *)lrcByTime:(float)time {    ZZLrcItem *item = [self itemByTime:time];    return item.lrc;}// 找比time稍大的,返回上一条- (ZZLrcItem *)itemByTime:(float)time {    NSInteger index = -100;    for (NSInteger i = 0; i < self.items.count; i++) {        ZZLrcItem *item = self.items[i];        if (item.time > time) { // 找到了比time大一点的项            index = i - 1;            break;        }    }    if (index == -1) { // 播放第一行        index = 0;    } else if (index == -100) { // 播放最后一行        index = _items.count-1;    }    return _items[index];}- (void)show {    [_items makeObjectsPerformSelector:@selector(show)];}/**  * ZZLrcParser {        author,        title,        ...        NSMutableArray *_items; // 数组里存放的是一个修正<ZZLrcItem>对象     } */@end

这里写图片描述
这里写图片描述
这里写图片描述

0 0
原创粉丝点击