hold-to-copy in uiwebview subclass - iphone

For my app, I subclassed UIWebView (the method described here http://ryan-brubaker.blogspot.com/2009/01/iphone-sdk-uiwebview.html).
I did this so that I could intercept touch events; when I detect certain types of taps, I perform the corresponding custom action, and then pass the event along to the underlying UIWebView.
So for example I can doubletap the view to make a toolbar appear/disappear, but a single tap on a link works the same as a regular UIWebView.
Under 3.0, Everything works just the same as it did under 2.2.1 (my doubletap + the standard single tap and scroll actions), but hold-to-copy does not.
I thought perhaps there was something new in UIResponder that I had to override, but as far as I can tell it's the same.
Any clues?

You shouldn't have to do anything special, as long as you're passing all the touch events through. It's certainly possible to disable that functionality using -webkit-user-select: none; in your CSS file.

<style>
body {-webkit-user-select:none;}
</style>

Related

UIAutomation pinch simulation

I'm trying to build a testing script for my iPhone application. Inside this test, I'm trying to simulate a pinch action.
I read on the official Apple reference that is possible to call the pinchOpenFromToForDuration function of UIATarget, but the simulator responds to this action how a double tap action (I'm sure because with double tap i perform another action in my code).
I can't understand how I can solve this problem, is possible to use any other trick to reach the same result?
Thank's
Marco
The odd behavior you are experiencing very well could be the coordinates you are using for the pinchOpenFromTo operation.
If the coordinates translate to something that does not "pinch" - like a WebView - then you usually get the click or tap result you mention. That has been my experience, anyway.
Use UIGestureRecognizer class for the zooming functionality. It would be easy for you to handle.
If you are in need of Pinch gesture use UIPinchGestureRecognizer class and delegate to handle that.
For Tap you may use UITapGestureRecognizer class and delegate methods….

Moving view up to accommodate keyboard

I have a view with multiple text fields and I want to do the same effect that the Contacts application does when you click on a text field would otherwise be hidden by the keyboard when it comes up. When I dismiss the keyboard I plan on moving the view back down properly.
I suspect that I do this by changing the Frame value, but I need this to be animated so that it isn't jarring to the user.
Advice? Examples?
Wrapping your view in a UIScrollView is indeed the way to go. As well as on the textFieldDidEndEditing delegate, you could instead subscribe to the UIKeyboardDidHideNotification and UIKeyboardDidShowNotification and when you receive a notification that the keyboard did hide/show then scroll your view appropriately. I can post code examples for the keyboard notifications if you need it : )
Edit
Figured I'd post the code anyway - someone might find it helpful:
You need to declare listeners for the notifications:
NSObject hideObj = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.DidHideNotification, HandleKeyboardDidHide);
NSObject showObj = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.DidShowNotification, HandleKeyboardDidShow);
then your Action methods would look something like:
void HandleKeyboardDidShow(NSNotification notification)
{
scrollView.ScrollRectToVisible(textfield.Frame, true);
}
void HandleKeyboardDidHide(NSNotification notification)
{
// scroll back to normal
}
Edit 2
So if you'd like to remove the Observers when the view is destroyed, first you need to ensure you assign NSObjects when adding the observers then use the following code to remove them:
NSNotificationCenter.DefaultCenter.RemoveObserver(showObj);
NSNotificationCenter.DefaultCenter.RemoveObserver(hideObj);
Hope that helps.
I just did this on an application. I used a scrollview to wrap my entire view, and then used scrollToRectVisible on the textFieldDidEndEditing-delegate method. It worked perfectly!
The Apple documentation on about the keyboard management topic is pretty good and contains code (at the bottom) for most situations that that you can copy/paste right into your app.
Best of luck.

UIWebView/MPMoviePlayerController and the "Done" button

I am using the UIWebView to load both streaming audio and video. I have properly set up the UIWebView delegate and I am receiving webViewDidStartLoading and webViewFinishedLoading events perfectly. The webview launches a full screen window (likely a MPMoviePlayerController)
Apple's MoviePlayer example gets the array of Windows to determine which window the moviePlayerWindow is for adding custom drawing/getting at the GUI components. I believe this to be a bad practice/hack.
My expectation is that I should be able to figure out when that button was clicked by either a delegate method or an NSNotification. It may also be the case that I have to poke around subviews or controllers with isKindOf calls, but I don't think those are correct approaches.
Are my expectations incorrect, and if so, why?
What is the correct way to bind an action to that "Done" button?
There isn't an MPMoviePlayer instance method that covers this. You can use - (void) moviePlayBackDidFinish:(NSNotification*)notification to find out when the movie has finished. Or you could overlay the existing Done button with your own and have complete control that way.
You can also use MPMoviePlayerWillExitFullscreenNotification in order to conrol the action provided that youe MoviePlayer is in fulscreen mode.

UIWebView events and hold to select/copy

I have created a subclass of UIWebView and have added a UIView on top of it in order to catch the touch events and use them.
Now, due to the extra view added on top of the UIWebView the text selection is not working at all. When I remove the extra UIView the text gets selected but then I cannot identify the events.
Is there a way by which both the functionalities can co-exist?
[EDIT]
May be my post was not clear enough. When I subclass UIWebView to handle events, selection stops working. I cannot select text for copy anymore. Any ideas why?
"The UIWebView class should not be subclassed." - from Apple's UIWebView docs.
It sounds like you're trying to mess with how a person interacts with a web page, which is likely to get you rejected from the app store. (For a lot of possible rejection reasons, check out app rejected.)
If you're not worried about that, here is some advice that might help you achieve your goals:
If you want to control where the user can and can't go via hyperlinks, or just perform some code whenever they click on some links, you can add a hook via the webView:shouldStartLoadWithRequest:navigationType: method of the UIWebViewDelegate protocol. Very handy.
If you want to perform some simple modifications to how the page acts or looks, you can essentially execute your own javascript in the page with a call to stringByEvaluatingJavaScriptFromString:, a method of UIWebView itself. Just pass in your javascript as a string.
And, in case that doesn't give you want you want (in which case you're really going to tick off them app store review guys), then you can probably do what you're already doing, and just propagate all those UITouchs right on through to the UIWebView itself. Something like this, as an example (in the overlapping UIView):
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self doWhatever];
[underlappingWebView touchesMoved:touches withEvent:event];
}
That way you can have your cake (get the user touch info) and eat it too (have the web page act as it normally does).
Not what you want to hear, but you definitely need to rethink your strategy to get the functionality you want.
UIWebview has a lot of complex behavior, it encapsulates an entire web rendering engine.
You can probably achieve your goals a different way (perhaps a toolbar item) or the functionality you desire may be hidden in a delegate method.

Deferring viewWillAppear until webViewDidFinishLoad

I have an application that uses UIWebViews in several view controllers. The UIWebViews are used to render locally generated html, no slow network access required.
To save memory I only load these on demand as prompted by the viewcontroller viewWillAppear callback. (And unload offscreen instances in response to didReceiveMemoryWarning messages.)
The problem is that the user gets to see the html being rendered, sometimes accompanied by flashes of styling and other assorted unpleasant artifacts. I would much rather the rendering be done offscreen, and reveal the fully rendered view when its ready.
It would be very tidy to be able to have the viewWillAppear not return until the UIWebView is fully rendered. But how?
I tell the UIWebView what to render by sending it a loadHTMLString:baseURL: message. This is asynchronous, and some time (soon) later the webview's delegate gets called back webViewDidFinishLoad.
I experimented with running a runloop inside viewWillAppear, running either the NSDefaultRunLoopMode or UITrackingRunLoopMode. This works in the simulator (it complains to the log
[CATransaction synchronize] called within transaction
but does work) but on a device it deadlocks, with webViewDidFinishLoad never being called.
(Also, it seems like the UIWebView loading property doesn't work. At least, after I call loadHTMLString:baseURL: and before getting the callback it's not true.)
Lots of solutions here I think. A quick one is to load your UIWebView with it's hidden property set to YES. Then set your UIViewController as the UIWebViews delegate and implement:
- (void)webViewDidFinishLoad:(UIWebView *)webView
where you set the property back to NO.
A thing to note is that webViewDidFinishLoad will fire more than once if you have framed/embedded content. So you have to keep track of this. Shouldn't really be a problem if you are loading local content.
I like monowerker's solution best, but another solution would be to hold onto the already-rendered UIWebView all the time (in some more permanent object than the view controller). I'd only do that if the look of monowerker's solution is too disruptive.