I was wondering if I could create an app which supports opening .html-pages.
For example, if the app supports .pdf, when opening a .pdf, a small gray box appears with the button "Open in myApp". Can I get something like this, but then for a webpage?
Hmm you are talking about UIDocumentInteractionController then.
Implement UIDocumentInteractionControllerDelegate in your UIViewController
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller { return self; }
- (UIView *)documentInteractionControllerViewForPreview:(UIDocumentInteractionController *)controller { return self.view; }
- (CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController *)controller { return self.view.frame; }
Then add a button to the navigation bar to popup the options box:
// example: opening a .html file
NSString *index = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"html"];
// self.controller is a UIDocumentInteractionController ivar
self.controller = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:fileToOpen]];
self.controller.delegate = self;
CGRect rect = self.navigationController.navigationBar.frame;
rect.size = CGSizeMake(1500.0f, 40.0f); // move the box right down under the button
[self.controller presentOptionsMenuFromRect:rect inView:self.view animated:YES];
A list of the applications supporting a particular document should appear. If you didn't register your app to support a type of document you still get the option "QuickLook". All this happens on whatever application is interacting with the file (since the files themselves are not exposed on the UI).
Related
I have two buttons in my VC and currently they both are connected to their respective pdf files. There is another button, Push, that goes to the rootviewcontroller. In the RVC I have a UIWebView. How can I make it so that if I push button A, a.pdf is displayed and b.pdf for button B?
I guess, how do I make the rvc listen for this event correctly?
Snippet for UIWebView inside my RVC.m
pdfViewer=[[UIWebView alloc]initWithFrame:CGRectMake(420, 190, 340, 445)];
NSString *path = [[NSBundle mainBundle] pathForResource:#"nameofpdf" ofType:#"pdf"];
NSURL *targetURL = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:targetURL];
[pdfViewer setAlpha: .8];
[pdfViewer loadRequest:request];
[self.view addSubview:pdfViewer];
And button Push in my VC
-(IBAction)pushButtonPressed{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
RootViewController *RVC = [storyboard instantiateViewControllerWithIdentifier:#"Root"];
[UIApplication sharedApplication].delegate.window.RootViewController = RVC;
}
Wrap up:
I first press A or B, then press Push which will bring me to the RVC which will display pdfA or pdfB.
Declare a property for your RVC for the pdf file you want it to open. In your viewController that holds the buttons have the buttonFunction pass the filename to the segue as the sender parameter in prepareForSegue. In prepareForSegue grab the dest view controller and set the property. A short snippet might be more clear
In your viewController with the Buttons:
- (void)buttonA {
[self performSegueWithIdentifier:#"mySegue" sender:#"pdfA.pdf"];
}
- (void)buttonB {
[self performSegueWithIdentifier:#"mySegue" sender:#"pdfB.pdf"];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"mySegue"]) {
UIViewController *rvc = segue.destinationViewController;
rvc.pdfToOpen = sender;
}
}
You'll have to adjust your prepareForSegue to use the correct class with the correct property name of course, but this is generally how you should pass information from an action into a view controller via a segue.
Once in your RVC you can access that property, probably inside viewDidLoad, and tell your webView to load the correct pdf.
I have a panel with an image on it, and I want to make it so that you can copy a file (not the image,the image is only going to server as an icon for the file) into a folder by “dragging” the image outside of the application and into any other application that accepts files being dragged into it (ex. Finder). How can I do this?
I implemented the NSDraggingSource protocol, but I’m not sure how to make the image draggable. It is currently inside of an ImageView, which is inside of an ImageViewCell.
Here is the protocol I implemented:
#import "DragNDropView.h"
#implementation
-(NSDragOperation)draggingSession:(NSDraggingSession *)session
sourceOperationMaskForDraggingContext: (NSDraggingContext) context{
switch(context){
case NSDraggingContextOutsideApplication:
return NSDragOperationCopy;
break;
default:
return NSDragOperationNone;
break;
}
}
-(void) draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint) screenPoint{
NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
NSPaseBoardItem *contents = [[NSPasteboardItem alloc]
inithWithPasteboardPreopertyList:SDKFileName ofType:NSFileContentsPboardType];
[pboard writeObjects[NSArray arrayWithObjects:contents, nil]];
}
-(void)drawRect:(NSRect)dirtyRect{
SDKFileName = #"example.example";
[super drawRect:dirtyRect];
}
#end
I added the method - (id)initWithCoder(NSCode *)coder and I also added
- (BOOL)acceptesFirstMouse:(NSEvent *)event { return YES; }
My application is set in info.plist to support only portrait mode.
However, the UIImagePickerController, rotates when the user rotates the screen to landscape.
Since in io6 the method shouldAutoRotate is not being called, I tried to extend it like this:
#interface NonRotatingUIImagePickerController : UIImagePickerController
#end
#implementation NonRotatingUIImagePickerController
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationMaskPortrait;
}
#end
But it doesn't help. Any idea why?
And in the log I see the above methods being called. The UIImagePickerController at first is displayed in portrait and when the user rotates - it rotates as well instead of staying portrait.
I set the image picker in the view like this:
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (!self.imagePickerController) {
self.imagePickerController = [[NonRotatingUIImagePickerController alloc] init];
self.imagePickerController.delegate = self;
}
return self;
}
- (void)viewDidAppear:(BOOL)animated{
self.imagePickerController.showsCameraControls = NO;
CGRect imagePickerControllerFrame = CGRectMake(0, topBar.frame.size.height, self.view.frame.size.width, self.view.frame.size.height - topBar.frame.size.height - bottomBar.frame.size.height);
self.imagePickerController.view.frame = imagePickerControllerFrame;
self.imagePickerController.allowsEditing = YES;
self.imagePickerController.view.clipsToBounds = YES;
self.imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera
[self.view.window addSubview:self.imagePickerController.view];
}
self.imagePickerController.view.frame = imagePickerControllerFrame;
// ...
[self.view.window addSubview:self.imagePickerController.view];
Well, that's all totally illegitimate. Apple makes this very clear in the docs:
This class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified
There is only one correct way to use an image picker controller that uses UIImagePickerControllerSourceTypeCamera - as a fullscreen presented view controller:
BOOL ok = [UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera];
if (!ok) {
NSLog(#"no camera");
return;
}
NSArray* arr = [UIImagePickerController availableMediaTypesForSourceType:
UIImagePickerControllerSourceTypeCamera];
if ([arr indexOfObject:(NSString*)kUTTypeImage] == NSNotFound) {
NSLog(#"no stills");
return;
}
UIImagePickerController* picker = [UIImagePickerController new];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.mediaTypes = #[(NSString*)kUTTypeImage];
picker.delegate = self;
[self presentViewController:picker animated:YES completion:nil];
If you want to present a live picture-taking interface inside your own interface, use AVFoundation and the camera capture API that it gives you.
Downloadable working example here:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch30p816cameraCaptureWithAVFoundation/p683cameraCaptureWithAVFoundation/ViewController.m
Perhaps you'll consider this answer unhelpful; but I'll just paste a snippet from Apple's documentation:
Important: The UIImagePickerController class supports portrait mode only. This class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified, with one exception. You can assign a custom view to the cameraOverlayView property and use that view to present additional information or manage the interactions between the camera interface and your code.
UIImagePickerController Doc Link
Sorry to be a kill-joy. You should look for a replacement class. Quickie search shows there are a bunch.
Assuming an application has many views pushed to a uinavigationViewController, each view is different in content.
since the elements in the app are complex, I would like to show a small help view for specific views or elements in a specific view.
Imagine a "?" button that when pressed on will pop a new view in the center of the screen, playing youtube help video, or just a textual HTML loaded from a remote server.
Question: what is the best strategy for doing such a thing?
where should I place this code (App Delegate?)
if so, how would I call it from other views (with URL Parameter)
-(void)showHelpView:(NSString *)theURLString{
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)];
//webView.delegate= self;
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:theURLString]]];
[window addSubview:webView];
[window makeKeyAndVisible];
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
}
I'd prefer using pseudo-modal views. So that you create view every time, and add it on top of current window. I've used this approach for OAuth 2.0 authorisation popup in my last app.
Basically you create custom UIViewController subclass, provide custom initialisator, such as, for example:
// - (id) initWithURL: (URL*)url {
// ...
// self.url = url;
// ...
// return self;
PseudoModalViewController* pmvc = [[PseudoModalViewController alloc] initWithURL:#"http://www.google.com/"];
After you've created view you add it on top of current window:
UIWindow* window = [[UIApplication sharedApplication] keyWindow];
if(!window)
{
window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
}
[window addSubview:pmvc.view];
In, for example, viewDidLoad you load url obtained in initialisator:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.webView loadRequest:[NSURLRequest requestWithURL:url]];
}
You may even design UI in Interface Builer for that. As a last piece I'd recommend add to include full screen transparent background view to ensure that all views below are disabled.
Oh, almost forgot, you hide that view with just a simple [self.view removeFromSuperview]. Don't forget to provide correct memory management for that view (i.e. release it in time, etc).
I am using a QLPreviewController to display a set of files. However, it only shows the first one and I can't seem to swipe or do anything to show the second. What am I doing wrong? Do I have to set it manually? If so - how would I go about doing that?
This is from my AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// normal viewcontroller init here
[self showPreview] ;
return YES;
}
NSArray* documents ;
QLPreviewController* preview ;
- (void) showPreview
{
documents = [[NSArray alloc] initWithObjects: #"photo" , #"photo2" , nil ] ;
preview = [[QLPreviewController alloc] init];
preview.dataSource = self;
preview.delegate = self;
preview.view.frame = [[UIScreen mainScreen] bounds];
//save a reference to the preview controller in an ivar
// self.previewController = preview;
//refresh the preview controller
[preview reloadData];
[[preview view] setNeedsLayout];
[[preview view] setNeedsDisplay];
[preview refreshCurrentPreviewItem];
preview.view.userInteractionEnabled = YES;
//add it
[self.viewController.view addSubview:preview.view];
}
I also declared the two callback functions in the same AppDelegate.m file:
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index
{
NSString* filename = [documents objectAtIndex:index] ; // #"photo" ;
NSURL* returnURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource: filename ofType:#"jpg" ]] ;
return returnURL ;
}
- (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller
{
return [documents count];
}
You are displaying it wrong.
QLPreviewController is a UIViewController, which means you basically have 2 ways of displaying it:
Push it into your UINavigationController.
Display it modally (this can be done with or without a UINavigationController - depends if you want a navigation bar).
If you choose option 2 you get "free" navigation arrows to switch between items.
For option 1 you need to create the arrows yourself.
This following is taken from the QLPreviewController documentation:
If there is more than one item in the list, a modally-presented (that
is, full-screen) controller displays navigation arrows to let the user
switch among the items. For a Quick Look preview controller pushed
using a navigation controller, you can provide buttons in the
navigation bar for moving through the navigation list.