Dragging in UIWebView - iphone

Is there a way to prevent a UIWebView from being dragged?
Also, is there a way to actually overwride the common UIWebView functions such as highlighting?
Hope someone can answer me.
Thanks

webview.scrollView.scrollEnabled = NO;

You can look up the scrollView of the webView and disable the scrolling with this code:
UIScrollView *scrollView = nil;
for(UIView *aView in webView.subviews){
if([aView isKindOfClass:[UIScrollView class] ]){
scrollView = (UIScrollView *)aView;
scrollView.scrollEnabled = NO;
scrollView.bounces = NO;
}
}

To prevent the drag:
<script type="text/javascript" language="javascript">
document.ontouchmove = function(e)
{
e.preventDefault();
}
</script>
To override the highlighting:
<style type="text/css">
body
{
-webkit-user-select: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-touch-callout: none;
}
</style>
So, on the highlighting part:
The 1st line disables selection (like on text)
The 2nd line disables the actual highlight
The 3rd option disables the "popup" you see when you press an image for 2 seconds, asking if you'd like to download/save
Keep the ones you need.
Hope this helps :)

Related

UIWebview re-enables scrolling even after scrollEnabled is set to NO

Here is a problem. I am using a draggable image in UIWebview. The Source code: here:http://ios-blog.co.uk/tutorials/rich-text-editing-a-simple-start-part-7/
It simply disables the scrolling during drag and reenable it when the dragging is completed.
It works perfectly fine when UIWebview is first brought up and hereafter. As soon as the edited text length is longer than the screen. UIWebview ignores the scroll setting of its scrollview and re-enables the scrolling.
The way I disable the scroll view is using this:
webview.scrollview.scrollEnabled = NO;
Please tell me where I was wrong. Much appreciated.
This problem is caused because of the following wrap placed within the html file I loaded as a template editing section.
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;"/>
<style type="text/css">
html, body {height: 100%;}
body {
margin: 0;
}
#wrap {
height: 100%;
width: 100%;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
#content
padding: 10px;
}
</style>
Any div wrapped with this block will always allow itself to be scrolled.
Deleted it and things turned out to function properly again!
may use
for(UIView *aView in webview.subviews){
if([aView isKindOfClass:[UIScrollView class]])
aView.scrollEnabled = NO;
}
this makes sure that any scrollview's scrolling is disabled.

UIWEBVIEW +contents fit in frame of webview

I am using UIwebview in my project.Where the the cotent in the webview is been filled from html data By doing below code like this:
[webView loadHTMLString:[NSString stringWithFormat:#"<html><body><font face=\"Arial\" size=\"3\"</font>%#</body></html>",[[[dict_Response objectForKey:#"objects"]objectAtIndex:0]objectForKey:#"detaildescription"]] baseURL:[NSURL URLWithString:#"http://newsletter.nobelbiocare.com/"]];
Now i am setting the frame of webview:-
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(appDel.ori_appDel == UIInterfaceOrientationPortraitUpsideDown || appDel.ori_appDel == UIInterfaceOrientationPortrait)
{
webView.frame=CGRectMake(30,150,710,450);
}else{
webView.frame=CGRectMake(30,150,930,450);
}
return yes;
}
Now the thing happen is in Landscape mode the content is showing in proper way.But when i move to portrait mode it automatically shows horizontal scrolling.I dont want to scroll the webview in horizontal mode..
Please help me..How to solve this.
I had used sizetofit and autoresizing|autofixing.
But then also it is not solving Please help me..
#shweta
try to update your webview in webViewDidFinishLoad: this will help you. and try to set the size in html rather than web view frame.
- (void)webViewDidFinishLoad:(UIWebView *)webview {
CGRect oldBounds = [[self webview] bounds];
//in the document you can use your string ... ans set the height
CGFloat height = [[webview stringByEvaluatingJavaScriptFromString:#"document.height"] floatValue];
[webview setBounds:CGRectMake(oldBounds.origin.x, oldBounds.origin.y, oldBounds.size.width, height)];
}
the main concern is the method .
[webview stringByEvaluatingJavaScriptFromString:#"document.height"]
by using javascript.
Instead of
sizetofit and autoresizing|autofixing
Write
webview.scalePageToFit=TRUE
Use this:
[webView loadHTMLString:[NSString stringWithFormat:#"<html><div style='font-family: arial,helvetica;font-size: 14px;'>%#</div></html>",[[[dict_Response objectForKey:#"objects"]objectAtIndex:0]objectForKey:#"detaildescription"]] baseURL:[NSURL URLWithString:#"http://newsletter.nobelbiocare.com/"]];
Try these
1. Put format specifier between body tag as </font>%#</body></html>.
2. Try reloading web view in this
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
//Reload your web view here
}

Workaround for 'background-attachment: fixed' which is not working in iOS4

I'm struggling to get web page with a fixed background image, so the image does not move when page is scrolled in a UIWebView.
What I've discovered is: background-attachment: fixed does not work in iOS4 (using 4.2.1).
To double-check I've prepared a page with code snippet (below) inside <head> section and the page works as expected under Safari and Firefox on Mac, but fails to do so in iPhone's Safari...
What do you suggest as a workaround for achieving the expected results? I've made my UIWebView translucent and added UIImageView, so I can see "fixed background image" through translucent page. Unfortunately, I can see UIWebView borders when I scroll over its end/beginning edges.
Is there any official Apple resource/web page stating that background-attachment: fixed is not implemented for iOS4?
Cheers!
P.S. The code snippet referred above:
<style type="text/css">
body {
background: #ffffff url('image.jpg') fixed no-repeat;
background-attachment: fixed;
}
</style>
I am not sure what is going on with the CSS and have not had a chance to check it out for myself but I know when I was trying to get rid of the shadows from a UIWebView I used this bit of code:
NSArray *sv = [NSArray arrayWithArray:[myWebView subviews]];
UIScrollView *webScroller = (UIScrollView *)[sv objectAtIndex:0];
NSArray *wsv = [NSArray arrayWithArray:[webScroller subviews]];
[[wsv objectAtIndex:6] setHidden:YES];
[[wsv objectAtIndex:7] setHidden:YES];
[[wsv objectAtIndex:8] setHidden:YES];
[[wsv objectAtIndex:9] setHidden:YES];
and it got rid of the shadows. I thought I got the answer off of a SO question but when I looked for it this is the only one that came up.
It passed App Store inspection.
Use a div for the background with a negative z-index:
<head>
<style>
#background {
background: url("background.jpg") no-repeat;
position: fixed;
top: 0;
left: 0;
background-size: 320px 480px;
width: 320px;
height: 480px;
z-index: -1;
}
</style>
</head>
<body>
<div id="background"></div>
This body text appears over the fixed background and scrolls.
</body>
Works on iOS 5 and iOS 6.

iPhone UIWebView width does not fit after zooming operation + UIInterfaceOrientation change

I created a bare bones iPhone app with a UIWebView (Scales Page to Fit = YES, shouldAutorotateToInterfaceOrientation = YES) and loaded a webpage, e.g. https://stackoverflow.com/
Rotating the device shows that UIWebView is auto-resized to fit the width. Good.
Incorrect: Zoom into the page and zoom out. Now rotating the device shows UIWebView in a weird width in one of the orientation (if u zoom in landscape, the portrait width is weird, vice versa). This behavior is fixed only when you navigate to another page.
Correct: Load the same URL in Mobile Safari. Rotating works & the width fits regardless of the zooming exercise.
Is this a UIWebView bug (probably not)? Or is there something that needs to be done to make things "just work" like in Mobile Safari?
I found something that worked for me. The problem is that when uiwebview changes its orientation web contents are zoommed to fit with viewport. But zoomscale parameter of scrollview subview is not updated correctly (nor are updated minimumZoomScale nor maximumZoomScale
Then we need to do it manually at willRotateToInterfaceOrientation:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
CGFloat ratioAspect = webview.bounds.size.width/webview.bounds.size.height;
switch (toInterfaceOrientation) {
case UIInterfaceOrientationPortraitUpsideDown:
case UIInterfaceOrientationPortrait:
// Going to Portrait mode
for (UIScrollView *scroll in [webview subviews]) { //we get the scrollview
// Make sure it really is a scroll view and reset the zoom scale.
if ([scroll respondsToSelector:#selector(setZoomScale:)]){
scroll.minimumZoomScale = scroll.minimumZoomScale/ratioAspect;
scroll.maximumZoomScale = scroll.maximumZoomScale/ratioAspect;
[scroll setZoomScale:(scroll.zoomScale/ratioAspect) animated:YES];
}
}
break;
default:
// Going to Landscape mode
for (UIScrollView *scroll in [webview subviews]) { //we get the scrollview
// Make sure it really is a scroll view and reset the zoom scale.
if ([scroll respondsToSelector:#selector(setZoomScale:)]){
scroll.minimumZoomScale = scroll.minimumZoomScale *ratioAspect;
scroll.maximumZoomScale = scroll.maximumZoomScale *ratioAspect;
[scroll setZoomScale:(scroll.zoomScale*ratioAspect) animated:YES];
}
}
break;
}
}
Hope this helps!
I've tried the solution from M Penades and this seems to work for me as well.
The only issue that I'm experiencing is that when running this on a 3Gs the rotation is unfortunately not very smooth.
I'm therefore now using a different approach:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
CGFloat scale = browserWebView.contentScaleFactor;
NSString *javaStuff = [NSString stringWithFormat:#"document.body.style.zoom = %f;", scale];
[browserWebView stringByEvaluatingJavaScriptFromString:javaStuff];
}
Best Regards,
Ralph
- (UIScrollView *)findScrollViewInsideView:(UIView *)view
{
for(UIView *subview in view.subviews){
if([subview isKindOfClass:[UIScrollView class]]){
return (UIScrollView *)subview;
}
UIScrollView *foundScrollView = [self findScrollViewInsideView:subview];
if (foundScrollView){
return foundScrollView;
}
}
return nil;
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
switch (self.interfaceOrientation){
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
{
UIScrollView *webViewScrollView = ([self.webView respondsToSelector:#selector(scrollView)])
? self.webView.scrollView
: [self findScrollViewInsideView:self.webView];
[webViewScrollView setZoomScale:1.01f animated:YES];
}
break;
default:
break;
}
}
try this code, it insignificantly changes zoom level (1.01) to allow UIWebView increase content size in landscape mode
findScrollViewInsideView: method added to support ios4
I have a solution to this problem, but I gotta say I'm not a huge fan of it. It works great, but the solution actually causes another problem. I have a fix for the secondary issue, but it takes a bit of effort.
Just keep in mind that since OS3.2 or iOS4 (not sure which) UIWebView's direct subview is now UIScrollView instead of UIScroller, so we can do a lot more with it. Also, since accessing subviews of a View is not a private action, neither is using a subview that is casted as a documented view we can do a lot with the UIWebView without breaking the rules.
First we need to get the UIScrollView from the UIWebview:
UIScrollView *sview = [[webView subviews] objectAtIndex:0];
Now we need to change the delegate of this scrollview so we can override scrollview delegate calls (which may actually be the cause of a secondary bug as a result of this solution, which I'll share in a moment):
sview.delegate = self;
Now, if you try it at this point, zooming is broken. We need to implement a UIScrollViewDelegate method to fix it. add:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
UIView *webBrowserView = [[scrollView subviews] objectAtIndex:10];
return webBrowserView;
}
webBrowserView is actually a UIWebBrowserView, but that isn't a documented class, so we are just going to treat it as a UIView.
Now run your app, zoom in and then zoom out the webpage. Rotate, and it should appear correctly.
This does cause a rather large bug, that is perhaps worse than the original.
If you zoom in and then rotate, you will loose scrolling ability, but your view will be zoomed in still. Here is the fix To complete the whole thing.
First, we need to keep track of a few numbers, and have a flag defined:
I have these defined in my h file:
BOOL updateZoomData;
float zoomData; //this holds the scale at which we are zoomed in, scrollView.zoomScale
CGPoint zoomOffset; //this holds the scrollView.contentOffset
CGSize zoomContentSize; //this holds the scrollView.contentSize
You may think you can just grab these numbers from UIScrollView, but when you need them, they will have changed, so we need them stored elsewhere.
We need to use another delegate method:
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
if(updateZoomData){
zoomData = scrollView.zoomScale;
zoomOffset = scrollView.contentOffset;
zoomContentSize = scrollView.contentSize;
}
}
Now it gets into a mess I feel.
We need to track rotation, so you'll need to add this to your viewDidLoad, loadView, or whatever method you use to register notifications:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(webViewOrientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
and create this method:
- (void)webViewOrientationChanged:(NSNotification *)notification{
updateZoomData = NO;
[self performSelector:#selector(adjustWithZoomData) withObject:nil afterDelay:0.0];
}
So now anytime you rotate webViewOrientationChange will be called. The reason performSelector is delayed for 0.0 seconds is because we want to call adjustWithZoomData on the next runloop. If you call it directly, the adjustWithZoomData will adjust for the previous orientation.
Here is the adjustWithZoomData method:
- (void)adjustWithZoomData{
UIScrollView *sview = [[webView subviews] objectAtIndex:0];
[sview setZoomScale:zoomData animated:YES];
[sview setContentOffset:zoomOffset animated:YES];
[sview setContentSize:zoomContentSize];
updateZoomData = YES;
}
Thats it! Now when you rotate it will maintain zoom, and roughly maintain the correct offset. If anyone wants to do the math on how to get the exact correct offset then go for it!
I was looking into this myself and found out some more information:
Issues when changing zoom:
Safari often doesn't repaint properly (if at all) even though zoom level changed.
Changing the width forces a repaint.
you would think width=device-width in landscape would use 1024 but it seems to use 768 (screen.width happens too).
e.g. if current width is 1024 and you want to zoom from 1 to 1.5 in landscape you could:
change combination of width and zoom e.g. width to 2048 and zoom to 0.75
change width to 1023 (ugly aliasing?)
change width to say 1023, then next line back to 1024 (double repaint, but at least window is repainted).
So apparently I didn't use the solution by M Penades in the end (and forgot to update this post! sorry).
What I did was to resize the entire document (and change my font-size to keep things proportionate). That apparently fixed the issue.
However, my UIWebView is only for loading my own HTML & CSS from the iOS filesystem - if you're building a general purpose web browser, this trick may not work as well.
ViewController.m
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
switch (toInterfaceOrientation) {
case UIInterfaceOrientationPortraitUpsideDown:
case UIInterfaceOrientationPortrait:
if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)) {
[webview stringByEvaluatingJavaScriptFromString:#"document.body.className = 'ppad'"];
} else {
[webview stringByEvaluatingJavaScriptFromString:#"document.body.className = 'pphone'"];
}
break;
default:
if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)) {
[webview stringByEvaluatingJavaScriptFromString:#"document.body.className = 'lpad'"];
} else {
[webview stringByEvaluatingJavaScriptFromString:#"document.body.className = 'lphone'"];
}
break;
}
}
And app.css
html>body.pphone { font-size:12px; width: 980px; }
html>body.lphone { font-size:18px; width: 1470px; }
html>body.ppad { font-size:12px; width: 768px; }
html>body.lpad { font-size:15.99999996px; width: 1024px; }
Gist at https://gist.github.com/d6589584944685909ae5
I am posting this because i have also faced the same problem and here i am following the M Penades Approach.M Penades 's Answer woks good only for case if user does not Skew(pinch Out) the Webview then rotate the device and repeat this process .then Content Size of UiwebView gets reduce gradually. so that was the issue came in M Penades Answer. so I have fixed that issue too and my code is as below.
1) For This I set the Pinch Gesture so that when User Skew The UIwebView could check the Scaled size of UIwebView.
//One This Please import The UIGestureRecognizerDelegate Protocol in '.h file'
//call below method in ViewDidLoad Method for setting the Pinch gesture
- (void)setPinchgesture
{
UIPinchGestureRecognizer * pinchgesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(didPinchWebView:)];
[pinchgesture setDelegate:self];
[htmlWebView addGestureRecognizer:pinchgesture];
[pinchgesture release];
// here htmlWebView is WebView user zoomingIn/Out
}
//Allow The allow simultaneous recognition
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
Returning YES is guaranteed to allow simultaneous recognition. returning NO is not guaranteed to prevent simultaneous recognition, as the other gesture's delegate may return YES
-(void)didPinchWebView:(UIPinchGestureRecognizer*)gestsure
{
//check if the Scaled Fator is same is normal scaling factor the allow set Flag True.
if(gestsure.scale<=1.0)
{
isPinchOut = TRUE;
}
else// otherwise Set false
{
isPinchOut = FALSE;
}
NSLog(#"Hello Pinch %f",gestsure.scale);
}
If User Hase Pinch In/Out The Web View in that Case Just Set THat Zooming Factor .
SO that WebView Can Adjust Its ContentSize as Oreintaion Changed.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
//Allow the Execution of below code when user has Skewed the UIWebView and Adjust the Content Size of UiwebView.
if(isPinchOut){
CGFloat ratioAspect = htmlWebView.bounds.size.width/htmlWebView.bounds.size.height;
switch (toInterfaceOrientation) {
case UIInterfaceOrientationPortraitUpsideDown:
case UIInterfaceOrientationPortrait:
// Going to Portrait mode
for (UIScrollView *scroll in [htmlWebView subviews]) { //we get the scrollview
// Make sure it really is a scroll view and reset the zoom scale.
if ([scroll respondsToSelector:#selector(setZoomScale:)]){
scroll.minimumZoomScale = scroll.minimumZoomScale/ratioAspect;
scroll.maximumZoomScale = scroll.maximumZoomScale/ratioAspect;
[scroll setZoomScale:(scroll.zoomScale/ratioAspect) animated:YES];
}
}
break;
default:
// Going to Landscape mode
for (UIScrollView *scroll in [htmlWebView subviews]) { //we get the scrollview
// Make sure it really is a scroll view and reset the zoom scale.
if ([scroll respondsToSelector:#selector(setZoomScale:)]){
scroll.minimumZoomScale = scroll.minimumZoomScale *ratioAspect;
scroll.maximumZoomScale = scroll.maximumZoomScale *ratioAspect;
[scroll setZoomScale:(scroll.zoomScale*ratioAspect) animated:YES];
}
}
break;
}
}
}
This Works perfectly for even user skew the UIWebView.
On rotation, try setting the scrollView zoomScale to 0.
See my full answer here: UIWebView content not adjusted to new frame after rotation

Stop scrolling to top in UIWebView - iPhone

I have placed following javascript in my html file.
<script TYPE="text/javascript">
function srk(){
document.ontouchmove = function(e){
e.preventDefault();
}
}
</script>
I am scrolling my webview by following code with some animation.
[myWebView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat: #"window.scrollTo(0,%i);",414*self.initialScrollPosition]];
Everything going right, but on problem that I am facing is as follows.
Whenever User/I tap on the status bar of iPhone, WebView Bydefault scrolls to top.
This should not be done.
Is it possible to prevent inbuilt functionality ?
I know one of the option is as follows.
((UIScrollView *)[[myWebView valueForKey:#"_internal"] valueForKey:#"scroller"]).scrollsToTop = NO;
But is it valid to do ?
You can add a very tiny UIScrollView in the window. Then tapping the status bar won't scroll the web view to top.
A more straightforward way to do this would be to set the scrollsToTop property of the UIScrollView in the WebView to NO.
for(UIView *view in [myWebView subviews]) {
if([view isKindOfClass:([UIScrollView class])]) {
[(UIScrollView *)view setScrollsToTop:NO];
}
}
I have tested this on iOS 4.0 and 4.3 (iOS 5 seems to not need this).
adapted from this.