Any idea how to do this? I have a UIImageView inside of each cell in my UITableView and I want to disable scroll when the user starts touching the UIImageView and then enable it once the user stops dragging their finger on the photo.
I just give my logic.
Add UIPanGestureRecognizer to each cell of UITableView.
UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanFrom:)];
[cell addGestureRecognizer:panGestureRecognizer];
And in method name is handlePanFrom:
- (void)handlePanFrom:(UIPanGestureRecognizer*)recognizer
{
CGPoint translation = [recognizer translationInView:recognizer.view];
CGPoint velocity = [recognizer velocityInView:recognizer.view];
if (recognizer.state == UIGestureRecognizerStateBegan)
{
/// track began
tableView.userInteractionEnabled = NO;
}
else if (recognizer.state == UIGestureRecognizerStateChanged)
{
// track the movement
} else if (recognizer.state == UIGestureRecognizerStateEnded)
{
// final position
tableView.userInteractionEnabled = YES;
}
}
Make sure your UIIMageView must be set as a userInteractionEnabled = YES;. Because by default UIIMageView have to set userInteractionEnabled = NO;.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch.view isKindOfClass:[UIImageView class]]) {
NSLog(#"self.tableView.scrollEnabled = NO");
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch.view isKindOfClass:[UIImageView class]]) {
NSLog(#"self.tableView.scrollEnabled = YES");
}
}
There are two ways to implement this, either include UITapGestureRecognizer or UIPanGestureRecognizer to your UIImageView and set the target and action where target is your custom UITableViewCell class or include
- (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
methods in the UIImageView custom class and set the delegate via protocol to your custom UITableViewCell.
for UIGestureRecognizer you can check its state property UIGestureRecognizer Class Reference to know the state with the help of switch
typedef enum {
UIGestureRecognizerStatePossible,
UIGestureRecognizerStateBegan,
UIGestureRecognizerStateChanged,
UIGestureRecognizerStateEnded,
UIGestureRecognizerStateCancelled,
UIGestureRecognizerStateFailed,
UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
}
Finally, by toggling the UITableView's scrollEnabled property to stop and start scrolling where UITableView is a sub class of UIScrollView
Related
I want to make voice recorder app. The
recording should start when long touch begins and the
recording must end when user stops the gesture on the button.
UIGestureRecognizer *longGesture=[[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(startrecording)];
How can I handle that when the user leaves the button?
in viewDidLoad method
UILongPressGestureRecognizer *longPressOnButton = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressOnButton:)];
longPressOnButton.delegate = self;
btn.userInteractionEnabled = YES;
[btn addGestureRecognizer:longPressOnButton];
- (void)longPressOnButton:(UILongPressGestureRecognizer*)gesture
{
// When you start touch the button
if (gesture.state == UIGestureRecognizerStateBegan)
{
//start recording
}
// When you stop touch the button
if (gesture.state == UIGestureRecognizerStateEnded)
{
//end recording
}
}
Also you can try or use the touchEvent concept
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)e {
// show touch-began state
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)e {
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)e {
UITouch *touch = [touches anyObject];
.....
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)e {
}
As user3182143 said, using a UILongPressGestureRecorgnizer will solve your problem, but if you are interested there is another way using a UIButton. No need to add a UILongPressGestureRecorgnizer!
From your storyboard, drag an IBAction for a UIButton. And while you are adding its name, change the event to Touch Down.
Now drag another IBAction for the same UIButton and while changing its name, change the event to Touch up Inside (if it isn't that already).
- (IBAction)touchDownButtonAction:(UIButton *)sender {
NSLog(#"Start");
}
- (IBAction)touchUpInsideButtonAction:(UIButton *)sender {
NSLog(#"End");
}
Handle your recording based on the actions!
Here is a screenshot just in case:
when i double tap on image then the image will show in complete view and at the same time i have to drag the image from one place to another in the same view.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
Using the above methods the drag and drop of image is implemented successfully but the UITapGesture is not working now. So, how can I implement both ? ``
By just using UILongPressGrstureRecognizer, it is surprising that it is able to implement tap and drag.
As you just drag first Action will be Tap by default.
You have to:
set the numberOfTapsRequired to 1 to detect the initial tap.
set the minimumDuration something smaller to detect drags quicker without waiting
e.g.:
UILongPressGestureRecognizer *mouseDrag = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleDrag:)];
mouseDrag.numberOfTapsRequired=1;
mouseDrag.minimumPressDuration=0.05;
[clickLeft requireGestureRecognizerToFail:mouseDrag];
to handle the drag, you must determine the state to handle it appropriately as a continuous gesture.
For tap gesture you can simply use
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapFrom:)];
[self.imageView addGestureRecognizer:tapGestureRecognizer];
tapGestureRecognizer.delegate = self;
While you tap on image this method invoke
- (void) handleTapFrom: (UITapGestureRecognizer *)recognizer
{
//Code to handle the gesture
}
Did you try to add the simultaneous recognition?
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
For Single Tap in viewDidLoad method,first set the tapGesture Recognizer
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap)];
singleTap.numberOfTapsRequired = 1;
imageView.userInteractionEnabled = YES;
[imageView addGestureRecognizer:singleTap];
Then method
-(void)handleSingleTap
{
NSLog(#"The single tap happened");
}
Touch Events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if (touch.tapCount == 1) {
NSLog(#"The single tap happened now");
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
NSLog(#"The tap count is - %lu",(unsigned long)touch.tapCount);
if (touch.tapCount == 1)
{
NSLog(#"The single tap Ended now");
}
}
I've a question.. I would like to do my own gesture recognizer with swipe and that you drag (or swipe) down with two fingers but I don't now how..
This is my code of GestureSwipe.h:
#import <UIKit/UIKit.h>
#interface GestureSwipe : UIGestureRecognizer
#property CGPoint startTouchPosition;
#property(nonatomic) NSUInteger numberOfTouchesRequired;
#property(nonatomic) UISwipeGestureRecognizerDirection direction;
- (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
This is my code of GestureSwipe.m:
#define VERT_SWIPE_DRAG_MAX 7
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *aTouch = [touches anyObject];
// startTouchPosition is a property
self.startTouchPosition = [aTouch locationInView:self.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *aTouch = [touches anyObject];
CGPoint currentTouchPosition = [aTouch locationInView:self.view];
// Check if direction of touch is horizontal and long enough
if (fabsf(self.startTouchPosition.y - currentTouchPosition.y) <=
VERT_SWIPE_DRAG_MAX)
{
// If touch appears to be a swipe
if (self.startTouchPosition.y < currentTouchPosition.y) {
[self myProcessDownSwipe:touches withEvent:event];
}
self.startTouchPosition = CGPointZero;
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
self.startTouchPosition = CGPointZero;
}
-(void)myProcessDownSwipe:(NSSet *)touches withEvent:(UIEvent *)event {
}
How should I do to do swipe down with two fingers?
Then I have other VC where recognize my own gesture:
HelloViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
//newGesture = [[GestureSwipe alloc] init];
newGesture = [[GestureSwipe alloc] initWithTarget:self action:#selector(showImage:)];
newGesture.numberOfTouchesRequired = 2;
}
In HelloViewController you'd add something like this:
UISwipeGestureRecognizer *recognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
// Set the acceptable swipe direction and number of touches required to do the gesture
[recognizer setDirection:(UISwipeGestureRecognizerDirectionDown)];
recognizer.numberOfTouchesRequired = 2;
// Add the gesture recogizer to the view
[self.view addGestureRecognizer:recognizer];
Then you would create a custom method (I called my one handleSwipe:, but this can be whatever suits you best) and do what you need to do.
EDIT: So your viewDidLoad method would look like this
- (void)viewDidLoad
{
[super viewDidLoad];
UISwipeGestureRecognizer *recognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
// Set the acceptable swipe direction and number of touches required to do the gesture
[recognizer setDirection:(UISwipeGestureRecognizerDirectionDown)];
recognizer.numberOfTouchesRequired = 2;
// Add the gesture recogizer to the view
[self.view addGestureRecognizer:recognizer];
}
And the handleSwipe: method could be like this:
-(void)handleSwipe:(id)sender{
// Do something
}
There is no need to create your own recognizer. You can handle this with a standard recognizer and just state how many touches is required.
A good example can be found here: Capture only UIView 2 finger UIPanGestureRecognizer
I've an UITextView into an UITableViewCell, but I can't scroll the text. When I try to scroll the textView, the tableView catch the touches.
There is any way to fix this?
PS: Subclass of UITableViewController
I'm thinking you can detect the object being touched and if it is a UITextView, then temporarily disable scrolling with UITableView:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
//detect if touch is on UITextView
if ([touch.view isKindOfClass: UITextView.class]) {
yourTableView.scrollEnabled = NO;
}
}
Don't forget to re-enable scrolling of the UITableView afterwards in touchesEnded
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
yourTableView.scrollEnabled = YES;
}
I put UIButton inside UITableViewCell in UITableView that is behind UIScrollView. I subclassed UIScrollView to forward touches to UITableView.
So method from UITableViewDelegate didSelectRow is calling properly. The problem is that UIButton inside table cell is not receiving TouchUpInside actions.
How can I solve this problem without deleting ScrollView over TableView?
EDIT:
I resolved this issue by detecting which view will receive touch. Here's the code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView *hitView = [self hitTest:[(UITouch*)[[touches allObjects] objectAtIndex:0] locationInView:self] withEvent:event];
if ([hitView isKindOfClass:[UIButton class]]) {
[(UIButton*)hitView sendActionsForControlEvents:UIControlEventTouchUpInside];
}
[super touchesBegan:touches withEvent:event];
}
If you want to enable actions for bouth objects - UIScrollView and UIButton you should to implement custom hit test mechanism for ScrollView.
In your UIScrollView subclass override - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event method to make views behind ScrollView available for getting events.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return __touchesEnabled;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
_touchesEnabled = NO;
UIWindow *window = [UIApplication sharedApplication].delegate.window;
for(UITouch *touch in touches) {
CGPoint point = [touch locationInView:self];
point = [window convertPoint:point fromView:self];
UIView *view = [window hitTest:point withEvent:event];
[view touchesBegan:touches withEvent:event];
}
_touchesEnabled = YES;
}
It works for me
Since you have added your scroll view over the UIButton, all the touch actions will not be passed to the button.
[yourScrollView setUserInteractionEnabled:NO];
This may solve your problem.