How can I enable zoom in on UIWebView which inside the UIScrollView? - objective-c

I have a UIWebView which inside a UIScrollView (scrollview contain another component)
I tried to enable multitouch both on Interface Builder or Programmatic on UIWebView but it still cannot zoom for html, do I need to handle both zoom in at the UIScrollView and UIWebView? Or anything I haven't to set?

You MUST set scalesPageToFit=YES for any pinching and zooming to work on a UIWebView

OK, you need to do both the above, but also the following. I had a web view in the main view, and that didn't work.
As above, you first have to put a UIScrollView in the main view, then put the web view in the scroll view.
As above, implement <UIScrollViewDelegate> in your view controller, drag the scroll view delegate to the view controller in Interface Builder, and implement the viewForZoomingInScrollView method. This must return the pointer to the UIScrollView (return myScrollView).
I created IBOutlet properties for both the web view and the scroll view - link them in the NIB to your view controller.
On the Scroll View, go to the Attributes Inspector, set your Max and Min zoom factors (I set 0.5 to 5.0, that works well).
On the Web View, in the Attributes Inspector:
In the Web View section, select Scales Pages To Fit
In the View section, select for Mode, "Top Left"
In the View section at the bottom, check off User Interaction Enabled, and Multiple Touch Enabled

With JavaScript you can control the zoom level, although the oly solution I have found doesn't look smooth.
Say you have in <head>:
<meta id="vp" name="viewport" content="width=768,initial-scale=1.0">
To zoom to 4x, and still allow the user to change zoom, change the content twice:
var vp = document.getElementById('vp');
vp.content = "width=767,minimum-scale=4.0,maximum-scale=4.0,user-scalable=yes";
vp.content = "width=768,minimum-scale=0.25,maximum-scale=10.0,user-scalable=yes";
Toggling the width is very important - otherwise Mobile Safari has serious repainting bugs (due to over-optimisation).
You cannot just set initial-scale again - it is ignored the second time.

You need to implement the viewForZoomingInScrollView method in your controller, or zooming won't do anything. (I don't really know why this should be needed, but there you go.)
For detailed information, see http://developer.apple.com/iphone/library/documentation/WindowsViews/Conceptual/UIScrollView_pg/ZoomZoom/ZoomZoom.html.

Related

UIPageControl (Page Control) not show in UIPageViewController

my UIPageViewController class conforms to UIPageViewControllerDataSource protocol and yet UIPageControl is not visible.
I've attached screen representing segues between UIPageViewController and it's child UIViewController's which are added by setViewControllers method.
Question is why Page Control is not shown and what can i do with it except adding UIPageControl instance to view myself ?
For some reason, it seems as though UIPageControl only appears when the Transition Style is set to "Scroll" -- very frustrating! (Hope I'm wrong?)
Click on your UIPageViewController ('Home Page View Controller'?) to see the option under Page View Controller.
Make sure you've implemented the optional -presentationCountForPageViewController: and -presentationIndexForPageViewController: data source methods.
UIPageViewController.h is very clear about the requirements:
A page indicator will be visible if both methods are implemented,
transition style is 'UIPageViewControllerTransitionStyleScroll', and
navigation orientation is
'UIPageViewControllerNavigationOrientationHorizontal'.

UIScrollView with controls repeating on every page?

I have perfectly working UIPageControl. I would like to add paging by swipe, and as I understood, it is done by UIScrollView.
But all tutorials are done with images, I want to have controls (labels, buttons) repeating on every page.
Because UIScrollControl is working the way that it must have set its width * pages count, does it mean, that controls can be placed only in code, not in IB?
Should I place labels and buttons directly on UIScrollView?
Thanks
If you have a View Controller designed using IB with all its buttons and labels, then it is possible to add that View Controller as a subview of your UIScrollView as such:
[scrollView addSubview:controller.view];
scrollView being your UIScrollView and controller being your IB designed View Controller.
You can achieve repeating controls with pagecontroll by using IB by ordering the objects appropriately. Here's what I have:
Drag the UIScrollview to the ViewController and also the drag the Page Controller and other controls also to the ViewController but not onto the UIScrollView. Keep them separate. The objects on the bottom of the IB list of objects shows up at the top of the view stack. (So when you swipe new pages the controls dont move and isn't covered by the UIScrollView) I also group the various controls by group selecting them and then use the "embed with view" menu item so that in IB I have two groups, the controls and the UIScrollView. Makes it neater and easier to manage. As for changing labels, I haven't tried it but I've seen tutorials where you can have iboutlets linked to changing value of pagecontroller and then update the labels in uiscrollview appropriately.

Handle tap event by subview of UIScrollView while scrolling

I have custom UIScrollView subclass with some content views inside. In some of them I have UITapGestureRecogniser. All works fine when scroll view is not scrolling. But when it scrolling content views does not receive tap action. What is the simplest solution to handle tap action by subview while scroll view is scrolling?
Details:
MyScrollView scrolls horizontally. It contains a lot of content views (e.g. MyContentView). Each MyContentView has width about one third of MyScrollView width. So there are about 3-4 visible MyContentView elements at a moment. The main behavior of MyScrollView is to 1)make sure that after scrolling one of MyContentView elements will be at center of screen and 2)to scroll to center of MyContentView if user taps on it. So the main answer I hope to get is how to "properly" implement handling of tap action in MyContentView while MyScrollView is decelerating.
I found some same questions and answers but none of them satisfied me. The best was to implement gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: of UITapGestureRecogniser delegate. But in this case I sometimes (when I tap, make smaaaal drag and release finger so tap is steel recognizable(lets called it quasi tap)) have both tap and scroll events and it leads to bugs for me even if scroll view is not scrolling when I begin tap. When user make quasi tap my application tries to scroll to tapped MyContentView element and than immediately handle normal scrolling. It seems even more terrible, due to some other functionality start to perform after handling tap (it must not perform when normal scrolling).
I need solution where scroll view wait enough to decide it is not tap event and only then make scroll. Otherwise if tap event had recognized scroll must not happen.
You can go with the custom delegates methods as well, using #protocol. Implement those delegate methods in view controller where your UIScrollView has been added.
like in MyContentView:
In touchesBegan method,
[self.delegate contentViewTapped:self];
Now in ContainerView class where scroll view is added, implement that method:
- (void)contentViewTapped:(MyContentView *)myContentView {
NSLog (#"ContentView no: %d", myContentView.tag); // if tag has been set while adding this view to scrollview.
}
Go through the examples for #protocol.
Hope this is what you required.
Enjoy Coding :)
This is built into UIScrollView - take a look at the delaysContentTouches and canCancelContentTouches properties. This should alleviate the problem when dragging a small bit after a tap.
This is all system built-in behaviour. I would suggest sticking with what Apple has provided for the feel of your interface (how it reacts to small drags, for instance) so that your app doesn't feel out of place on a user's phone.
EDIT:
Alternatively, you could disable scrolling of your scroll view in you gesture recognizer and re-enable it once it's ended/cancelled.
Further Edit:
I don't understand - I've created a sample project that illustrates how to intercept touches in a subview of a scroll view using gesture recognizer delegate methods. Play close attention to the "Cancellable Content Touches" and "Delays Content Touches" properties of the scroll view. They're both YES for very important reasons.
You scroll view should be delaying content touches until it has determined if the user is attempting a tap, pseudo-tap (as you put it), or a pan for the scroll view. Apple has already written the functionality you're trying to build; UIScrollView will already do what you want.
The problem is that the system doesn't want a scroll view's subviews intercepting tap events while the scroll view is scrolling. To this end, it cancels touch events if it determines that the user is actually trying to pan. Setting "Delays Content Touches" enables this behaviour. Ensure it's turned on and you should be fine.

Why doesn't UIScrollview have an accessibility area in the Interface Builder?

I've noticed that a UIScrollView doesn't have mentioned accessibility area where I can set accessibility label or accessibility. This seems to apply for activity indicators too.
Why does UIVIews, UIButtons and more have this area and not UIScrollView and UIActivityIndicatorView?
Good question - the reason for a scroll view is that Apple don't consider it to be an accessible element.
If you look at the UIAccessibility documentation, you'll find Apple have the following to say on what counts as an 'accessible element':
The only exception to this [a view being accessible] is a view that merely serves as a container for other items that should be accessible. Such a view should implement the UIAccessibilityContainer protocol and set this property to NO.
A UIScrollView is simply a container for subviews, so its isAccessibilityElement property is set to no (hence why you don't see the accessibility options in interface builder).
So basically, when you're using a scroll view the items inside it should be accessible, but not the scroll view itself.
To add more details on UIAutomation accessibility labels for UIScrollView you will have to use the index to the ScrollView to access subviews on the scroll view. Eg :
target.frontMostApp().mainWindow().scrollViews()[0].buttons()["logoutButton"].tap();
NOTE : Assumption is that the "logoutButton" is the accessibility label for the logout button and it is a subview on the scroll view.

How to synchronize scrolling of a NSScrollView and a WebView?

My app has two main views: a NSTextView subclass within a NSScrollView and a WebView. What the WebView displays is dependent on what the user enters into the text view - so I would like when the user scrolls either the text view or the web view the other scrolls proportionately to it.
I found this article which mentions how to do it with 2 scroll views. My problem is that WebKit doesn't seem to use normal Scroll views anywhere.
How should I implement this? What am I missing?
This is not a trivial problem to solve perfectly, as it's difficult to know whether the amount of text being edited in your text view corresponds to a similar amount of scrolling in the web view.
However, to answer your question about scroll views in WebView, they are used but as far as I know not documented extensively. You have to take advantage of the fact that you can obtain the scrollview being used, using public API, by asking the appropriate WebView subview for its "enclosingScrollView". Something like this works for me in a WebView where I know that there is only one frame:
[[[[myWebView mainFrame] frameView] documentView] enclosingScrollView];
If they are scrolling proportionately, probably the simplest solution would be to override touches events on your UIScrollview and impliment stringByEvaluatingJavaScriptFromString: on the UIWebView with (js) window.scroll(x,y). However, scrolling from the webView to the textview will require more work. The webView eats touches events, so you would need to
create a top level UIView or UIScroll view which captures the touches and sends them on to both the scrollView and the webView (via javascript) for ALL touches events, or
use a gesture recognizer to do the same.