I need to create a main menu for my app with a UIScrollView. I have some images inside it that can be clicked. When I scroll the UIScrollView I need that on the background there are other two views that move creating a parallax effect.
Can someone provide me a sample code? I'm trying to work with
-(void) scrollViewDidScroll:(UIScrollView *)scrollView
but I cannot find any productive example about applying on my project.
How's this? The imageView will scroll up half as fast as the UIScrollView.
float y = scrollView.contentOffset.y;
CGRect imageFrame = self.imageView.frame;
imageFrame.origin.y = y/2;
self.imageView.frame = imageFrame;
This GitHub repository has an amazing implementation that works quite well:
https://github.com/ralfbernert/RBParallaxScrolling
Here's my test of the code, using a UIScrollView with pagination (in the front) and an image in the background:
http://clrk.it/211o3h0A053m
The bit of code that does this parallax trick works as follows:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == _scrollView) {
float speedFactor = _headerImageScrollView.contentSize.width / _scrollView.contentSize.width;
[_headerImageScrollView setContentOffset:CGPointMake(speedFactor * _scrollView.contentOffset.x, 0)];
}
}
In this code, I've got a UIScrollView that contains a UIImageView; I call this _headerImageScrollView.
In front of it, I have a second UIScrollView with pagination and the three labels. That one's called _scrollView.
Related
I have a UIScrollView which has about 10+ images laid out horizontally using the following code adapted from apple sample code:
- (void)layoutScrollViewImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView subviews];
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
[scrollView setContentSize:CGSizeMake((kNumImages * kScrollObjWidth),[scrollView bounds].size.height)];
}
The user can page through the images one at a time, in a horizontal manner, but I want each individual image zoomable. I have tried returning my scrollView in viewForZoomingInScrollView but that seems to zoom the entire scrollview, not the individual image. Additionally, I have tried setting the UIImageView as a property and returning that, but still have not had any success. Additionally, I have tried adding a pinch gesture recognizer in storyboard, but that did not work AT ALL. So looking for some guidance on essentially how to return the individual UIImageView within an array of scrollView.subviews.
It sounds like you want something similar to Apples Photo Library effect, where you can swipe from image to image but zoom / scroll per individual image.
You are going to have to put each subview inside it's own zooming scrollview. Then each one can scroll independently of the others.
Take a look at Apple's 'photoscroller' sample code (just search for photoscroller in the docs). There is also a WWDC video to accompany the code (WWDC 2010, "Designing Apps with Scroll Views")
So i got an imageView inside a ScrollView that should resize, which works the way i want (see a small video here: https://dl.dropbox.com/u/80699/scroll.m4v)
what i did is setting up a UIScrollViewDelegate and using the scrollViewDidScroll method to resize my image based on the scrolling offset
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView
{
CGFloat scrollViewOffset = aScrollView.contentOffset.y;
if(scrollViewOffset < 0.0f) {
// postition top
CGRect imageViewRect = self.imageView.frame;
imageViewRect.origin.y = scrollViewOffset;
if(scrollViewOffset < 0.0f && scrollViewOffset >= -50.0f) {
CGFloat newBackdropHeight = kImageHeight - scrollViewOffset;
imageViewRect.size.height = newBackdropHeight;
}
self.imageView.frame = imageViewRect;
}
}
whats basically happening here is, that if the user is scrolling upwards when he is on the top (bounces enabled) the imageView expands with the scroll until a certain amount of offset(here 60px).
the problem with this is, that if i scroll very fast, the image stops resizing, but the rest of the scrollview scrolls fast down like it would normally do. then, when the scrollview snaps back, the image expands immediately and then scales down like it should (see video here: https://dl.dropbox.com/u/80699/scroll2.m4v).
with this behavior, the user-expierience is not very nice and the user sees a jumping image.
does anybody know how i could fix this?
here is a small sample project if you want to see the behavior yourself: https://dl.dropbox.com/u/80699/scroll.zip
thanks for your help!
if anything is unclear, PLEASE leave a comment
I had a quick look at your test project, and I believe the issue is that when you scroll quickly, by the time the callback is called the Y offset is greater than -50, so the image view is not resized.
I solved this by removing the inner if condition and giving the backdrop a maximum height:
if(scrollViewOffset < 0.0f) {
// postition top
CGRect imageViewRect = self.imageView.frame;
imageViewRect.origin.y = scrollViewOffset;
CGFloat newBackdropHeight = kImageHeight - MAX(scrollViewOffset,-50.0);
imageViewRect.size.height = newBackdropHeight;
self.imageView.frame = imageViewRect;
}
Hope that helps
I have created a subclass of UIScrollView that uses the UIScrollViewDelegate. I created it to work with OpenGL ES objects. I have the following code:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
for(InputEntity * iEnt in [sceneInstance inputObjects]){
iEnt.display.translation = GLKVector2Make(0, self.contentOffset.y);
}
}
It eventually puts all the content in the correct spot, but it does not update the locations until after the scroll view has stopped moving. Is there a way to fix this so it looks animated like UIScrollViews do?
do you have render method like setNeedDisplay:
if you have,you can:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
for(InputEntity * iEnt in [sceneInstance inputObjects]){
iEnt.display.translation = GLKVector2Make(0, self.contentOffset.y);
//render here
}
}
what I would like to do is to build a UIScrollView which contains a lots of images, the problem is that I don't want to load all the images to the scroll view at once for performance issues, so if someone can suggest and help me to build a UIScrollView which can add images on runtime, for example when I scroll left I get image and the next image is allocated when needed, paging on.
Use this delegate method for add new image.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
// called on finger up if user dragged. decelerate is true if it will continue moving afterwards
You can implement UIScrollViewDelegate and use its methods like
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
which tells you about any offset changes in the Scroll View, and then you can load whichever image should appear at that offset at run-time. For that, you would have to keep track of the current offset and the page of your scroll view.
Look into the Apple's PageControl Sample Code
This could be a good starting point
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
float currPos = scroll.contentOffset.x;
BOOL movingRight = ( currPos / scroll.frame.size.width ) > 1 ? YES : NO ;
if (movingRight) {
NSLog(#"RIGHT");
[photo2 setImage:[UIImage imageNamed:#"22.jpg"]];
photo2.frame = CGRectMake(scroll.frame.size.width * 2, 0, scroll.frame.size.width, scroll.frame.size.height);
}else{
NSLog(#"LEFT");
[photo2 setImage:[UIImage imageNamed:#"33.jpg"]];
photo2.frame = CGRectMake(0, 0, scroll.frame.size.width, scroll.frame.size.height);
}
//NSLog(#"%f",currPos);
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
UIImage *img = [photo1 getImage];
[photo1 setImage:[photo2 getImage]];
[self.scroll scrollRectToVisible:CGRectMake(self.scroll.frame.size.width, 0, self.scroll.frame.size.width, self.scroll.frame.size.height) animated:NO];
[photo2 setImage:img];
}
I have a paging UIScrollView that pages through multiple full screen images. I am tiling the pages, queuing and dequeuing the UIViews dynamically as the scroll view pages through the collection of images, based on Apple example code.
I have a toolbar button the calls scrollRectToVisible:animated: to move the UIScrollView to a specific image. That works perfectly.
The problem is that if you then do a single touch in the UIScrollView, it scrolls back to the page it was displaying before the button was touched and the scrollRectToVisible:animated: method call scrolled the view.
If your touch is moving, the UIScrollView scrolls as expected, and subsequent touches do not cause the UIScrollView to move back to the original page.
How do I prevent this behavior?
Thanks
jk
You need to use content offset rather than scrollRectToVisible, eg:
[pagingScrollView setContentOffset:[self offsetForPageAtIndex:page] animated:YES];
where offsetForPageAtIndex looks like this:
- (CGPoint)offsetForPageAtIndex:(NSUInteger)index {
CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
CGPoint offset;
offset.x = (pagingScrollViewFrame.size.width * index);
offset.y = 0;
return offset;
}
This is based off the Apple "photoscroller" example code from WWDC 2010, which had a frameForPagingScrollView that looks like this:
- (CGRect)frameForPagingScrollView {
CGRect frame = [[UIScreen mainScreen] bounds];
frame.origin.x -= PADDING;
frame.size.width += (2 * PADDING);
return frame;
}
A full copy of that version of the Photoscroller sample code is here:
https://github.com/jogu/WWDC-2010/tree/master/PhotoScroller
Though Joseph's answer sent me the right way, I had some odd behaviour when rotating the device. I found that using offset.x = (pagingScrollView.bounds.size.width * index); instead worked better.