Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Detect touch in scrollview - tutorial

elpuercoelpuerco Posts: 136Tutorial Authors
edited June 2012 in iPhone SDK Tutorials
Hi,

have spent an age searching for the answer to this problem and found a number of references to the solution, i.e subclassing the UIScrollView class, but no examples.

I found a lot of people asking the same question as me (or rather I was asking same as them lol)

So I created an app from scratch and thought I would post the detail here for others to use. learn or flame at bad coding....but it works for me so I am happy!

OK..here goes:

Start a new project called ScrollViewTapDetectionViewController of class UIViewController.

Here is the code, read my comments...
#import <UIKit/UIKit.h>

// these will be covered in a flie to come later in this tutorial 
:) @class myScrollView; @class myImageView; // make sure you set this to be a UIScrollViewDelegate! @interface ScrollViewTapDetectionViewController : UIViewController <UIScrollViewDelegate> { // this will be our UIScrollView subclass myScrollView *contentView; // this will be our UIImageView subclass myImageView *imageView; } @property (retain, nonatomic) myScrollView *contentView; @property (retain, nonatomic) myImageView *imageView; @end
Now create another class of UIViewController and name it myScrollView

here is the code, again read my comments...
#import <UIKit/UIKit.h>

// change the class to be of type UIScrollView that is all for this file 
:) @interface myScrollView : UIScrollView { } @end
And again add another class of type UIViewController

here is the code, again read my comments...
#import <UIKit/UIKit.h>

// change the class to be of type UIImageView that is all for this file 
:) @interface myImageView : UIImageView { } @end
Now open the file myScrollView.m and ad this code, read my comments ;-)
#import "myScrollView.h"


@implementation myScrollView

// This code is from ThirtyOne's post.....thanks a million TO ;-)

-(void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event 
{	
	if (!self.dragging) {
		[self.nextResponder touchesEnded: touches withEvent:event]; 
	}		

	[super touchesEnded: touches withEvent: event];
}

Now open the file myImageView.m and add this code ;-)
#import "myImageView.h"


@implementation myImageView

// simple method you should be familiar with!

-(void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
{
	NSLog(@Touch detected);
}


Now for the nitty gritty to pull it all together :)
// import the required header files 

#import "ScrollViewTapDetectionViewController.h"
#import "myScrollView.h"
#import "myImageView.h"

@implementation ScrollViewTapDetectionViewController

@synthesize contentView;
@synthesize imageView;

// we want the instance of our myImageView to be the one used for scrolling

-(UIView *) viewForZoomingInScrollView: (UIScrollView *) ScrollView
{
	return imageView;
}

-(void) loadView
{
        // set the image to be displayed, pic your own image here

	imageView = [[myImageView alloc] initWithImage: [UIImage imageNamed: @AnyOldImage.png]];

        // yes we want to allow user interaction

	[imageView setUserInteractionEnabled:YES];
	
        // set the instance of our myScrollView to use the main screen

	contentView = [[myScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
	
        // turn on scrolling

	[contentView setScrollEnabled: YES];
 	
        // set the content size to the size of the image

	[contentView setContentSize: imageView.image.size];

        // add the instance of our myImageView class to the content view
	
	[contentView addSubview: imageView];

        // flush the item
	
	[imageView release];

       // set max zoom to what suits you
	
	[contentView setMaximumZoomScale:1.0f];
	
       // set min zoom to what suits you

	[contentView setMinimumZoomScale:0.25f];
	
       // set the delegate

	[contentView setDelegate: self];
  
        // scroll a portion of image into view (my image is very big) 
:) [contentView scrollRectToVisible:CGRectMake(400, 400, 320, 440) animated:NO]; // yes to autoresize contentView.autoresizesSubviews = YES; // set the mask contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); // set the view self.view =contentView; }
Now compile and run your app and ensure you have the console open.

Drag the image around, zoom in and out etc and nothing appears in the console which is what we want. But not just click on the image and hey presto.......the text Touch detected appears :)


hope this helps someone :)

NB I have not entered the code for release instance variables etc....you can do that ;-)
Post edited by elpuerco on
«1

Replies

  • Chris StewartChris Stewart Posts: 765Administrators Admin
    edited January 2009
    Thanks for sharing your experience! I think this thread would be better served in the Tutorials forum. Would you like me to move it there for others to view and learn from? In return, I can make you a Tutorial Author on the site which will allow you to create threads in the Tutorials forum in the future.
    Founder, <a href="http://locomolabs.com&quot; target="_blank">Locomo Labs, LLC</a><br />
    <a href="http://itunes.apple.com/us/app/socialblast/id461401661?ls=1&mt=8&quot; target="_blank">SocialBlast</a> -- iPhone/iPad -- Update Twitter/Facebook/LinkedIn/Foursqua
  • elpuercoelpuerco Posts: 136Tutorial Authors
    edited January 2009
    Hi, yes that would be great thanks and as I progress I shall add more :)
  • ipodgreatmasteripodgreatmaster Posts: 92Registered Users
    edited February 2009
    It would be great if you can make a video for this
    Independent developer<br />
    Please excuse me by my bad english. English is not my native language<br />
    <br />
    Sabius Software<br />
    <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewArtist?id=320539244&quot; target="_blank">Link To App Store<
  • bullalebullale Posts: 6New Users
    edited February 2009
    I am going to attach an application that I made. It passes touches in UIScrollView to subviews.

    Using IB, I made the following:

    Window
    -View
    --UIScrollView
    ---UIView (*contentView)
    ----MyImageView
    ----UIButton

    I had to make the AppDelegate the UIScrollView delegate. Within the AppDelegate I implemented the zoom view method.
    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    	return contentView;
    }
    

    Since the UIImage and UIButton are subviews of the UIView, they scroll and zoom together.

    UIButton's touch up inside method can be linked to an IBAction. In this case I linked it to a method in the appDelegate that prints an NSLog line.

    I had to subclass UIImageView (MyImageView) to implement a touches method:
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    	NSLog(@ImagePressed);
    }
    

    I had to check UserInteractionEnabled for the contentView, MyImageView, and the UIButton.

    Note however that I did not have to use ThirtyOne's code. I did not have to subclass UIScrollView. It seems as though the documentation is telling the truth in that UIScrollView passes touches to the subviews by default. (Look for touchesShouldBegin in the documentation).

    Also note that touches are passed immediately when zoomed all the way out (no scrolling possible). But when zoomed in some, touches only pass after a short delay (to make sure the touch isn't a scroll).

    I made this with IB in 10 minutes. I am trying to get this to work using view controllers and programming my view hierarchy manually, but have not been successful yet.
  • bullalebullale Posts: 6New Users
    edited February 2009
    The forum limit for attachments is much smaller than the file. Anyone know where I can put it? Or you can just pm me or e-mail me if you want me to send it to you.
  • seanriceseanrice Posts: 86Registered Users
    edited February 2009
    Hi, I'm Sean. I think it sounds great and i'd love to see how you did it. I'm actually faced with exactly this situation and posted a Question on this to the forums. I basically built a scrollView and loaded it with buttons horizontally. 33 to be exact. Now i need to trap the (id)Sender information or the buttons, but can't figure out how to link them to an IBAction (one function for all), must less a firstResponder's IBAction ... where my global actions reside.

    Thanks! :) for any help.
  • hakimnyhakimny Posts: 72Registered Users
    edited April 2009
    Thank you so much with this tutorial , you really made my day
  • elpuercoelpuerco Posts: 136Tutorial Authors
    edited April 2009
    seanrice wrote: »
    Hi, I'm Sean. I think it sounds great and i'd love to see how you did it. I'm actually faced with exactly this situation and posted a Question on this to the forums. I basically built a scrollView and loaded it with buttons horizontally. 33 to be exact. Now i need to trap the (id)Sender information or the buttons, but can't figure out how to link them to an IBAction (one function for all), must less a firstResponder's IBAction ... where my global actions reside.

    Thanks! :) for any help.

    You can link all the buttons to the same method in your code from IB.

    You can do the same if creating the button progmatically using addTarget.

    Lastly you could also add a unique tag to each button and query that in your single method.
  • elpuercoelpuerco Posts: 136Tutorial Authors
    edited April 2009
    hakimny wrote: »
    Thank you so much with this tutorial , you really made my day

    Glad to help ;-)
  • WaRcLaWzWaRcLaWz Posts: 36Registered Users
    edited May 2009
    I am so happy that I found your post! I have been struggling with this issue for quite some time now, and who would have thought that all I had to do was just sub-class the UIImageView and the UIScrollView. Woohoo! :)

    It made me decide to become a subscriber to iPhone Dev SDK.
  • RodOfIPODRodOfIPOD Posts: 21Registered Users
    edited June 2009
    There are some minor issues but i found this very helpful.

    What would you do differently if you wanted this to work with absolutely NO IB usage. I really despise that tool.

    Pretend we throw away the IB file and then how would that effect your code as it uses IB in 2 places.....

    Thanks!
  • RodOfIPODRodOfIPOD Posts: 21Registered Users
    edited June 2009
    So i added the following code (i tried both before the [contentView addSubview: imageView] and after) to your LoadView routine:
    	CGContextRef context = UIGraphicsGetCurrentContext();
    	CGContextSetRGBStrokeColor(context, .97, .83, .15, 1.0);
    	CGContextSetRGBFillColor(context, 0.0, 0.0, 1, 1.0);
    	CGContextSetLineWidth(context, 1.0);
    	CGContextAddRect(context, CGRectMake(100, 100, 100, 100));
    	CGContextStrokePath(context);
    	
    	[[UIColor redColor] set];
    	UIFont *font = [UIFont boldSystemFontOfSize:16];
    	CGPoint point = CGPointMake(100,100);
    	[@HELLO drawAtPoint:point withFont:font];
    


    and neither the box nor the text shows up and yet it shows up perfectly in my non scroll view from my app :P

    I guess my real question is how do i attach text and or rectangle drawings to an image so that the image can include these?

    Any ideas?
  • seanriceseanrice Posts: 86Registered Users
    edited June 2009
    I might be missing something, but i'd suggest just adding a Label on top of your image and (through some iteration) setting the Label.text as appropriate each time through the loop.

    I basically solved my problem above by:

    1) create my content UIView
    2) load my girls from a Plist into an NSDictionary
    3) start a loop which, for each girl in list, determines image(s) based on whether the user has clicked the button before or not ... and sets the labels appropriately, and calculates the position on the scroll view for the button, and passes all this to another method (createButtonForGirl) which actually creates the button, loads it onto the view and returns to the loop event ... repeating this step until all are loaded =) and then (finally) once completed we load the SwipeView with the ContentView and then addSubview:SwipeView =)

    My first product is called uOrgasm (www.drummerboy.me) and is waiting approval from Apple. =) chow and Good Luck !!!!
  • RodOfIPODRodOfIPOD Posts: 21Registered Users
    edited June 2009
    Yes i was successfully able to get the labels to show but i still cant get things like rects to show OR move.. my frustration grows.
  • shiva.0537shiva.0537 Posts: 54Registered Users
    edited June 2009
    elpuerco wrote: »
    Hi,

    have spent an age searching for the answer to this problem and found a number of references to the solution, i.e subclassing the UIScrollView class, but no examples.

    I found a lot of people asking the same question as me (or rather I was asking same as them lol)

    So I created an app from scratch and thought I would post the detail here for others to use. learn or flame at bad coding....but it works for me so I am happy!

    OK..here goes:

    Start a new project called ScrollViewTapDetectionViewController of class UIViewController.

    Here is the code, read my comments...
    #import <UIKit/UIKit.h>
    
    // these will be covered in a flie to come later in this tutorial 
    :) @class myScrollView; @class myImageView; // make sure you set this to be a UIScrollViewDelegate! @interface ScrollViewTapDetectionViewController : UIViewController <UIScrollViewDelegate> { // this will be our UIScrollView subclass myScrollView *contentView; // this will be our UIImageView subclass myImageView *imageView; } @property (retain, nonatomic) myScrollView *contentView; @property (retain, nonatomic) myImageView *imageView; @end
    Now create another class of UIViewController and name it myScrollView

    here is the code, again read my comments...
    #import <UIKit/UIKit.h>
    
    // change the class to be of type UIScrollView that is all for this file 
    :) @interface myScrollView : UIScrollView { } @end
    And again add another class of type UIViewController

    here is the code, again read my comments...
    #import <UIKit/UIKit.h>
    
    // change the class to be of type UIImageView that is all for this file 
    :) @interface myImageView : UIImageView { } @end
    Now open the file myScrollView.m and ad this code, read my comments ;-)
    #import "myScrollView.h"
    
    
    @implementation myScrollView
    
    // This code is from ThirtyOne's post.....thanks a million TO ;-)
    
    -(void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event 
    {	
    	if (!self.dragging) {
    		[self.nextResponder touchesEnded: touches withEvent:event]; 
    	}		
    
    	[super touchesEnded: touches withEvent: event];
    }
    

    Now open the file myImageView.m and add this code ;-)
    #import "myImageView.h"
    
    
    @implementation myImageView
    
    // simple method you should be familiar with!
    
    -(void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
    {
    	NSLog(@Touch detected);
    }
    
    

    Now for the nitty gritty to pull it all together :)
    // import the required header files 
    
    #import "ScrollViewTapDetectionViewController.h"
    #import "myScrollView.h"
    #import "myImageView.h"
    
    @implementation ScrollViewTapDetectionViewController
    
    @synthesize contentView;
    @synthesize imageView;
    
    // we want the instance of our myImageView to be the one used for scrolling
    
    -(UIView *) viewForZoomingInScrollView: (UIScrollView *) ScrollView
    {
    	return imageView;
    }
    
    -(void) loadView
    {
            // set the image to be displayed, pic your own image here
    
    	imageView = [[myImageView alloc] initWithImage: [UIImage imageNamed: @AnyOldImage.png]];
    
            // yes we want to allow user interaction
    
    	[imageView setUserInteractionEnabled:YES];
    	
            // set the instance of our myScrollView to use the main screen
    
    	contentView = [[myScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
    	
            // turn on scrolling
    
    	[contentView setScrollEnabled: YES];
     	
            // set the content size to the size of the image
    
    	[contentView setContentSize: imageView.image.size];
    
            // add the instance of our myImageView class to the content view
    	
    	[contentView addSubview: imageView];
    
            // flush the item
    	
    	[imageView release];
    
           // set max zoom to what suits you
    	
    	[contentView setMaximumZoomScale:1.0f];
    	
           // set min zoom to what suits you
    
    	[contentView setMinimumZoomScale:0.25f];
    	
           // set the delegate
    
    	[contentView setDelegate: self];
      
            // scroll a portion of image into view (my image is very big) 
    :) [contentView scrollRectToVisible:CGRectMake(400, 400, 320, 440) animated:NO]; // yes to autoresize contentView.autoresizesSubviews = YES; // set the mask contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); // set the view self.view =contentView; }
    Now compile and run your app and ensure you have the console open.

    Drag the image around, zoom in and out etc and nothing appears in the console which is what we want. But not just click on the image and hey presto.......the text Touch detected appears :)


    hope this helps someone :)

    NB I have not entered the code for release instance variables etc....you can do that ;-)

    HI,

    Nice post

    You could have shared that application. It will be more helpful
  • stlaustlau Posts: 109Registered Users
    edited July 2009
    elpuerco wrote: »
    Hi,

    have spent an age searching for the answer to this problem and found a number of references to the solution, i.e subclassing the UIScrollView class, but no examples.

    I found a lot of people asking the same question as me (or rather I was asking same as them lol)

    So I created an app from scratch and thought I would post the detail here for others to use. learn or flame at bad coding....but it works for me so I am happy!

    OK..here goes:

    Start a new project called ScrollViewTapDetectionViewController of class UIViewController.

    Here is the code, read my comments...
    #import <UIKit/UIKit.h>
    
    // these will be covered in a flie to come later in this tutorial 
    :) @class myScrollView; @class myImageView; // make sure you set this to be a UIScrollViewDelegate! @interface ScrollViewTapDetectionViewController : UIViewController <UIScrollViewDelegate> { // this will be our UIScrollView subclass myScrollView *contentView; // this will be our UIImageView subclass myImageView *imageView; } @property (retain, nonatomic) myScrollView *contentView; @property (retain, nonatomic) myImageView *imageView; @end
    Now create another class of UIViewController and name it myScrollView

    here is the code, again read my comments...
    #import <UIKit/UIKit.h>
    
    // change the class to be of type UIScrollView that is all for this file 
    :) @interface myScrollView : UIScrollView { } @end
    And again add another class of type UIViewController

    here is the code, again read my comments...
    #import <UIKit/UIKit.h>
    
    // change the class to be of type UIImageView that is all for this file 
    :) @interface myImageView : UIImageView { } @end
    Now open the file myScrollView.m and ad this code, read my comments ;-)
    #import "myScrollView.h"
    
    
    @implementation myScrollView
    
    // This code is from ThirtyOne's post.....thanks a million TO ;-)
    
    -(void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event 
    {	
    	if (!self.dragging) {
    		[self.nextResponder touchesEnded: touches withEvent:event]; 
    	}		
    
    	[super touchesEnded: touches withEvent: event];
    }
    

    Now open the file myImageView.m and add this code ;-)
    #import "myImageView.h"
    
    
    @implementation myImageView
    
    // simple method you should be familiar with!
    
    -(void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
    {
    	NSLog(@Touch detected);
    }
    
    

    Now for the nitty gritty to pull it all together :)
    // import the required header files 
    
    #import "ScrollViewTapDetectionViewController.h"
    #import "myScrollView.h"
    #import "myImageView.h"
    
    @implementation ScrollViewTapDetectionViewController
    
    @synthesize contentView;
    @synthesize imageView;
    
    // we want the instance of our myImageView to be the one used for scrolling
    
    -(UIView *) viewForZoomingInScrollView: (UIScrollView *) ScrollView
    {
    	return imageView;
    }
    
    -(void) loadView
    {
            // set the image to be displayed, pic your own image here
    
    	imageView = [[myImageView alloc] initWithImage: [UIImage imageNamed: @AnyOldImage.png]];
    
            // yes we want to allow user interaction
    
    	[imageView setUserInteractionEnabled:YES];
    	
            // set the instance of our myScrollView to use the main screen
    
    	contentView = [[myScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
    	
            // turn on scrolling
    
    	[contentView setScrollEnabled: YES];
     	
            // set the content size to the size of the image
    
    	[contentView setContentSize: imageView.image.size];
    
            // add the instance of our myImageView class to the content view
    	
    	[contentView addSubview: imageView];
    
            // flush the item
    	
    	[imageView release];
    
           // set max zoom to what suits you
    	
    	[contentView setMaximumZoomScale:1.0f];
    	
           // set min zoom to what suits you
    
    	[contentView setMinimumZoomScale:0.25f];
    	
           // set the delegate
    
    	[contentView setDelegate: self];
      
            // scroll a portion of image into view (my image is very big) 
    :) [contentView scrollRectToVisible:CGRectMake(400, 400, 320, 440) animated:NO]; // yes to autoresize contentView.autoresizesSubviews = YES; // set the mask contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); // set the view self.view =contentView; }
    Now compile and run your app and ensure you have the console open.

    Drag the image around, zoom in and out etc and nothing appears in the console which is what we want. But not just click on the image and hey presto.......the text Touch detected appears :)


    hope this helps someone :)

    NB I have not entered the code for release instance variables etc....you can do that ;-)

    I tried. but it seems the imageview still cannot reponse the multi-touch message?
    <a href="http://lymobilesoft.com/blog/?p=160&quot; target="_blank"><br />
    AppRelease</a> - Track your App Release Dates(Source Code provided).<br />
    <a href="http://www.lymobilesoft.com&quot; target="_blank">LY MobileSoft</a> on <a href="http://itunes.com/apps/ly
  • anils_dasanils_das Posts: 51Registered Users
    edited July 2009
    in 3.0 sdk this is not working. I think this is the issue


    Issue: Touches are no longer forwarded to a UIScrollView in 3.0.

    Calling touchesBegan/touchesMoved/touchesEnded/touchesCancelled methods directly is not supported. Previously, all touches in subviews of a UIScrollView were hit tested to the UIScrollView itself, which then attempted to forward the touches to the correct content view. This often resulted in the UIScrollView having its touchesBegan/touchesMoved/touchesEnded/touchesCancelled methods called twice for each event. In 3.0 this is no longer the case, and UIScrollView now behaves the same as every other UIKit-provided view. Whichever content view was actually touched is returned from hitTest, and if that view implements the UIResponder touch methods and doesn't call super, then the responder methods for UIScrollView will never get called. Instead, use touchesShouldBegin:withEvent:inContentView: or touchesShouldCancelInContentView:.


    how can we solve that?
    anil
  • slahteineslahteine Posts: 196New Users
    edited July 2009
    anils_das wrote: »
    Issue: Touches are no longer forwarded to a UIScrollView in 3.0. ... how can we solve that?

    The answer is, you must handle touch events in the subview and modify the behavior of the scroll view by setting its canCancelContentTouches and delaysContentTouches flags appropriately.

    When delaysContentTouches is set to YES, no event is sent to your subView until it can be determined that it is NOT a scroll gesture. Thus this flag always causes a delay (unless you tap very quickly).

    With delaysContentTouches set to NO, the event is sent immediately to your subview. If canCancelContentTouches is set to YES then any gesture that is "scrolly enough" will (by default) cancel events to your subview and initiate scrolling. If canCancelContentTouches is set to NO then no scrolling will occur, no matter what gesture occurs.

    With canCancelContentTouches set to YES you can use the touchesShouldCancelInContentView method in your UIScrollView subclass to allow or disallow scrolling based on whatever criteria you want. For example, if you only want to allow scrolling when a finger swipe is mostly vertical, but not if it's at or under 45°, you can test for this in your subView's touch processing and set the value of a BOOL variable that touchesShouldCancelInContentView can return.

    This should work in theory, though I haven't fully implemented it yet. It may happen that a swipe at 10° will cause scrolling to start before the subView can determine that the angle is too oblique (or too obtuse, for that matter).

    The delaysContentTouches flag causes the scrollView to start a timer when it's first touched, and when the timer runs out it either scrolls its contents or starts streaming events to the subview. (A sufficiently scrolly gesture will also cancel the timer and start scrolling.) Unfortunately there's no documented way to change the duration of the timer or to implement your own scroll-worthy test in your UIScrollView subclass, so the only option seems to be what I've outlined.
    | I wrote <a href="http://www.thinkyhead.com/chordcalc&quot; target="_blank">ChordCalc</a>, <i>A fretboard 'calculator' for iOS</i> and <a href="http://www.thinkyhead.com/fretpet&quot; target="_blank">FretPet</a>, <i>a guitar-oriented music sequencer for OS X</i>.
  • anuragphadkeanuragphadke Posts: 9New Users
    edited September 2009
    Scott,
    I am trying to implement what you said.. Here's my code
    I added a hittest method in my ScrollView
    -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    	scrollView.delaysContentTouches = YES;
            return self;
    

    The above code allows me to detect all my touches in UIScrollview. For eg:
    -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    	NSLog(@touch moved);
    }
    

    However, I can no longer perform any swipe, scroll or any other gesture in my WebView class implemented inside UIScrollView.

    without
    return self
    
    everything works but I cannot recognize any gestures.

    Any tips?
  • hakimnyhakimny Posts: 72Registered Users
    edited September 2009
    Scott,
    I am trying to implement what you said.. Here's my code
    I added a hittest method in my ScrollView
    -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    	scrollView.delaysContentTouches = YES;
            return self;
    

    The above code allows me to detect all my touches in UIScrollview. For eg:
    -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    	NSLog(@touch moved);
    }
    

    However, I can no longer perform any swipe, scroll or any other gesture in my WebView class implemented inside UIScrollView.

    without
    return self
    
    everything works but I cannot recognize any gestures.

    Any tips?


    This is what I use in my subclass of UIScrollView

    // Code begin here

    @implementation MyScrollView
    @synthesize imageId;

    -(void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
    {

    NSLog(@Inside Touches Began);
    if (!self.dragging) {
    //********** not Dragging ***************
    [self.nextResponder touchesEnded: touches withEvent:event];

    for (UITouch *touch in touches) {

    for (int i = 1; i < [self subviews].count; i++)
    {
    //Looping thru all images to see which one was touched

    if(CGRectContainsPoint([[self viewWithTag:i]frame], [touch locationInView:self])){
    NSLog(@touched %d th view,i);
    //get current image if not dragging
    self.imageId = i;
    }
    }
    }


    }

    else{
    for (UITouch *touch in touches) {

    for (int i = 1; i < [self subviews].count; i++)
    {

    //*************** Dragging **********************
    if(CGRectContainsPoint([[self viewWithTag:i]frame], [touch locationInView:self])){
    NSLog(@touched %d th view,i+1);
    //get next image if dragging
    self.imageId = i+1;
    }
    }
    }
    }
    [super touchesEnded: touches withEvent: event];
    }

    Hope this helps
  • anuragphadkeanuragphadke Posts: 9New Users
    edited September 2009
    hakimny,
    This doens't work for me as the touchesEnded doesn't even get invoked. The only way for me to access the touch detection is via the hittest method, and then I run in everything else except touches event freezing
  • slahteineslahteine Posts: 196New Users
    edited September 2009
    Your code in hitTest isn't doing anything useful, so you might as well drop that. The property you're setting there is sticky, you can just set it on your scroll view and leave it set.

    However, you DON'T want to set delaysContentTouches to YES, because it will only allow touch-up events to be detected in your subviews. That's why your web view can only receive simple taps, and not swipes.

    Instead, set canCancelContentTouches=YES and delaysContentTouches=NO, then implement -touchesShouldCancelInContentView: on your scrollview. This is called the moment you do anything that could scroll the view. You should return YES if you want to allow the scroll to happen, and NO if you want to prevent it.

    Since you have subviews inside your scrollview that want to receive swipes and things, you can simply set a BOOL flag (e.g., a global var or a property in your scrollview) to NO whenever one of those subviews receives any touch event, then return that flag from touchesShouldCancelInContentView:. When your subview is done ( receives -touchesEndedWithEvent: ) reset the flag to YES to reallow scrolling.

    Either way, touchesShouldCancelInContentView: is the key.
    | I wrote <a href="http://www.thinkyhead.com/chordcalc&quot; target="_blank">ChordCalc</a>, <i>A fretboard 'calculator' for iOS</i> and <a href="http://www.thinkyhead.com/fretpet&quot; target="_blank">FretPet</a>, <i>a guitar-oriented music sequencer for OS X</i>.
  • anuragphadkeanuragphadke Posts: 9New Users
    edited September 2009
    scott,
    I followed your suggestions, but the touchesBegan, touchesEnded etc. is still unable to receive anything. Here's the code:
    #import "PageScrollView.h"
    @implementation PageScrollView
    
    
    -(id)initWithFrame:(CGRect)frame : (int)showPage {
        self = [ super initWithFrame: frame ];
        if (self != nil) {
            _pages = nil;
            _pageRegion = CGRectMake(0.0, 0.0, 320.0,420.0);
    
            _controlRegion = CGRectMake(0.0, 420.0,320.0, 0.0);
    		
            self.delegate = nil;
    		
            scrollView = [ [ UIScrollView alloc ] initWithFrame: _pageRegion ];
    		scrollView.pagingEnabled = YES;
    		scrollView.clipsToBounds = YES;
    		scrollView.userInteractionEnabled = YES;
    		scrollView.scrollEnabled = YES;
    		scrollView.delaysContentTouches = NO;
    		scrollView.canCancelContentTouches = YES;
    		scrollView.directionalLockEnabled = YES;
    		scrollView.delegate = self;
    		scrollView.minimumZoomScale = 1.0;
    		scrollView.maximumZoomScale = 5.0;
            [ self addSubview: scrollView ];
    		
            pageControl = [ [ UIPageControl alloc ] initWithFrame: _controlRegion ];
            [ pageControl addTarget: self action: @selector(pageControlDidChange
    :) forControlEvents: UIControlEventValueChanged ]; [ self addSubview: pageControl ]; [ scrollView setContentOffset: CGPointMake(_pageRegion.size.width * showPage, scrollView.contentOffset.y) animated: YES ]; pageControl.currentPage = showPage; } else { pageControl.currentPage = showPage; } return self; } -(void)myPage:(int) myPage { NSLog(@MY PAGE: %d, myPage); } -(void)setPages:(NSMutableArray *)pages { if (_pages != nil) { for(int i=0;i<[_pages count];i++) { [ [ _pages objectAtIndex: i ] removeFromSuperview ]; } } _pages = pages; scrollView.contentOffset = CGPointMake(0.0, 0.0); scrollView.contentSize = CGSizeMake(_pageRegion.size.width * [ _pages count ], 0.0); scrollView.backgroundColor = [UIColor darkGrayColor]; scrollView.showsHorizontalScrollIndicator = NO; scrollView.alwaysBounceVertical = NO; scrollView.delaysContentTouches = NO; scrollView.canCancelContentTouches = YES; pageControl.numberOfPages = [ _pages count ]; pageControl.currentPage = 0; [ self layoutViews ]; } - (void)layoutViews { for(int i=0;i<[ _pages count];i++) { UIView *page = [ _pages objectAtIndex: i ]; page.backgroundColor = [UIColor darkGrayColor]; CGRect bounds = page.bounds; CGRect frame = CGRectMake(_pageRegion.size.width * i, 0.0, 320,400); page.frame = frame; page.bounds = bounds; [ scrollView addSubview: page ]; } } -(id)getDelegate { return _delegate; } - (void)setDelegate:(id)delegate { _delegate = delegate; } -(NSMutableArray *)getPages { return _pages; } -(void)setCurrentPage:(int)page { [ scrollView setContentOffset: CGPointMake(_pageRegion.size.width * page, scrollView.contentOffset.y) animated: YES ]; pageControl.currentPage = page; } -(int)getCurrentPage { return (int) (scrollView.contentOffset.x / _pageRegion.size.width); } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { pageControl.currentPage = self.currentPage; [ self notifyPageChange ]; } -(void) pageControlDidChange: (id)sender { UIPageControl *control = (UIPageControl *) sender; if (control == pageControl) { self.currentPage = control.currentPage; } [ self notifyPageChange ]; } -(void) notifyPageChange { if (self.delegate != nil) { if ([ _delegate conformsToProtocol:@protocol(PageScrollViewDelegate) ]) { if ([ _delegate respondsToSelector: @selector(pageScrollViewDidChangeCurrentPage:currentPage:) ]) { [ self.delegate pageScrollViewDidChangeCurrentPage: (PageScrollView *)self currentPage: self.currentPage ]; } } } } -(BOOL)touchesShouldCancelInContentView:(UIView *) view { return YES; } - (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view { return NO; } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@touch moved); } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { scrollView.delaysContentTouches = NO; scrollView.canCancelContentTouches = YES; NSLog(@touch begin); } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@touch end); } /* http://www.codingventures.com/2008/12/using-uiwebview-to-render-svg-files/ */ -(void)myNavControllerHide { [[self.delegate navigationController] setNavigationBarHidden:YES animated:YES]; } @end

    Kindly let me know where I am going wrong..... Thanks
  • slahteineslahteine Posts: 196New Users
    edited September 2009
    What result do you get if you return NO from touchesShouldCancelInContentView?

    Also, you shouldn't be handling any touches in the ScrollView itself, only in the content views within it.
    | I wrote <a href="http://www.thinkyhead.com/chordcalc&quot; target="_blank">ChordCalc</a>, <i>A fretboard 'calculator' for iOS</i> and <a href="http://www.thinkyhead.com/fretpet&quot; target="_blank">FretPet</a>, <i>a guitar-oriented music sequencer for OS X</i>.
  • anuragphadkeanuragphadke Posts: 9New Users
    edited September 2009
    no difference. I have a NSLog statement at touchesShouldCancelInContentView, but that NSLog never gets printed suggesting that the method isn't getting accessed. Can you elaborate more on the handling of touches not within ScrollView but within content?
«1
Sign In or Register to comment.