I have several UILabel inside the child view of a UIScrollView. I believe I've set it up exactly like the functioning UIScrollView I have in another view controller, only this one won't scroll. The contentSize is set to larger than the scrollview frame size and scrollview delegate is set to self. The views are wired up in Interface Builder and the UIScrollview has scrolling enabled, bounces, user interaction and multiple touch enabled. The child UIView also has user interaction enabled. Here is my code:
.h file
#import <UIKit/UIKit.h>
#interface CreditsViewController : UIViewController <UIScrollViewDelegate>
#end
.m file
#import "CreditsViewController.h"
#interface CreditsViewController ()
#property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
#property (nonatomic, strong) IBOutlet UIView *contentView;
#end
#implementation CreditsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.scrollView.delegate = self;
_scrollView.contentSize = _contentView.frame.size;
NSLog(#"scrollview frame size, contentview frame size: %f x %f, %f x %f", _scrollView.frame.size.width, _scrollView.frame.size.height, _contentView.frame.size.width, _contentView.frame.size.height);
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
NSLog(#"in scrollViewWillBeginDragging");
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSLog(#"in scrollViewDidScroll");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
I get scrollview frame size, contentview frame size: 240.000000 x 128.000000, 320.000000 x 568.000000 as the log printout but I never get the statements from the delegate methods. The scrollview is the only child of the view controller so it should be receiving the touch events when I try to scroll. What's going on?
You'll need to implement viewForZoomingInScrollView: and return your _contentView.
Related
I'm relatively new to Xcode, and am in the process of making an app in Objective C with several viewControllers each with a single UIScrollView containing a single UIImage that can be zoomed and scrolled.
This code works for the first image (dermatomes), but I can't figure out how to tweak the UIView to enable zooming and scrolling on the second image (anatomicPlanes). Currently the second image imports correctly to the second UIScrollView, but when I try to zoom it just jumps down and right and remains static there.
The size of the UIScrollViews were set using Interface Builder, no problems there.
viewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIScrollViewDelegate> {
IBOutlet UIScrollView *dermatomeScrollView;
UIImageView *dermatomesImageView;
IBOutlet UIScrollView *anatomicPlaneScrollView;
UIImageView *anatomicPlanesImageView;
}
#property (strong, nonatomic) IBOutlet UIScrollView *dermatomeScrollView;
#property (strong, nonatomic) IBOutlet UIImageView *dermatomesImageView;
#property (strong, nonatomic) IBOutlet UIImageView *anatomicPlanesImageView;
#property (strong, nonatomic) IBOutlet UIScrollView *anatomicPlaneScrollView;
#end
viewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize dermatomeScrollView, anatomicPlanesImageView, dermatomesImageView, anatomicPlaneScrollView;
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return dermatomesImageView;
}
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *dermatomes = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"dermatomes.jpg"]];
self.dermatomesImageView = dermatomes;
dermatomeScrollView. maximumZoomScale = 1.2;
dermatomeScrollView. minimumZoomScale = 0.4;
dermatomeScrollView. delegate = self;
[dermatomeScrollView addSubview:dermatomesImageView];
dermatomeScrollView.zoomScale = 0.6;
UIImageView *planes = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"anatomic planes.jpg"]];
self.anatomicPlanesImageView = planes;
anatomicPlaneScrollView. maximumZoomScale = 1.2;
anatomicPlaneScrollView. minimumZoomScale = 0.4;
anatomicPlaneScrollView. delegate = self;
[anatomicPlaneScrollView addSubview:anatomicPlanesImageView];
anatomicPlaneScrollView.zoomScale = 0.6;
}
Any help is appreciated!
You need to return the correct view based on the scroll view that is requesting. Every method in the delegate pattern is passed a reference to the originator of the method call, so your delegate implementation can handle it differently. In this case, the originator of the delegate method call is the scroll view:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
if (scrollView == dermatomeScrollView) {
return dermatomesImageView;
}
return anatomicPlanesImageView;
}
If you add more scrollviews, you'll have to extend this method further.
I am trying to set up nested UIScrollViews. What I have is two scroll views with the same content size 640*640 setup like this: canvasScrollView (a UIScrollView) > contentScrollView (a UIScrollView) > content (a UIView). These are all in a UIViewController. What I want to happen is, when the user pinches to zoom in on the content in contentScrollView the canvasScrollView view zooms out at with same factor and speed. I have tried setting up code like below:
#import "ViewController.h"
#import "ContentView.h"
#interface ViewController () <UIScrollViewDelegate>
#property (weak, nonatomic) IBOutlet UIScrollView *canvasScrollView;
#property (strong, nonatomic) UIView *viewForZoom;
#property (strong, nonatomic) ContentView *content;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *contentScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 568)];
contentScrollView.contentSize=CGSizeMake(640 ,640);
contentScrollView.minimumZoomScale=0.25;
contentScrollView.maximumZoomScale=1;
self.content = [[[NSBundle mainBundle] loadNibNamed:#"floatingView" owner:self options:nil] objectAtIndex:0];
self.viewForZoom=self.content;
[contentScrollView addSubview:self.content];
contentScrollView.delegate=self;
//canvasScrollView was setup in the interface builder, same dimensions as above 320*568
self.canvasScrollView.contentSize=CGSizeMake(640 ,640);
self.canvasScrollView.minimumZoomScale=0.25;
self.canvasScrollView.maximumZoomScale=1;
self.canvasScrollView.userInteractionEnabled=NO;
[self.canvasScrollView addSubview:contentScrollView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.viewForZoom;
}
My first step is to make sure it is the contentScrollView that zooms and not the canvasScrollView. With my code above the views load up fine but I am unable to pan or zoom the content. I'm not sure why this doesn't work. I have disabled the canvasScrollView from user interaction as later on this will be modified programmatically, I have also set the contentScrollView delegate. Not working though. Would really appreciate some help on this one!!!
Thanks
You have added contentScrollView to a view that has userInteractionEnabled=NO. A view that doesn't allow user interaction does not allow user interaction any of its subviews. Try attaching it to the self.view instead.
[self.view addSubview:contentScrollView];
I'm Making a game, with level select Ive got 3 levels and 3 views on 3 different controllers
Now I've placed 2 - 1/4 of the button on each side of my scroll view, on on the left and one on the right!
When the user of the game is on level 1 "thats View1" The button on the left needs to be hidden and only show when its on View2 and View 3 - same goes for the button on View3 on the right!
How is this done?
Outlets for those buttons are leftIllusion & rightIllusion
code for UIViews:
#implementation ViewController
#synthesize View1;
#synthesize View2;
#synthesize View3;
- (void)viewDidLoad
{
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"View1"]];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"View2"]];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"View3"]];
}
code from that imports scroll file .h:
#import "PagerViewController.h"
#interface ViewController : PagerViewController {
}
#property (strong, nonatomic) IBOutlet UIView *View1;
#property (strong, nonatomic) IBOutlet UIView *View2;
#property (strong, nonatomic) IBOutlet UIView *View3;
#end
UIScrollView instance has property contentOffset, which can help you to detect what view is being displayed now (view1, view2, view3). I am posting example code-snippet, which helps me to determine the page number of scrollView.
- (NSInteger)pageNumber
{
static NSInteger previousPage = 0;
CGFloat pageWidth = self.scrollView.frame.size.width;
float fractionalPage = self.scrollView.contentOffset.x / pageWidth;
NSInteger page = lround(fractionalPage);
NSLog(#"page number %d",page);
if (previousPage != page) {
previousPage = page;
/* Page did change */
//put here your hide/show buttons logics
}
return page;
}
The best place to insert these lines is scrollView delegate's method -(void)scrollViewDidEndDecelerating:. The scroll view calls this method each time when the scrolling movement comes to a halt.
So your final version will look like:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender
{
[self pageNumber];
}
When the user zooms far enough out of the image by pinching out, then releases, I want it to close the UIImageView/scroll view, basically exiting the picture viewer.
How would I go about doing this? scrollViewDidEndZooming is called after it animates back into place, so I can't use that, and none of the other delegate methods seem helpful.
i have create this effect for one of my app, dont forget to set delegate of your scrollview.
you need to update the private method with your pinch gesture(thats all)
code for .h file
#import <UIKit/UIKit.h>
#interface ImageViewerController : UIViewController<UIScrollViewDelegate>
// The scroll view used for zooming.
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
// The image view that displays the image.
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
// The image that will be shown.
#property (strong, nonatomic) NSString *imageUrlString;
#end
code for .m
#import "ImageViewerController.h"
#interface HNImageViewerController ()
- (IBAction)handleSingleTap:(UIButton*)tapGestureRecognizer;
#end
#implementation ImageViewerController
- (void)viewDidLoad {
[super viewDidLoad];
[self.imageView setImage:[UIImage imageNamed:#"placeholder-image"]];
self.scrollView.delegate=self;
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
#pragma mark - UIScrollViewDelegate methods
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.imageView;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (self.scrollView.zoomScale == self.scrollView.minimumZoomScale) {
[self dismissViewControllerAnimated:YES completion:nil];
}
}
#pragma mark - Private methods
- (IBAction)handleSingleTap:(UIButton *)tapGestureRecognizer {
[self dismissViewControllerAnimated:YES completion:nil];
}
so i have a navigation controller, and in it i have a view and a scrollview embedded in that view. My goal is to make my program scroll to a location when it is close to it.
to do this i added to outlets to my vc. one is the scroll view and the other is the view. The view is just a big rectangle about twice as wide as the iphones screen and slightly higher. My scroll view scrolls only horizantally, and whenever i lift my finger from scrolling, my goal is if the iphones bounds are within the views bounds. I want the scroll view to manually scroll to the middle of that view. (if you can think of a game menu in angry birds or cut the rope, when the user is scrolling between level packs horizantally, when the user lets go from scrolling it sort of zaps into place to the level the user let go by, this is what i want to mimick).
so, heres my code for both my view and my vc. The only thing i did with storyboards is that i hooked up the two outlets, and set the size of my view.
(the level packs is the vc and the other one is the view).
#import <UIKit/UIKit.h>
#import "HorizantalLockingView.h"
#interface LevelPacks : UIViewController <ViewDelegate>
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#property (weak, nonatomic) IBOutlet HorizantalLockingView *lockingView;
#end
#import "LevelPacks.h"
#implementation LevelPacks
#synthesize scrollView=_scrollView;
#synthesize lockingView = _lockingView;
-(void)viewDidAppear:(BOOL)animated
{
CGSize size;
size.width=825;
size.height=460;
self.scrollView.contentSize=size;
self.scrollView.contentOffset=CGPointMake(0, 0);
}
-(void)viewDidLoad
{
[super viewDidLoad];
self.lockingView.delegate=self;
}
- (void)viewDidUnload
{
[self setLockingView:nil];
[super viewDidUnload];
self.scrollView=nil;
// Release any retained subviews of the main view.
}
#end
#import <UIKit/UIKit.h>
#protocol ViewDelegate
#property (nonatomic, weak) UIScrollView *scrollView;
#end
#interface HorizantalLockingView : UIView
#property (nonatomic, weak) IBOutlet id <ViewDelegate> delegate;
#end
#import "HorizantalLockingView.h"
#implementation HorizantalLockingView
#synthesize delegate=_delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect location=self.superview.bounds;
NSLog(#"dkfjdkjf");
if (CGRectContainsRect(self.frame, location))
{
[self.delegate.scrollView scrollRectToVisible:CGRectMake(284, 190, 157, 119) animated:YES];
}
}
#end
o, and i did the nslog earlier to see if the method would even do anything, and the nslog never even ran, so obviously somethings wrong.
Im kind of new to this, any help would really be great!
Enabling paging will automatically do this for you.
scrollView.pagingEnabled=YES;
Also adding a UIPageControl and using the UIScrollView delegate methods to update the page control will add a good usability