I have four UIImageViews placed on a circular UIView. Dragging the UIView rotates the view. But when I drag the UIImageView, the rotation does not occur. The UIImageView is eating the touches.
I subclassed the UIImageView and tried this:
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self.superview touchesMoved:touches withEvent:event];
[super touchesMoved:touches withEvent:event];
}
That doesn't seem to solve the problem. I tried disabling touches on the UIImageView - [imageView setUserInteraction:NO]. That doesn't solve the problem either. I know there are similar questions been asked. But none seem to solve my problem.
Thanks.
Try setting userInteractionEnabled to NO on your UIImageViews, it should prevent them from consuming the touches.
I'm trying to track if the user has a finger (or fingers) in the area of a UIScrollView. I overrode UIScrollView's - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event, - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event and - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event to track the number of touches that are "down" and "up".
This seems to work perfectly otherwise, but when the screen is panned, it seems that UIScrollView doesn't call these methods.
Which is the correct way to detect if the user is touching UIScrollView or not?
These properties of UIScrollView may be the best choice instead of messing with the
- (void)touchesBegan - (void)touchesCancelled - (void)touchesEnded methods
if (yourScrollView.isTracking || yourScrollView.isZooming || yourScrollView.isDragging)
{
// User interacting
}
I have multiple Views inside a ViewController and I want to know when a view is tapped on and I'm not sure how to go about it
In order to check whether certain view inside another view was touched you can use hitTest.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
In your custom implementation of touchesBegan check every touch in touches set. The point for hitTest method can be obtained using
- (CGPoint)locationInView:(UIView *)view;
method, where the view is your superView (the one that contains other views).
EDIT: Here's a fast custom implementation:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint locationPoint = [[touches anyObject] locationInView:self];
UIView* viewYouWishToObtain = [self hitTest:locationPoint withEvent:event];
}
I hope this was helpful, Paul
Sources : Detect if certain UIView was touched amongst other UIViews
Is there a way to stop a UIScrollView from scrolling while a touch is still held down? Setting the content offset using the scrollViewDidScroll: delegate method is excessive and can cause some issues (view moves and resets quickly) with the GPU, so I was hoping for a cleaner solution, if there is one.
You can simply turn it out by using its property scrollEnabled in viewDidLoad..
self.myScrollView.scrollEnabled = NO;
I would try:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[scrollView setScrollingEnabled:NO];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[scrollView setScrollingEnabled:NO];
}
That will turn it off for a press and you can adjust detecting how far the "Move" was from the original touch to see if you want to reenable scrolling or not
I'm trying to distinguish between horizontal swiping / panning and
vertical scrolling in a UITableView. The behavior I'm looking to
imitate (in a sense) is that of the Twitter iPad app, that has
multiple UITableView that can be moved horizontally on the screen. If
I slide my finger left or right on one of these UITableView, the view
itself moves horizontally. If I swipe vertically, the view scrolls as
expected.
I'm having trouble figuring out the correct way to implement this
behavior. I've seen some tutorials on this which involve adding touch
event handlers in the UITableViewCells, and overriding hitTest in the
UITableViewto appropriately route events depending on which direction
the gesture is moving. I've implemented some of these techniques, but
none of them work particularly well.
Does anyone know the correct way to implement this sort of behavior?
Conditionally performing actions on a UITableViewdependent on the
direction of the user's finger movement?
Thanks.
I've been struggling with a similar problem for days, and I've went through several potential solutions. I've found the best way and also the simplest solution to be subclassing UIGestureRecognizer to handle horizontal movement and attach it to your UITableViews.
The way it works is that it intercepts any touch events before they go to the UITableView (also UIScrollView). The UITableView, being a subclass of UIScrollView, has a custom UIPanGestureRecognizer built in which detects dragging and scrolls it's view accordingly. By adding your own subclass of UIGestureRecognizer, you can get the touches before the UIScrollView's gesture recognizer does. If your recognizer sees that the user is dragging horizontally, it should change it's state in an overridden touchesMoved: method to UIGestureRecognizerStateBegan. Otherwise, it sets it's state to UIGestureRecognizerCancelled, which lets the underlying UIScrollView handle the touches instead.
Here's what my UIGestureRecognizer subclass looks like:
#import <UIKit/UIGestureRecognizerSubclass.h>
#interface TableViewCellPanGestureRecognizer : UIGestureRecognizer
{
CGPoint startTouchPoint;
CGPoint currentTouchPoint;
BOOL isPanningHorizontally;
}
- (void)reset;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
#end
#implementation TableViewCellPanGestureRecognizer
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
startTouchPoint = [[touches anyObject] locationInView:nil];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
currentTouchPoint = [[touches anyObject] locationInView:nil];
if ( !isPanningHorizontally ) {
float touchSlope = fabsf((currentTouchPoint.y - startTouchPoint.y) / (currentTouchPoint.x - startTouchPoint.x));
if ( touchSlope < 1 ) {
self.state = UIGestureRecognizerStateBegan;
isPanningHorizontally = YES;
[self.view touchesCancelled:touches withEvent:event];
} else {
self.state = UIGestureRecognizerStateCancelled;
[self.view touchesCancelled:touches withEvent:event];
}
} else {
self.state = UIGestureRecognizerStateChanged;
}
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
self.state = UIGestureRecognizerStateCancelled;
[self.view touchesCancelled:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
self.state = UIGestureRecognizerStateCancelled;
}
-(void)reset
{
[super reset];
startTouchPoint = CGPointZero;
currentTouchPoint = CGPointZero;
isPanningHorizontally = NO;
}
#end
Then I have a subclassed UITableView that attaches the recognizer to itself and implements an action method to trigger horizontal movement of individual rows:
In my UITableView init:
horizontalPanGesture = [[TableViewCellPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleHorizontalDrag:)];
[self addGestureRecognizer:horizontalPanGesture];
[horizontalPanGesture release];
And the action method:
-(void)handleHorizontalDrag:(UIGestureRecognizer *)gesture
{
UIGestureRecognizerState state = gesture.state;
// Set the touched cell
if (!touchedCell){
NSIndexPath *indexPathAtHitPoint = [self indexPathForRowAtPoint:[gesture locationInView:self]];
id cell = [self cellForRowAtIndexPath:indexPathAtHitPoint];
touchedCell = cell;
startTouchPoint = [gesture locationInView:touchedCell];
}
if ( state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged ) {
// move your views horizontally
} else if ( state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled ) {
touchedCell = nil;
}
}
The above gets the current cell being touched within the table view, and then applies horizontal movements to it as the user drags left or right. However, if my gesture recognizer determines that the touches are meant to scroll vertically, it just cancels itself and the following touches are sent on to the UITableView to initiate vertical scrolling automatically.
This setup seems to be much simpler than overriding hitTest and doing all sorts of touch event trickery within the UITableView itself. It simply makes an immediate determination about the direction of the touch movement. You'll want to read up on UIGestureRecognizers - specifically about how it should be subclassed. You need to make sure to forward on certain touch events like touchesCancelled to the UITableView, as the UITableView's built in panGestureRecognizer won't be handling these events as it normally does. Obviously, you'll want to move entire table views and not individual cells, but it should be pretty straightforward.
This solution, as simple as it is, took me awhile to get exactly right for my exact needs. I am pretty new to IOS development, so I had to spend a lot of time reading about and tinkering with gesture recognizers and scroll views to figure this out.
I have never done this myself, but as a UITableView is a subclass of UIScrollView, the delegates of UITableView are also UIScrollViewDelegates. So in your UITableViewController subclass, you should be able to use UIScrollView delegates, and intercept the scrolls - making sure to also call the super method.
If you want the UITableViews to be placed "side by side" and when you swipe horizontally you expect them to all move together horizontally at the same time, (like a photo gallery with UITableViews instead of images) you can do the following:
Use a UIScrollView and add the UITableViews as the UIScrollView's subviews. You should set the scrollview's contentSize like this:
CGRect bounds = scrollView.bounds;
scrollView.contentSize=CGSizeMake(bounds.size.width * kNumOfTableViews, bounds.size.height);
so that the UIScrollview scrolls horizontally and not vertically.
You may also want to use
scrollView.pagingEnabled=YES;
depending on the desirable behaviour.
The UITableviews will respond the normal way if you slide your finger vertically and you will be able to change between UITableViews by sliding your finger horizontally.
For more details about how to do this efficiently, you can look at the WWDC 2010 video Session 104 - Designing Apps with Scroll Views and check out the source code from here: http://developer.apple.com/library/ios/#samplecode/PhotoScroller/ . This session describes how to slide between images. Instead of images you will use UITableViews
However, if you want each UITableView to be able to move horizontally independently and maybe overlap with another one as in the twitter app for iPad, this solution will not work for you, at least not out of the box.