UIScrollView, sliding, zooming - ios

I have an app which has a uiscrollview, which in turn has two uiimageviews.
The scrollview works fine in sliding between both imageviews, by making the content size twice the width. like so
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * 2, self.scrollView.frame.size.height)];
Now the client wants the user to be able to zoom into any image in those two images. He does not want another modal view with the selected picture zoomed in, but rather on the same uiscrollview he wants this to happen. Is this doable? or a good Idea?
The problem I am having is that when I implement the zooming logic ( implementing the delegate
UIScrollViewDelegate
the moment I set the value of
self.scrollView.zoomScale
I end up calling this method
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [self getCurrentVisibleImage];
}
And with that happening, I end up with the UIscrollview that after zooming back to the normal size of the image, the scrollview simply doesn't slide left or right?
Any help is appreciated.

Answer was simple, I was manipulating contentsize and not setting it properly. that fixed it.

Related

UIScrollView over MKMapView

I'm trying to create a specific layout in an iOS App, where the "background" is a MKMapView and the overlay is a UIScrollView. The idea is that there are two screens, one with a map, and another with some additional information on. The user can scroll down to see this general information, and this view covers up the map and has a blurred background to create some depth.
Here's an image showing the layout:
As you can see, the map is fixed in its position. It will always be behind the content, even if you scroll. I want the map to respond to gestures, but only when used directly on the map. When the user "scrolls" over the bottom bar, I want the content to scroll up, revealing the second page which then covers the map.
I'm lost at what to do to achieve this. I tried putting the map on the original UIView and then covering it up with a scrollview, but this causes the map not to respond to gestures. I only want the UIScrollView to respond to gestures when it's on either the bottom bar, or the second page (each is its own separate view). Otherwise I want the Map to respond to the gestures.
I hope I managed to explain it well, if not, please do not hesitate to ask questions. I appreciate all help!
It sounds like you are adding a full screen UIScrollView on top of a MKMapView and the scrollview is picking up all the touches.
What you are asking about is not necessarily standard so there are multiple ways to implement it and you have to decide what works best for your use case.
Here is what I would do:
Use constraints on the scrollview to ensure that it is only covering the bottom bar area.
Make sure you can toggle the constant of the constraint controlling the scroll view's height (hook up an IBOutlet if you're using storyboard).
Add both a swipe gesture recognizer and a tap gesture recognizer that will fire toggleScrollViewFullScreen if recognized. Ensure that these recognizers can only be recognized while the scrollView is the bottom bar.
Have an X-out button display in the top corner while the scrollview is in full screen. This button can call toggleScrollViewFullScreen to dismiss the view back down.
Example toggleScrollViewFullScreen method:
//Toggle size of scroll view
- (void) toggleScrollViewFullScreen {
CGFloat bottomBarHeight = 100;
if (self.scrollViewHeightConstraint.constant > bottomBarHeight){
self.scrollViewHeightConstraint.constant = bottomBarHeight
}else {
self.scrollViewHeightConstraint.constant = self.view.bounds.size.height;
}
//Animate constraint change:
[UIView animateWithDuration:1 animations:^{
[self.view setNeedsUpdateConstraints];
[self.view setNeedsLayout];
}];
}

uiscrollview pull horizontal to select object base on how far you drag

I have a uiscrollview and I put 4 uiviews to make an option. I put label 1 for uiview1 and label 2 for uiview2, for uiview 3 i put label 3 and uiview4 i put label 4.
After that I hide the 4 uiview so everytime I pulldown the screen the 4 uiviews will display base on how far the user pull.
Can anyone give an example on how to display the which uiview is selected, when you pull the screen in ios iphone?
You can use contentOffset of scroll View to find how far user pulled scroll View.
Use scroll View delegate Method:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
By checking frames of your views & scrollView contentOffset, you can determine which view is visible (i.e. uiview1, uiview2,..).
Edit:
Your logic should be like this:
if(uiview1.frame.origin.y - scrollView.contentOffset.y > uiview1.frame.origin.y + uiview1.frame.size.height)
{
//your logic for selection of uiview1
}else if.......
Apply this conditions from last view to first view.
For your reference, you can see a sample implementation of a page control from here. http://developer.apple.com/library/ios/#samplecode/PageControl/
For the implementation you want, to your surprise, the scrollview's width is actually smaller than 320 (or 480). The magic property to set is:
scrollView.clipsToBounds = NO
The only problem with this implementation is that the scrollview get no touch events if the touch is outside the bounds of the scrollView. This can be fix by passing its parent hitTest event to scrollView.
Just to link to to a better explanation: UIScrollView horizontal paging like Mobile Safari tabs
Slightly different from what I recommend but does the same thing.
Edit:
I have a small project called LXPagingViews that does the above, hopefully in an out of the box manner (Do drop me a pull request or feedback in issue): https://github.com/lxcid/LXPagingViews

iOS 6 Autolayout - ScrollView with embedded ImageView not zooming properly

I am trying to setup a simple view that displays an image and allows users to zoom in/out and pan the image as they desire.
I have autoLayout enabled and the view consists of a UIScrollView with an embedded UIImageView.
Both views are sized to the entire screen.
I used the logic and code from Apple's ScrollViewSuite (the "1_TapToZoom" sample) and everything seems correct. However, when pinching the view, the ScrollView/ImageView gets all distorted and doesn't respond properly. Hard to explain the behavior, but lets just call it "funky". The size and aspect changes in no consistent manner.
My GUESS is that this has to do with autolayout constraints.
Does anyone have some suggestions/fixes for this?
The issues that occurs is the changing of location of the imageview during the zoom process. The origin location of the imageview will change to be a negative value during the zoom. I believe this is why the jerky movement occurs. As well, after the zoom is complete the imageView is still in the wrong location meaning that scrolls will appear to be offset.
If you implement -(void) scrollViewDidZoom:(UIScrollView *)scrollView and log the frame of the UIImageView during this time you can see its origin changing.
I ended up making things work out by implementing a strategy like this: https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch20p573scrollViewAutoLayout/ch20p573scrollViewAutoLayout/ViewController.m
And in addition changing the frame of the contentView while zooming
-(void) scrollViewDidZoom:(UIScrollView *)scrollView {
CGRect cFrame = self.contentView.frame;
cFrame.origin = CGPointZero;
self.contentView.frame = cFrame;
}

How can I let UIScrollView (pagingEnabled) to move 1.2 page each time?

Ok. here is the story:
I have a UIWebView in full screen, width = 768
It loads several images and those images are in one line, which means the UIWebView will scroll only horizontally.
Now, I set the UIScrollView inside the UIWebView to pagingEnabled = YES. So the scroll on the UIWebView will move page by page.
The problem is that every image's width is about 900. I won't scale them down and if I scroll the UIWebView, from the 2nd page on, always 132points of previous image will show. This is not good for me.
So how can I manipulate the UIWebView or the UIScrollView inside the UIWebView so that each scroll will move a page of 900 points, if the view's frame width is 768?
The constraints are:
I can't change its contentSize
I can't change its bounds or frame
I say these constraints because UIWebView will change them on its own purpose when it loads contents.
Anyone would like to join this brain storming?
Thanks
I'm thinking you're going to need to set a UIScrollView delegate that tracks touches beginning and ending. More specifically, scrollViewDidEndDragging:willDecelerate is what I'm thinking you'll need to use, as it fires the instant a user lifts their hand from the device.
First, pagingEnabled=NO seems obvious, we're going to have to control our own paging. Which, I don't feel is too tough. Track the direction of the scrolling in scrollViewDidScroll:, so that we have some global set:
BOOL isGoingRight = YES or NO (NO means the last movement was to the left)
float PAGESIZE = 900.0;
Here's how my scrollview delegate method would look like that handles paging.
- (void) scrollViewDidEndDragging:(UIScrollView*)_scrollView willDecelerate:(BOOL)willDecelerate {
float offsetProportion = _scrollView.contentOffset.x/_scrollView.frame.size.width;
//depending upon our direction, round up or down
int page = isGoingRight? ceilf(offsetProportion): floorf(offsetProportion);
//manually finish the scroll
[_scrollView scrollRectToVisible:CGRectMake(page*PAGESIZE, 0, _scrollView.frame.size.width, _scrollView.frame.size.height) animated:YES];
}
I didn't test this, you may or may not need to disable touches at points.

how to forward UIWebView scroll to UIScrollView ? (conditionally)

I have a UIWebView inside UIScrollView.
This idea is to be able to create more reading space on screen when user scroll the webpage upwards - by scrolling the UIScrollView upwards till the toolbar is visible, and obviously when the toolbars is nomore visible actually scroll the webpage to show more content that's on the page.
IPhone Safari browser does exactly the same functionality.
see screenshot (first) for default behavior i am getting - i guess because : the scrolling message is consumed by the webview since the touch/scroll is happening directly on webview area.
what i would like to do here is programatiicaly decide when to forward the 'upward scroll' to the UIScrollivew and when not to.
Any tips on how to get around this will be so helpful. Thanks!!
The UIWebView class reference discourages embedding a UIWebView in a UIScrollView:
Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.
However I suppose you still want to implement your feature ;-)
Idea 1: Don't embed the UIWebView in a UIScrollView, instead run javascript using UIWebView's stringByEvaluatingJavaScriptFromString: method, modifying the DOM to add a toolbar below. If required, you can callback objective-c code from any buttons pushed on the toolbar by registering some custom URL schemes.
Idea 2: Don't embed the UIWebView in a UIScrollView, but in a normal UIView. Building on Vignesh's suggestion, listen for your webView's inner scrollView's scrollViewDidScroll: callback via the delegate, checking the contentOffset vs. the contentSize's height each time the callback is called. Once they are equal, it means you got to the bottom. Once this happens you can animate your toolbar's frame to "enter" the containing UIView and "push" the webView's frame away.
Idea 3: Ignore Apple's recommendation, and embed the UIWebView in a UIScrollView. Building on Vignesh's suggestion, listen for your webView's inner scrollView's scrollViewDidScroll: callback via the delegate, checking the contentOffset vs. the contentSize's height each time the callback is called. Once they are equal, it means you got to the bottom. Once this happens set the userInteractionEnabled property of the webView to NO, and set it to YES on the scrollView which contains the webView and the toolbar. Hopefully the scroll will continue smoothly enough. Of course you have to listen to the containing scroll view in the same way to determine when to switch back the userInteractionEnabled.
A variation on this idea would be to just set userInteractionEnabled to NO for the webView, but set the webView's frame's height to match its contentSize, and also enlarge the contentSize of the containing scrollView accordingly.
Both variations have the drawback that in some cases you won't be able to do things such as click on links :-( But maybe that's good enough for your case. At least in the first variation it's not so bad.
You can add a searchbox and uiwebview in a UIscrollview one below another. To get the content offset when webview is scrolled you can use the following code snippet.
UIScrollView* currentScrollView;
for (UIView* subView in testWebView.subviews) {
if ([subView isKindOfClass:[UIScrollView class]]) {
currentScrollView = (UIScrollView*)subView;
currentScrollView.delegate = (id)self;
}
}
Now you can change your base scrollview offset's y value to the offset value you get from the scrollview didscroll delegate method.
Advanced ScrollView Techniques
https://developer.apple.com/videos/wwdc/2011/

Resources