I try to show with QlPreviewController a pdf from internet url without download it.
This is my code:
NSURL* url2 = [NSURL URLWithString:#"http://wwww.myweb.com/files/terms_en.pdf"];
// Check if can be shown
if(![QLPreviewController canPreviewItem:url2]) {
// cant show document
NSLog(#"can't show document");
}else {
NSLog(#"can show document");
// Show the document in preview
// _previewItemURL = url;
QLPreviewController* preview = [[QLPreviewController alloc] init];
[preview setDataSource:url2];
}
But it didn't show anything. In addition I have a warning in the last sentence [preview setDataSource:url2] saying 'Sending 'NSURL *_strong' to parameter of incompatible type 'id
As per the documentation, QLPreviewController requires NSFileURL, i.e. local files. Download your web resource with other means (e.g. NSData dataWithContentsOfURL), write to disk, and then feed the local URL to it.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
QLPreviewController *previewController = [[QLPreviewController alloc] init];
[previewController setDataSource:self];
[previewController setDelegate:self];
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
}
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller
{
return [self.arrayForPDFList count];
}
- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
NSString *pathForPdf =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
pathForPdf = [pathForPdf stringByAppendingFormat:#"/%#.pdf",[self.arrayForPDFList objectAtIndex:index]];
return [NSURL URLWithString:pathForPdf];
}
Related
I am having an interesting little problem using the uiimagepickercontroller and was wondering if anyone has any insight as to what might be happening. Users can take pictures with the camera or pick from the photo library until the cows come home as many times in a row as they like. My issue lies in allowing users to revert back to the original image that shipped with the app. Here is the flow:
Users go the the tableview which shows a thumbnail of the image.
Users navigate to the detail view which shows a larger view of the image.
Users can tap on the image in the detail view to bring up a custom alertcontroller with options to a) use the camera to take a picture, b) use a picture from their library, or c) revert back to the original image.
Users choose either option 'a' or option 'b' to either take a picture or use a picture from the photo library. IF they IMMEDIATELY change their mind about using one of those choices and want to just go back to using the original image, nothing happens! They can snap another picture or choose another image right away, but cannot revert back to the original image right away.
Reverting back to the original image DOES work perfectly when the app has been closed and then opened again. Sometimes it will work if you navigate around to other views within the app and then come back to the detail view where they just added their own image. By why the delay? I've searched around for two weeks but have not found anything resembling my problem or any solutions that help in any way (like reloading the headerview where image is sitting). Any thoughts?
Also I have figured out how to save the image to iCloud by using the documentation but cannot figure out how to retrieve them so there is no code for that. That is entirely different question. The same thing seems to occur even without that code.
Thanks for taking the time to look at this!
Here is some code:
-(void)bookImageTapped:(UIGestureRecognizer *)gesture
{
URBAlertView *changeImageAlertView = [[URBAlertView alloc] initWithTitle:#"Add A New Book Cover Image" message:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"Use Camera", #"Open Gallery", #"Use Original Photo", nil];
[changeImageAlertView setHandlerBlock:^(NSInteger buttonIndex, URBAlertView *alertView) {
[self checkPermission];
if (PHAuthorizationStatusAuthorized)
{
if(buttonIndex == 0)
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
pickerController.delegate = self;
pickerController.allowsEditing = NO;
pickerController.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
[self presentViewController:pickerController animated:YES completion:nil];
}];
[alertView hide];
}
else
{
NSLog(#"Camera not available");
[alertView hide];
}
}
else if (buttonIndex == 1)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
pickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
pickerController.delegate = self;
pickerController.allowsEditing = NO;
pickerController.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
[self presentViewController:pickerController animated:YES completion:nil];
}];
[alertView hide];
}
else if (buttonIndex == 2)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self restoreOriginalPhoto];
}];
[alertView hide];
}
else
{
NSLog(#"button 2 cancel");
[alertView hide];
}
}
}];
[changeImageAlertView show];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary<NSString *,id> *)info
{
[picker dismissViewControllerAnimated:YES completion:nil];
_book.largeBookImage = [info objectForKey:UIImagePickerControllerOriginalImage];
_book.largeBookImage = [self scaleImage:_book.largeBookImage toSize:CGSizeMake(120, 168)];
_bookImageView.image = _book.largeBookImage;
_book.wasNewImageAdded = YES;
_book.originalImageUsed = NO;
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:_book.largeBookImage withFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
-(void)saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath
{
if ([[extension lowercaseString] isEqualToString:#"png"])
{
[UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"png"]] options:NSAtomicWrite error:nil];
//Create a URL to the local file
NSURL *resourceURL = [NSURL fileURLWithPath:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"png"]]];
if (resourceURL)
{
CKAsset *asset = [[CKAsset alloc] initWithFileURL:resourceURL];
//create a record object
CKRecord *bookCover = [[CKRecord alloc] initWithRecordType:#"Bookcover"];
//set the record's fields
bookCover[#"title"] = _book.title;
bookCover[#"bookImage"] = asset;
/* TO SAVE A RECORD */
//get the public database
CKContainer *appContainer = [CKContainer defaultContainer];
CKDatabase *publicDatabase = [appContainer publicCloudDatabase];
[publicDatabase saveRecord:bookCover completionHandler:^(CKRecord *bookCover, NSError *error) {
if (error)
{
//insert error handling
return;
}
//insert succesfully saved record code
NSLog(#"png record saved after using picker!");
}];
}
}
else if ([[extension lowercaseString] isEqualToString:#"jpg"] || [[extension lowercaseString] isEqualToString:#"jpeg"])
{
[UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"jpg"]] options:NSAtomicWrite error:nil];
//Create a URL to the local file
NSURL *resourceURL = [NSURL fileURLWithPath:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"jpg"]]];
if (resourceURL)
{
CKAsset *asset = [[CKAsset alloc] initWithFileURL:resourceURL];
//create a record object
CKRecord *bookCover = [[CKRecord alloc] initWithRecordType:#"Bookcover"];
//set the record's fields
bookCover[#"title"] = _book.title;
bookCover[#"bookImage"] = asset;
/* TO SAVE A RECORD */
//get the public database
CKContainer *appContainer = [CKContainer defaultContainer];
CKDatabase *publicDatabase = [appContainer publicCloudDatabase];
[publicDatabase saveRecord:bookCover completionHandler:^(CKRecord *bookCover, NSError *error) {
if (error)
{
//insert error handling
return;
}
//insert succesfully saved record code
NSLog(#"jpg record saved after using picker!");
}];
}
}
else
{
NSLog(#"Image Save Failed\nExtension: (%#) is not recognized, use (PNG/JPG)", extension);
}
}
- (UIImage *) scaleImage:(UIImage*)image toSize:(CGSize)newSize
{
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
-(void)restoreOriginalPhoto
{
NSLog(#"restore photo called");
_book.originalImageUsed = YES;
_book.wasNewImageAdded = NO;
_bookImageView.image = _book.largeBookImage;
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:_book.largeBookImage withFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
}
Here is the headerview with the imageview:
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
_headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 26)];
_headerView.backgroundColor = [UIColor colorWithRed:8/255.0 green:46/255.0 blue:46/255.0 alpha:0.8];
if (section == 0)
{
_headerView.backgroundColor = [UIColor whiteColor];
_bookImageView = [[UIImageView alloc] initWithFrame:CGRectMake((tableView.frame.size.width - 120)/2, 6, 120, 168)];
_bookImageView.contentMode = UIViewContentModeScaleAspectFit;
if (_book.wasNewImageAdded)
{
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
_bookImageView.image = image;
}
else
{
_bookImageView.image = _book.largeBookImage;
}
if(_book.originalImageUsed)
{
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
_bookImageView.image = image;
}
UITapGestureRecognizer *bookImageTouched = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(bookImageTapped:)];
bookImageTouched.numberOfTapsRequired = 1;
[_bookImageView addGestureRecognizer:bookImageTouched];
_bookImageView.userInteractionEnabled = YES;
[_headerView addSubview:_bookImageView];
}
I finally figured it out! It seems that I was confusing xcode with my property names. The code ended up much simpler in the end.
In didFinishPickingMediaWithInfo I created a UIImage and then set it to the bookImageView.image. Later, when I wanted to be able to update the image back to the original image, then I could call the bundle asset, _book.largeBookImage. Voila! The image was able to update immediately.
The most pertinent code is posted below.
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary<NSString *,id> *)info
{
[picker dismissViewControllerAnimated:YES completion:nil];
_chosenImage = [[UIImage alloc] init];
_chosenImage = [info objectForKey:UIImagePickerControllerOriginalImage];
_bookImageView.image = _chosenImage;
_book.wasNewImageAdded = YES;
_book.originalImageUsed = NO;
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:_chosenImage withFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
}
-(void)saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath
{
if ([[extension lowercaseString] isEqualToString:#"png"])
{
[UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"png"]] options:NSAtomicWrite error:nil];
[self.tableView reloadData];
}
else if ([[extension lowercaseString] isEqualToString:#"jpg"] || [[extension lowercaseString] isEqualToString:#"jpeg"])
{
[UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"jpg"]] options:NSAtomicWrite error:nil];
[self.tableView reloadData];
}
else
{
//NSLog(#"Image Save Failed\nExtension: (%#) is not recognized, use (PNG/JPG)", extension);
}
}
-(void)restoreOriginalPhoto
{
_book.originalImageUsed = YES;
_book.wasNewImageAdded = NO;
_bookImageView.image = _book.largeBookImage;
_backgroundImage.image = _book.largeBookImage;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section == 0)
{
_bookImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 120, 168)];
_bookImageView.contentMode = UIViewContentModeScaleAspectFit;
_bookImageView.clipsToBounds = YES;
_bookImageView.layer.cornerRadius = 10.0f;
if (_book.wasNewImageAdded)
{
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
_bookImageView.image = image;
}
else
{
_bookImageView.image = _book.largeBookImage;
}
if(_book.originalImageUsed)
{
_bookImageView.image = _book.largeBookImage;
}
}
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(_book.originalImageUsed)
{
_bookImageView.image = _book.largeBookImage;
}
[self.tableView reloadData];
[self.tableView setContentOffset:CGPointZero animated:NO];
}
Is there any way I can show Open With or Open In window for ms office files I have seen UIDocumentInteractionController and QuickLook Framework but didn't work me. Does these two really support office files?
Quicklook must work
{
QLPreviewController *previewer = [[QLPreviewController alloc] init];
previewer.dataSource = datasource;
previewer.currentPreviewItemIndex = 0;
NSURL *urlFilePath = [[NSBundle mainBundle] URLForResource:#"name" withExtension:#"pdf"];
[self presentViewController:previewer animated:YES completion:nil];
}
-(NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller
{
return 1;
}
- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
return urlFilePath;
}
where urlFilePath is file path url.
First of all Add "QuickLook.framework" to your project.
Its part of the iOS SDK frameworks.
Get the names of all files present in document directory in listOfFilesPresentInDocumentDirectory NSArray which is defined as the class variable.
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
listOfFilesPresentInDocumentDirectory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentDirectory error:NULL];
Create an object of QLPreviewController, set self as its datasource, set its currentPreviewItemIndex and push it to the UINavigationController
QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.currentPreviewItemIndex = indexPath.row;
[[self navigationController] pushViewController:previewController animated:YES];
Implement QLPreviewControllerDataSource protocol in you class’s definition and add following two QLPreviewControllerDataSource functions in the implementation block of your class
pragma mark - QLPreviewControllerDataSource Methods
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller{
return [listOfFilesPresentInDocumentDirectory count];
}
- (id)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
NSURL *fileURL = nil;
NSString *fileName = [listOfFilesPresentInDocumentDirectory objectAtIndex:index];
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
NSString *previewFileFullPath = [documentDirectory stringByAppendingPathComponent:fileName];
fileURL = [NSURL fileURLWithPath:previewFileFullPath];
return fileURL;
}
I have code to show a document as follows:
documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:self.thisUrl];
NSString *pathExtension = [self.thisUrl pathExtension];
if (pathExtension) {
NSString *UTI = (__bridge NSString*)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)(pathExtension), NULL);
if (UTI) {
documentInteractionController.UTI = UTI;
}
}
documentInteractionController.delegate = self;
[documentInteractionController presentOptionsMenuFromBarButtonItem:shareButton animated:YES];
When the options menu is displayed, it shows a list of apps that can open the document (e.g. Message), along with a list of actions below.
The options menu shows a list actions that is different from the menu shown in e.g., the Mail app.
The main difference is that the Mail app shows a "print" option, while my options menu does not. How do I get the options menu to show the print option?
EDIT:
I did a further test where I implemented the methods:
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller canPerformAction:(SEL)action
{
return YES;
}
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller performAction:(SEL)action
{
return YES; // or NO, doesn't matter
}
This had the effect of showing the "print", "copy" and "save to camera roll" actions in the popup view. Nothing happened when I tapped them, probably because I didn't properly implement -performAction. I also get a warning in the console log about using legacy methods.
This was a step backwards in some ways because I could no longer print some documents which were able to print correctly with the document interaction controller before I added those methods.
Apple encourage you to use UIActivityViewController. You can easily achieve this with that. However Print option is available only if your sharing content type supports printing. You can see a list of supported activities by data types here
- (IBAction)shareButton:(UIBarButtonItem *)sender
{
NSString *textToShare = #"Text to share";
NSURL *myWebContent = [NSURL URLWithString:#"http://yourpath.com/yourfile.pdf"]; // set your printable file here!
NSData *myData = [NSData dataWithContentsOfURL:myWebContent];
NSArray *objectsToShare = #[textToShare, myData];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil];
//Add exclusions here
NSArray *excludeActivities = #[UIActivityTypeAirDrop,
UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAddToReadingList,
UIActivityTypePostToFlickr,
UIActivityTypePostToVimeo];
activityVC.excludedActivityTypes = excludeActivities;
[self presentViewController:activityVC animated:YES completion:nil];
}
I got this working using the QuickLook framework. I don't know why the "print" option sometimes doesn't appear for the document interaction controller, but then again, apparantly noone else does either.
The QuickLook framework supports previewing some document types but not all, so I left in my previous view controller and the document interaction controller for those unsupported types.
Below is a snippet of my working code.
#interface PreviewItemDataSource ()
#property (nonatomic, retain) NSURL* item;
#end
#implementation PreviewItemDataSource
#synthesize item=_item;
+(PreviewItemDataSource*)dataSourceWithItem:(NSURL*)item
{
PreviewItemDataSource *source = [[PreviewItemDataSource alloc] init];
source.item = item;
return source;
}
-(NSInteger) numberOfPreviewItemsInPreviewController:(QLPreviewController*)controller {
return 1;
}
- (id<QLPreviewItem>) previewController:(QLPreviewController*)controller previewItemAtIndex:(NSInteger)index {
return self.item;
}
#end
#interface AppDelegate ()
#property (nonatomic, retain) PreviewItemDataSource *dataSource;
#end
...
-(void) openExternalFile:(NSString*) filePath withDelegate:(id<ChildBrowserDelegate>)delegate
{
if ([filePath length] == 0)
return;
NSURL *item = [NSURL URLWithString:filePath];
if (item && [QLPreviewController canPreviewItem:item]) {
[self openQuickLookForItem:item];
} else {
// previous method unchanged
}
}
- (void) openQuickLookForItem:(NSURL*)item {
QLPreviewController *controller = [[QLPreviewController alloc] init];
PreviewItemDataSource *dataSource = [PreviewItemDataSource dataSourceWithItem:item];
controller.dataSource = dataSource;
controller.modalPresentationStyle = UIModalPresentationFullScreen;
[controller setCurrentPreviewItemIndex:0];
[self.viewController presentViewController:controller animated:YES completion:nil];
self.dataSource = dataSource;
}
In my project I'm using WSAssetPickerController.
Despite the toolbar not working (not a huge issue), everything is working fine.
I have added a share button in the view controller, but I can't seem to get the UIDocumentInteractionController to get called, I tried copying the same method I'm using for files saved in the apps folder (which works fine). But here it's not.
How the irrelevant Downloads page works:
NSString *fileName = [directoryContents objectAtIndex:indexPath.row];
NSString *path;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Downloads"];
path = [path stringByAppendingPathComponent:fileName];
documentController = [[UIDocumentInteractionController alloc] init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
[documentController setDelegate:self];
[documentController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
How the images get loaded:
#pragma mark - Fetching Code
- (void)fetchAssets
{
// TODO: Listen to ALAssetsLibrary changes in order to update the library if it changes.
// (e.g. if user closes, opens Photos and deletes/takes a photo, we'll get out of range/other error when they come back.
// IDEA: Perhaps the best solution, since this is a modal controller, is to close the modal controller.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.assetsGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (!result || index == NSNotFound) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
self.navigationItem.title = [NSString stringWithFormat:#"%#", [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName]];
});
return;
}
WSAssetWrapper *assetWrapper = [[WSAssetWrapper alloc] initWithAsset:result];
dispatch_async(dispatch_get_main_queue(), ^{
[self.fetchedAssets addObject:assetWrapper];
});
}];
});
[self.tableView performSelector:#selector(reloadData) withObject:nil afterDelay:0.5];
}
How I load and call the button:
- (void)viewDidLoad
{
self.navigationItem.title = #"Loading";
UIBarButtonItem *shareButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAction
target:self
action:#selector(shareAction:)];
self.navigationItem.rightBarButtonItem = shareButton;
self.navigationItem.rightBarButtonItem.enabled = NO;
// TableView configuration.
self.tableView.contentInset = TABLEVIEW_INSETS;
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.allowsSelection = NO;
// Fetch the assets.
[self fetchAssets];
}
Should and did select fetched assets
#pragma mark - WSAssetsTableViewCellDelegate Methods
- (BOOL)assetsTableViewCell:(WSAssetsTableViewCell *)cell shouldSelectAssetAtColumn:(NSUInteger)column
{
BOOL shouldSelectAsset = (self.assetPickerState.selectionLimit == 0 ||
(self.assetPickerState.selectedCount < self.assetPickerState.selectionLimit));
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
NSUInteger assetIndex = indexPath.row * self.assetsPerRow + column;
WSAssetWrapper *assetWrapper = [self.fetchedAssets objectAtIndex:assetIndex];
if ((shouldSelectAsset == NO) && (assetWrapper.isSelected == NO))
self.assetPickerState.state = WSAssetPickerStateSelectionLimitReached;
else
self.assetPickerState.state = WSAssetPickerStatePickingAssets;
return shouldSelectAsset;
}
- (void)assetsTableViewCell:(WSAssetsTableViewCell *)cell didSelectAsset:(BOOL)selected atColumn:(NSUInteger)column
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
// Calculate the index of the corresponding asset.
NSUInteger assetIndex = indexPath.row * self.assetsPerRow + column;
WSAssetWrapper *assetWrapper = [self.fetchedAssets objectAtIndex:assetIndex];
assetWrapper.selected = selected;
// Update the state object's selectedAssets.
[self.assetPickerState changeSelectionState:selected forAsset:assetWrapper.asset];
// Update navigation bar with selected count and limit variables
dispatch_async(dispatch_get_main_queue(), ^{
if (self.assetPickerState.selectionLimit) {
self.navigationItem.title = [NSString stringWithFormat:#"%# (%lu/%ld)", [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName], (unsigned long)self.assetPickerState.selectedCount, (long)self.assetPickerState.selectionLimit];
}
});
if (self.assetPickerState.selectedCount == 0) {
self.navigationItem.rightBarButtonItem.enabled = NO;
}
else {
self.navigationItem.rightBarButtonItem.enabled = YES;
}
}
Work needed to below with example from the download code I have used before.
-(void)shareAction:(id)sender {
//Launch UIDocumentInteractionController for selected images
documentController =[[UIDocumentInteractionController alloc]init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath://Code needed here??//]];
documentController.delegate=self;
[documentController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
}
What would be the best practice to do this?
Thanks.
UPDATE 8/4:
-(void)shareAction:(id)sender {
//Launch UIDocumentInteractionController for selected images
if (self.assetPickerState.selectedCount >= 1) {
documentController = [[UIDocumentInteractionController alloc] init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:#"public.image"]];
[documentController setDelegate:self];
[documentController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES];
}
}
Returns: Unable to get data for URL: The operation couldn’t be completed. (Cocoa error 260.)
Your interactionControllerWithURL: doesn't seem to be a problem but I have observed that -presentOpenInMenuFromRect: does not show if there are no apps that can open the file.
If your purpose is to share the file, and generally that doesn't mean open the file in the conventional sense, then instead of:
-presentOpenInMenuFromRect:inView:animated:
use
-presentOptionsMenuFromRect:inView:animated:
The former is an OpenInMenu and latter is an OptionsMenu.
For the tiny difference, check my related answer or check Apple doc directly
Example:
//this seems fine
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
//do this
[documentController presentOptionsMenuFromRect:CGRectZero
inView:self.view
animated:YES];
Also..., just before you present the documentInteractionController, it's good practice to specify the file's UTI so the documentInteractionController can populate itself with the appropriate options that can be performed & the list of all apps that can handle this file:
Example:
//assuming the file is a PDF
[documentController setUTI:#"com.adobe.pdf"];
//or... same thing but a more standardized way would be
[documentController setUTI:(NSString *)kUTTypePDF];
//but for this second style you'll need to add the `MobileCoreServices` framework
//to your project bundle and specify the following in your .h or .m
//#import <MobileCoreServices/MobileCoreServices.h>
Extra: Apple's Uniform Type Identifiers Reference
How do we create a universal search textfield like in iOS 7 safari. I know how to create a Google search field, but how can I create one textfield which has both Google search and URL search.
Google Searchfield:
-(void)SearchButtonClicked {
NSString *query = [maintext.text stringByReplacingOccurrencesOfString:#" " withString:#"+"];
NSString *urlString = [NSString stringWithFormat:#"%#", query];
// remember to change the view controller class in storyboard
MyWebViewController *webViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"WebView"];
// urlString is a public property on MyWebViewController
webViewController.urlString = urlString;
[self presentViewController:webViewController animated:YES completion:nil];
}
- (IBAction)SearchButton:(id)sender {
NSString *query = [maintext.text stringByReplacingOccurrencesOfString:#" " withString:#"+"];
NSString *urlString = [NSString stringWithFormat:#"http://www.google.com/search?q=%#", query];
// remember to change the view controller class in storyboard
MyWebViewController *webViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"WebView"];
// urlString is a public property on MyWebViewController
webViewController.urlString = urlString;
[self presentViewController:webViewController animated:YES completion:nil];
}
My Webview controller:
#import "MyWebViewController.h"
#import "ViewController.h"
#import <Social/Social.h>
#import "SIAlertView.h"
#import "TTAlertView.h"
#import "ETActivityIndicatorView.h"
#implementation MyWebViewController {
}
#synthesize searchField;
#synthesize webView;
ETActivityIndicatorView * etActivity;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSURL *url = [NSURL URLWithString:self.urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
-(void)webView:(UIWebView *)webBlog didFailLoadWithError:(NSError *)error{
if ([error code] != -999) {
NSLog(#"Could not load the dumb webPage");
//show error alert, etc.
TTAlertView *alert = [[TTAlertView alloc] initWithTitle:#"Internet Error"
message:#"Searched cannot open the page because your iPhone is not connected to the internet."
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[alert show];
[etActivity setHidden:YES];
}else{
NSLog(#"Could not load the dumb web page...just might blame user!");
}
}
//Called whenever the view starts loading something
- (void)webViewDidStartLoad:(UIWebView *)webView {
[etActivity startAnimating];
[etActivity setHidden:NO];
}
//Called whenever the view finished loading something
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[etActivity stopAnimating];
[etActivity setHidden:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[webView setDelegate:self];
self.searchField.backgroundColor = [UIColor colorWithRed:255.0/255 green:255.0/255 blue:255.0/255 alpha:1.0f];
self.searchField.layer.cornerRadius = 3.0f;
self.searchField.placeholder = #"Search or enter address";
self.searchField.leftViewMode = UITextFieldViewModeAlways;
UIView* leftView1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
self.searchField.leftView = leftView1;
//Setup handling of LEFT and RIGHT swipes
UISwipeGestureRecognizer *recognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[[self view] addGestureRecognizer:recognizer];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[[self view] addGestureRecognizer:recognizer];
self.searchField.delegate = self;
//ETActivityIndicatorView
etActivity = [[ETActivityIndicatorView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 60.0f, 60.0f)];
etActivity.center=self.view.center;
//you can set your custom color for ETActivityIndicatorView
etActivity.color = [UIColor colorWithRed:13.0/255 green:136.0/255 blue:236.0/255 alpha:1.0f];
[self.view addSubview:etActivity];
}
-(void)handleSwipeFrom:(UISwipeGestureRecognizer *)recognizer {
if (recognizer.direction == UISwipeGestureRecognizerDirectionRight) {
NSLog(#"Swipe Right");
[webView goBack];
}
if (recognizer.direction == UISwipeGestureRecognizerDirectionLeft) {
NSLog(#"Swipe Left");
[webView goForward];
}
}
#pragma mark - RNGridMenuDelegate
- (void)gridMenu:(RNGridMenu *)gridMenu willDismissWithSelectedItem:(RNGridMenuItem *)item atIndex:(NSInteger)itemIndex {
if (itemIndex == 0) {
NSLog(#"Reload");
[self.webView reload];
}
if (itemIndex == 1) {
NSLog(#"Facebook");
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) //check if Facebook Account is linked
{
mySLComposerSheet = [[SLComposeViewController alloc] init]; //initiate the Social Controller
mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook]; //Tell him with what social plattform to use it, e.g. facebook or twitter
[mySLComposerSheet setInitialText:[NSString stringWithFormat:#""]]; //the message you want to post
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
}
[mySLComposerSheet setCompletionHandler:^(SLComposeViewControllerResult result) {
switch (result) {
case SLComposeViewControllerResultCancelled:
break;
case SLComposeViewControllerResultDone:
break;
default:
break;
} //check if everything worked properly. Give out a message on the state.
}];
}
if (itemIndex == 2) {
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter])
{
SLComposeViewController *tweetSheet = [SLComposeViewController
composeViewControllerForServiceType:SLServiceTypeTwitter];
[tweetSheet setInitialText:#""];
[self presentViewController:tweetSheet animated:YES completion:nil];
}
}
if (itemIndex == 3) {
NSLog(#"Home");
MyWebViewController *MainView = [self.storyboard instantiateViewControllerWithIdentifier:#"MainView"];
[self presentViewController:MainView animated:NO completion:nil];
}
}
- (void)showList {
NSInteger numberOfOptions = 4;
NSArray *options = #[
#"Reload",
#"Facebook",
#"Twitter",
#"Home",
];
RNGridMenu *av = [[RNGridMenu alloc] initWithTitles:[options subarrayWithRange:NSMakeRange(0, numberOfOptions)]];
av.delegate = self;
av.itemFont = [UIFont boldSystemFontOfSize:18];
av.itemSize = CGSizeMake(150, 55);
[av showInViewController:self center:CGPointMake(self.view.bounds.size.width/2.f, self.view.bounds.size.height/2.f)];
}
- (IBAction)onShowButton:(id)sender {
[self showList];
}
![enter image description here][1]
Google Chrome assumes the typed text is a URL in these cases:
Text contains no whitespaces (One word):
Starts with a valid and accepted URI scheme (Like http, https, and ftp).
Starts with a forward slash (/).
Ends with a valid TLD (See 1, 2, 3).
Ends with a forward slash (/).
Known hostnames (Like localhost).
Valid IP addresses.
Text contains whitespaces (Multiple words):
Starts with a forward slash (/).
Text contains a question mark (?) and the part before it can be assumed a URL.
In all other cases you can safely assume the typed text is a search term.
This isn't a complete list of rules, but I think it's more than enough for regular usage.
Main reference: Chromium - Omnibox design principles.
Update:
Here are some hints to help you convert the previous rules to a working code (the order is important):
(Rule 3) Replace the part of text that matches this regular expression:
\?.*$
with empty string #"", and then apply other rules.
(Rules 1.1, 1.2, 1.4, 1.5, and 2.1) Match against this regular expression:
^((\/)|((https?|ftp):\S+$)|(\S+\/$)|(localhost$))
(Rule 1.3) You can collect some popular TLDs from the links above and form a one regular expression from them like this:
\S+\.(com|net|org|....)$
(Rule 1.6) Match against this regular expression:
^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$
Use this code. This basically checks the text entered into the textfield. If it's a complete url, then it redirects directly to it else the text entered is searched on google.
- (IBAction)SearchButton:(id)sender
{
MyWebViewController *webViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"WebView"];
NSString *urlString = maintext.text;
if([urlString rangeOfString:#"//"].location == NSNotFound)
{
// to resolve a url according to rfc 1808 (the most common form of URL), it must contain '//' in it.
// appending '//' in the url string to check for valid url
urlString = [NSString stringWithFormat:#"//%#", urlString];
}
NSURL *url = [NSURL URLWithString:urlString];
if(url && (url.scheme || url.host) && ([urlString rangeOfString:#"."].location != NSNotFound))
{
// url is valid, it contains domain and host
webViewController.urlString = maintext.text;
}
else
{
NSString *query = [maintext.text stringByReplacingOccurrencesOfString:#" " withString:#"+"];
NSString *urlString = [NSString stringWithFormat:#"http://www.google.com/search?q=%#", query];
// urlString is a public property on MyWebViewController
webViewController.urlString = urlString;
}
[self presentViewController:webViewController animated:YES completion:nil];
}
For, extra checks, you can also check that the url is valid or not like pinging to it and checking for it whether it responds or not.
You can create a category:
#interface NSString (NSStringValidator)
- (BOOL)isValidEmail;
- (BOOL)isValidURL;
#end
#implementation NSString (NSStringValidator)
- (BOOL)isValidEmail {
NSString *regExpPattern = #"\\b([a-zA-Z0-9%_.+\\-]+)#([a-zA-Z0-9.\\-]+?\\.[a-zA-Z]{2,6})\\b";
NSError *errorNext = NULL;
NSRegularExpression *regexNext = [NSRegularExpression regularExpressionWithPattern:regExpPattern
options:NSRegularExpressionCaseInsensitive
error:&errorNext];
NSRange range = [regexNext rangeOfFirstMatchInString:self
options:NSRegularExpressionCaseInsensitive
range:NSMakeRange(0, self.length)];
return NSEqualRanges(range, NSMakeRange(0, self.length));
}
- (BOOL)isValidURL {
NSString *regExpPattern = #"(?i)(?:(?:https?):\\/\\/)?(?:\\S+(?::\\S*)?#)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:\\/[^\\s]*)?";
NSError *errorNext = NULL;
NSRegularExpression *regexNext = [NSRegularExpression regularExpressionWithPattern:regExpPattern
options:NSRegularExpressionCaseInsensitive
error:&errorNext];
NSRange range = [regexNext rangeOfFirstMatchInString:self
options:NSRegularExpressionCaseInsensitive
range:NSMakeRange(0, self.length)];
return NSEqualRanges(range, NSMakeRange(0, self.length));
}
#end
Then call category method:
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField
{
[theTextField resignFirstResponder];
if (theTextField.text.isValidURL) {
//open site
} else {
//search text
}
return YES;
}