 |
|
 |
|
 |
01-14-2009, 09:53 AM
|
#1 (permalink)
|
|
Tutorial Author
Join Date: Nov 2008
Posts: 136
|
Detect touch in scrollview - tutorial
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...
Code:
#import
// 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 {
// 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...
Code:
#import
// 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...
Code:
#import
// 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 ;-)
Code:
#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 ;-)
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
Code:
// 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 ;-)
Last edited by elpuerco; 01-14-2009 at 10:11 AM.
|
|
|
01-14-2009, 11:29 AM
|
#2 (permalink)
|
|
Administrator
Join Date: Mar 2008
Location: Richmond, VA
Age: 27
Posts: 741
|
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.
|
|
|
01-14-2009, 11:48 AM
|
#3 (permalink)
|
|
Tutorial Author
Join Date: Nov 2008
Posts: 136
|
Hi, yes that would be great thanks and as I progress I shall add more
|
|
|
02-16-2009, 02:59 PM
|
#4 (permalink)
|
|
Registered Member
Join Date: Feb 2009
Posts: 88
|
It would be great if you can make a video for this
__________________
Independent developer
Please excuse me by my bad english. English is not my native language
Sabius Software
Link To App Store
|
|
|
02-17-2009, 07:09 PM
|
#5 (permalink)
|
|
Registered Member
Join Date: Feb 2009
Posts: 6
|
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.
Code:
- (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:
Code:
- (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.
|
|
|
02-17-2009, 07:12 PM
|
#6 (permalink)
|
|
Registered Member
Join Date: Feb 2009
Posts: 6
|
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.
|
|
|
02-25-2009, 06:22 PM
|
#7 (permalink)
|
|
New Member
Join Date: Feb 2009
Posts: 86
|
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.
Last edited by seanrice; 02-25-2009 at 06:25 PM.
|
|
|
04-29-2009, 11:37 AM
|
#8 (permalink)
|
|
Registered Member
Join Date: Aug 2008
Posts: 66
|
Thank you so much with this tutorial , you really made my day
|
|
|
04-30-2009, 05:01 AM
|
#9 (permalink)
|
|
Tutorial Author
Join Date: Nov 2008
Posts: 136
|
Quote:
Originally Posted by seanrice
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.
|
|
|
04-30-2009, 05:01 AM
|
#10 (permalink)
|
|
Tutorial Author
Join Date: Nov 2008
Posts: 136
|
Quote:
Originally Posted by hakimny
Thank you so much with this tutorial , you really made my day
|
Glad to help ;-)
|
|
|
05-12-2009, 09:35 PM
|
#11 (permalink)
|
|
Registered Member
Join Date: May 2009
Posts: 36
|
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.
|
|
|
06-13-2009, 11:11 PM
|
#12 (permalink)
|
|
IPOD Training Wheels
Join Date: May 2009
Location: Seattle WA
Age: 45
Posts: 21
|
Nice Work!
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!
|
|
|
06-15-2009, 04:25 PM
|
#13 (permalink)
|
|
IPOD Training Wheels
Join Date: May 2009
Location: Seattle WA
Age: 45
Posts: 21
|
How would one add text and or a rectangle?
So i added the following code (i tried both before the [contentView addSubview: imageView] and after) to your LoadView routine:
Code:
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?
Last edited by RodOfIPOD; 06-15-2009 at 04:32 PM.
|
|
|
06-17-2009, 12:09 PM
|
#14 (permalink)
|
|
New Member
Join Date: Feb 2009
Posts: 86
|
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 !!!!
Last edited by seanrice; 06-17-2009 at 12:19 PM.
Reason: clarification
|
|
|
06-17-2009, 08:16 PM
|
#15 (permalink)
|
|
IPOD Training Wheels
Join Date: May 2009
Location: Seattle WA
Age: 45
Posts: 21
|
Hmm
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.
|
|
|
06-23-2009, 03:43 AM
|
#16 (permalink)
|
|
shiva
Join Date: Jun 2009
Location: Hyderabad
Age: 23
Posts: 54
|
Quote:
Originally Posted by elpuerco
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...
Code:
#import
// 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 {
// 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...
Code:
#import
// 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...
Code:
#import
// 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 ;-)
Code:
#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 ;-)
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
Code:
// 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
|
|
|
07-02-2009, 08:19 PM
|
#17 (permalink)
|
|
Registered Member
Join Date: Feb 2009
Posts: 87
|
Quote:
Originally Posted by elpuerco
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...
Code:
#import
// 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 {
// 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...
Code:
#import
// 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...
Code:
#import
// 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 ;-)
Code:
#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 ;-)
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
Code:
// 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?
|
|
|
07-06-2009, 09:48 AM
|
#18 (permalink)
|
|
Registered Member
Join Date: Jul 2009
Location: India
Posts: 47
|
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
|
|
|
07-11-2009, 12:09 AM
|
#19 (permalink)
|
|
Programming Wizard
Join Date: Oct 2008
Location: Northampton, MA USA
Age: 43
Posts: 187
|
Quote:
Originally Posted by anils_das
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.
Last edited by slahteine; 07-11-2009 at 12:12 AM.
|
|
|
09-27-2009, 01:48 AM
|
#20 (permalink)
|
|
Registered Member
Join Date: Jul 2009
Posts: 9
|
Scott,
I am trying to implement what you said.. Here's my code
I added a hittest method in my ScrollView
Code:
-(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:
Code:
-(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
everything works but I cannot recognize any gestures.
Any tips?
|
|
|
09-27-2009, 08:21 AM
|
#21 (permalink)
|
|
Registered Member
Join Date: Aug 2008
Posts: 66
|
Quote:
Originally Posted by anuragphadke
Scott,
I am trying to implement what you said.. Here's my code
I added a hittest method in my ScrollView
Code:
-(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:
Code:
-(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
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
|
|
|
09-27-2009, 01:17 PM
|
#22 (permalink)
|
|
Registered Member
Join Date: Jul 2009
Posts: 9
|
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
|
|
|
09-27-2009, 04:19 PM
|
#23 (permalink)
|
|
Programming Wizard
Join Date: Oct 2008
Location: Northampton, MA USA
Age: 43
Posts: 187
|
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.
Last edited by slahteine; 09-27-2009 at 04:22 PM.
|
|
|
09-27-2009, 05:06 PM
|
#24 (permalink)
|
|
Registered Member
Join Date: Jul 2009
Posts: 9
|
scott,
I followed your suggestions, but the touchesBegan, touchesEnded etc. is still unable to receive anything. Here's the code:
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
|
|
|
09-27-2009, 10:03 PM
|
#25 (permalink)
|
|
Programming Wizard
Join Date: Oct 2008
Location: Northampton, MA USA
Age: 43
Posts: 187
|
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.
|
|
|
 |
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is On
|
|
|
|
» Advertisements |
» Online Users: 458 |
| 41 members and 417 guests |
| bbc z, Bitzal, DanielNovy, DaveHolzer, davidloew, DrEvil, drhansen, ebohdas, eriss87, firearasi, harkonian, harrytheshark, hazmat82, HemiMG, hermonir, homer1980ar, ieasyproductions, isley, jaywright00, JonnyBGoode, lukeca, melmoup, MiniRobinho, Mopedhead, Mr Jack, mriphoneman, nDev1, paul84, ronm3xico, ryguy2503, scleland, scottlangendyk, sorghum, Straathond, swissmade, Tambourin, tidyguy, tsktsk, vikinara, xslim, zackattack |
| Most users ever online was 779, 05-11-2009 at 09:55 AM. |
» Stats |
Members: 23,966
Threads: 38,751
Posts: 170,024
Top Poster: smasher (2,560)
|
| Welcome to our newest member, cruisetom |
|