QLPreviewController来预览文件

Mac OS系统有一个很方便的功能就是文件预览,在Finder中选中一个文件,按下空格键就能够预览其中的内容。支持图片、文档、视频等类型。在iOS4.0系统中,官方SDK提供了一个QLPreviewController,使用它就可以让我们的App在iPhone/iPad中直接预览各个文件了。官方的开发文档中说明其支持的文件类型有:

  1. iWork文档
  2. 微软Office97以上版本的文档
  3. RTF文档
  4. PDF文件
  5. 图片文件
  6. 文本文件和CSV文件

使用方法也很简单,在Frameworks中添加QuickLook.framework,直接alloc出一个QLPreviewController对象,用presentModalViewController方法把它调出来即可。要指定QLPreviewController预览那个文件,只要直接实现它的代理方法previewItemAtIndex,返回一个NSURL对象即可:

- (id)previewController:(QLPreviewController *)previewController previewItemAtIndex:(NSInteger)idx
{   
return [NSURL fileURLWithPath:[NSString stringWithFormat:@“%@/Documents/files/%@”, NSHomeDirectory(), [fileList objectAtIndex:currentIndex]]];
}


官方程序如下

1.

DITableViewController.h

#import <UIKit/UIKit.h>

#import <QuickLook/QuickLook.h>

 #import "DirectoryWatcher.h"

 @interface DITableViewController : UITableViewController <QLPreviewControllerDataSource,

                                                          QLPreviewControllerDelegate,

                                                          DirectoryWatcherDelegate,

                                                          UIDocumentInteractionControllerDelegate> {

 

    DirectoryWatcher *docWatcher;

    NSMutableArray *documentURLs;

    UIDocumentInteractionController *docInteractionController;

}

 @property (nonatomic, retain) DirectoryWatcher *docWatcher;

@property (nonatomic, retain) NSMutableArray *documentURLs;

@property (nonatomic, retain) UIDocumentInteractionController *docInteractionController;

@end

DITableViewController.m文件

#import "DITableViewController.h"

@interface DITableViewController (private)

- (NSString *)applicationDocumentsDirectory;

@end

 static NSString* documents[] =

    {   @"Text Document.txt",

        @"Image Document.jpg",

        @"PDF Document.pdf",

        @"HTML Document.html"

    };

#define NUM_DOCS 4

#define kRowHeight 58.0f

@implementation DITableViewController

 @synthesize docWatcher, documentURLs, docInteractionController;

#pragma mark -

#pragma mark View Controller

 - (void)setupDocumentControllerWithURL:(NSURL *)url

{

    if (self.docInteractionController == nil)

    {

        self.docInteractionController = [UIDocumentInteractionControllerinteractionControllerWithURL:url];

        self.docInteractionController.delegate = self;

    }

    else

    {

        self.docInteractionController.URL = url;

    }

}

- (void)viewDidLoad {

    [superviewDidLoad];

        // start monitoring the document directory…

    self.docWatcher = [DirectoryWatcherwatchFolderWithPath:[selfapplicationDocumentsDirectory] delegate:self];

    self.documentURLs = [NSMutableArrayarray];

    // scan for existing documents

    [selfdirectoryDidChange:self.docWatcher];

}

 - (void)viewDidUnload {

    self.documentURLs = nil;

    self.docWatcher = nil;

}

 - (void)dealloc {

    [documentURLsrelease];

    [docWatcherrelease];

    [super dealloc];

}

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation

{

    returnYES;

}

 #pragma mark -

#pragma mark UITableViewDataSource

 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

{

    return 2;

}

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

    if (section == 0)

    {

        return NUM_DOCS;

    }

    else

    {

        return self.documentURLs.count;

    }

}

 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

{

    NSString *title = nil;

    if (section == 0)

        title = @"Example Documents";

    else

    {

        if (self.documentURLs.count > 0)

            title = @"Documents folder";

    }

    return title;

}

- (NSString *)formattedFileSize:(unsigned long long)size

{

NSString *formattedStr = nil;

    if (size == 0) 

formattedStr = @"Empty";

else 

if (size > 0 && size < 1024) 

formattedStr = [NSString stringWithFormat:@"%qu bytes", size];

        else 

            if (size >= 1024 && size < pow(1024, 2)) 

                formattedStr = [NSString stringWithFormat:@"%.1f KB", (size / 1024.)];

            else 

                if (size >= pow(1024, 2) && size < pow(1024, 3))

                    formattedStr = [NSString stringWithFormat:@"%.2f MB", (size / pow(1024, 2))];

                else 

                    if (size >= pow(1024, 3)) 

                        formattedStr = [NSString stringWithFormat:@"%.3f GB", (size / pow(1024, 3))];

 

return formattedStr;

}

// if we installed a custom UIGestureRecognizer (i.e. long-hold), then this would be called

- (void)handleLongPress:(UILongPressGestureRecognizer *)longPressGesture

{

    if (longPressGesture.state == UIGestureRecognizerStateBegan)

    {

        NSIndexPath *cellIndexPath = [self.tableView indexPathForRowAtPoint:[longPressGesture locationInView:self.tableView]];

 

NSURL *fileURL;

if (cellIndexPath.section == 0)

fileURL = [NSURLfileURLWithPath:[[NSBundlemainBundle] pathForResource:documents[cellIndexPath.row] ofType:nil]];

else

fileURL = [self.documentURLs objectAtIndex:cellIndexPath.row];

self.docInteractionController.URL = fileURL;

 

[self.docInteractionControllerpresentOptionsMenuFromRect:longPressGesture.view.frame

                                                           inView:longPressGesture.view

                                                         animated:YES];

    }

}

- (UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    static NSString *cellIdentifier = @"cellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

       if (!cell)

    {

        cell = [[[UITableViewCellalloc] initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:cellIdentifier] autorelease];

        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

    }

     NSURL *fileURL;

    if (indexPath.section == 0)

    {

        // first section is our build-in documents

    fileURL = [NSURLfileURLWithPath:[[NSBundlemainBundle] pathForResource:documents[indexPath.row] ofType:nil]];

    }

    else

    {

        // second section is the contents of the Documents folder

fileURL = [self.documentURLs objectAtIndex:indexPath.row];

    }

[selfsetupDocumentControllerWithURL:fileURL];

    // layout the cell

    cell.textLabel.text = [[fileURL path] lastPathComponent];

    NSInteger iconCount = [docInteractionController.iconscount];

    if (iconCount > 0)

    {

        cell.imageView.image = [docInteractionController.icons objectAtIndex:iconCount - 1];

    }

    NSError *error;

    NSString *fileURLString = [self.docInteractionController.URL path];

    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fileURLString error:&error];

    NSInteger fileSize = [[fileAttributes objectForKey:NSFileSize] intValue];

    cell.detailTextLabel.text = [NSStringstringWithFormat:@"%@ - %@",

                                 [self formattedFileSize:fileSize], docInteractionController.UTI];

     // attach to our view any gesture recognizers that the UIDocumentInteractionController provides

    //cell.imageView.userInteractionEnabled = YES;

    //cell.contentView.gestureRecognizers = self.docInteractionController.gestureRecognizers;

    //

    // or

    // add a custom gesture recognizer in lieu of using the canned ones

    UILongPressGestureRecognizer *longPressGesture =

    [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];

    [cell.imageView addGestureRecognizer:longPressGesture];

    cell.imageView.userInteractionEnabled = YES;    // this is by default NO, so we need to turn it on

    [longPressGesture release];

     return cell;

}

 - (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{

    returnkRowHeight;

}

 #pragma mark -

#pragma mark UITableView delegate

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

    // three ways to present a preview:

    // 1. Don't implement this method and simply attach the canned gestureRecognizers to the cell

    //

    // 2. Don't use canned gesture recognizers and simply use UIDocumentInteractionController's

    //      presentPreviewAnimated: to get a preview for the document associated with this cell

    //

    // 3. Use the QLPreviewController to give the user preview access to the document associated

    //      with this cell and all the other documents as well.

    

    // for case 2 use this, allowing UIDocumentInteractionController to handle the preview:

    /*

    NSURL *fileURL;

    if (indexPath.section == 0)

    {

        fileURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:documents[indexPath.row] ofType:nil]];

    }

    else

    {

        fileURL = [self.documentURLs objectAtIndex:indexPath.row];

    }

    [self setupDocumentControllerWithURL:fileURL];

    [self.docInteractionController presentPreviewAnimated:YES];

    */

    // for case 3 we use the QuickLook APIs directly to preview the document -

    QLPreviewController *previewController = [[QLPreviewControlleralloc] init];

    previewController.dataSource = self;

    previewController.delegate = self;

    // start previewing the document at the current section index

    previewController.currentPreviewItemIndex = indexPath.row;

    [[selfnavigationController] pushViewController:previewController animated:YES];

    [previewController release];

}

 #pragma mark -

#pragma mark UIDocumentInteractionControllerDelegate

 - (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)interactionController

{

    returnself;

}

 #pragma mark -

#pragma mark QLPreviewControllerDataSource

 

// Returns the number of items that the preview controller should preview

- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)previewController

{

    NSInteger numToPreview = 0;

    NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];

    if (selectedIndexPath.section == 0)

        numToPreview = NUM_DOCS;

    else

        numToPreview = self.documentURLs.count;

     return numToPreview;

}

 - (void)previewControllerDidDismiss:(QLPreviewController *)controller

{

    // if the preview dismissed (done button touched), use this method to post-process previews

}

 // returns the item that the preview controller should preview

- (id)previewController:(QLPreviewController *)previewController previewItemAtIndex:(NSInteger)idx

{

    NSURL *fileURL = nil;

    NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];

    if (selectedIndexPath.section == 0)

    {

        fileURL = [NSURLfileURLWithPath:[[NSBundlemainBundle] pathForResource:documents[idx] ofType:nil]];

        //fileURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://vr.tudou.com/v2proxy/v2.m3u8?it=5903919&st=2"]];//http://www.tudou.com/programs/view/R-FTzWszxS0/?resourceId=0_06_02_99?fr=2

    }

    else

    {

        fileURL = [self.documentURLs objectAtIndex:idx];

    }

    return fileURL;

}

 #pragma mark -

#pragma mark File system support

 - (NSString *)applicationDocumentsDirectory

{

return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

}

 - (void)directoryDidChange:(DirectoryWatcher *)folderWatcher {

[self.documentURLsremoveAllObjects];    // clear out the old docs and start over

 NSString *documentsDirectoryPath = [self applicationDocumentsDirectory];

 NSArray *documentsDirectoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectoryPath error:NULL];

 for (NSString* curFileName in [documentsDirectoryContents objectEnumerator]) {

 

NSString *filePath = [documentsDirectoryPath stringByAppendingPathComponent:curFileName];

NSURL *fileURL = [NSURL fileURLWithPath:filePath];

BOOL isDirectory;

        [[NSFileManagerdefaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory];

         // proceed to add the document URL to our list (ignore the "Inbox" folder)

        if (!(isDirectory && [curFileName isEqualToString: @"Inbox"]))

        {

            [self.documentURLs addObject:fileURL];

        }

}

[self.tableViewreloadData];

}

@end

 

2.

DirectoryWatcher.h 文件

#import <Foundation/Foundation.h>

 @classDirectoryWatcher;

 @protocol DirectoryWatcherDelegate <NSObject>

@required

- (void)directoryDidChange:(DirectoryWatcher *)folderWatcher;

@end

 @interface DirectoryWatcher : NSObject  {

 

id <DirectoryWatcherDelegate> delegate;

    int dirFD;

    int kq;

    CFFileDescriptorRef dirKQRef;

}

@property (nonatomic, assign) id <DirectoryWatcherDelegate> delegate;

 + (DirectoryWatcher *)watchFolderWithPath:(NSString *)watchPath delegate:(id<DirectoryWatcherDelegate>)watchDelegate;

- (void)invalidate;

@end

DirectoryWatcher.m 文件

#import "DirectoryWatcher.h"

 #include <sys/types.h>

#include <sys/event.h>

#include <sys/time.h>

#include <fcntl.h>

#include <unistd.h>

 #import <CoreFoundation/CoreFoundation.h>

 @interface DirectoryWatcher (DirectoryWatcherPrivate)

- (BOOL)startMonitoringDirectory:(NSString *)dirPath;

- (void)kqueueFired;

@end

 #pragma mark -

 @implementation DirectoryWatcher

 @synthesize delegate;

 - (id)init {

self= [superinit];

delegate = NULL;

 dirFD = -1;

    kq = -1;

dirKQRef = NULL;

 returnself;

}

 - (void)dealloc {

[selfinvalidate];

[superdealloc];

}

 + (DirectoryWatcher *)watchFolderWithPath:(NSString *)watchPath delegate:(id)watchDelegate {

DirectoryWatcher *retVal = NULL;

if ((watchDelegate != NULL) && (watchPath != NULL)) {

DirectoryWatcher *tempManager = [[[DirectoryWatcheralloc] init] autorelease];

tempManager.delegate = watchDelegate;

if ([tempManager startMonitoringDirectory: watchPath]) {

// Everything appears to be in order, so return the DirectoryWatcher.  

// Otherwise we'll fall through and return NULL.

retVal = tempManager;

}

}

return retVal;

}

 - (void)invalidate {

if (dirKQRef != NULL) {

CFFileDescriptorInvalidate(dirKQRef);

CFRelease(dirKQRef);

dirKQRef = NULL;

// We don't need to close the kq, CFFileDescriptorInvalidate closed it instead.

// Change the value so no one thinks it's still live.

kq = -1;

}

if(dirFD != -1) {

close(dirFD);

dirFD = -1;

}

}

@end

 #pragma mark -

 @implementation DirectoryWatcher (DirectoryWatcherPrivate)

 - (void)kqueueFired {

    assert(kq >= 0);

    struct kevent   event;

    struct timespec timeout = {0, 0};

    int             eventCount;

    eventCount = kevent(kq, NULL, 0, &event, 1, &timeout);

    assert((eventCount >= 0) && (eventCount < 2));

    // call our delegate of the directory change

    [delegatedirectoryDidChange:self];

    CFFileDescriptorEnableCallBacks(dirKQRef, kCFFileDescriptorReadCallBack);

}

 static void KQCallback(CFFileDescriptorRef kqRef, CFOptionFlags callBackTypes, void *info) {

    DirectoryWatcher *obj;

    obj = (DirectoryWatcher *)info;

    assert([obj isKindOfClass:[DirectoryWatcherclass]]);

    assert(kqRef == obj->dirKQRef);

    assert(callBackTypes == kCFFileDescriptorReadCallBack);

  [obj kqueueFired];

}

 - (BOOL)startMonitoringDirectory:(NSString *)dirPath {

// Double initializing is not going to work...

if ((dirKQRef == NULL) && (dirFD == -1) && (kq == -1)) {

// Open the directory we're going to watch

dirFD = open([dirPath fileSystemRepresentation], O_EVTONLY);

if (dirFD >= 0) {

// Create a kqueue for our event messages...

kq = kqueue();

if (kq >= 0) {

struct kevent eventToAdd;

eventToAdd.ident  = dirFD;

eventToAdd.filter = EVFILT_VNODE;

eventToAdd.flags  = EV_ADD | EV_CLEAR;

eventToAdd.fflags = NOTE_WRITE;

eventToAdd.data   = 0;

eventToAdd.udata  = NULL;

 int errNum = kevent(kq, &eventToAdd, 1, NULL, 0, NULL);

if (errNum == 0) {

CFFileDescriptorContext context = { 0, self, NULL, NULL, NULL };

CFRunLoopSourceRef      rls;

 // Passing true in the third argument so CFFileDescriptorInvalidate will close kq.

dirKQRef = CFFileDescriptorCreate(NULL, kq, true, KQCallback, &context);

if (dirKQRef != NULL) {

rls = CFFileDescriptorCreateRunLoopSource(NULL, dirKQRef, 0);

if (rls != NULL) {

CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);

CFRelease(rls);

CFFileDescriptorEnableCallBacks(dirKQRef, kCFFileDescriptorReadCallBack);

 // If everything worked, return early and bypass shutting things down

return YES;

}

// Couldn't create a runloop source, invalidate and release the CFFileDescriptorRef

CFFileDescriptorInvalidate(dirKQRef);

                        CFRelease(dirKQRef);

dirKQRef = NULL;

}

}

// kq is active, but something failed, close the handle...

close(kq);

kq = -1;

}

// file handle is open, but something failed, close the handle...

close(dirFD);

dirFD = -1;

}

}

returnNO;

}

@end

 

posted on 2012-12-17 10:47  一梦浮生2012  阅读(1994)  评论(0编辑  收藏  举报