how to get touchesMoved for UIImageView within a cell of UITableView? - ios

I need to get touchesBegan and touchesMoved for a UIImageView within a cell of UITableView.
But touchesBegan and touchesMoved don't fire if I touch UIImageView in cell.
touchesBegan and touchesMoved work if I touch any other UIImageView that is beyond UITableView.
Here is allocation of UITableView called from viewDidLayoutSubviews()................
tableFrame = CGRectMake(y-42, x+10 + DEVICE_TABLE_BORDER_WIDTH, height, width);
device_off_tableView = [[UITableView alloc]initWithFrame:tableFrame style:UITableViewStylePlain];
device_off_tableView.rowHeight = device_off_row_height;
device_off_tableView.sectionFooterHeight = 0;
device_off_tableView.sectionHeaderHeight = 0;
device_off_tableView.scrollEnabled = YES;
device_off_tableView.bounces = YES;
device_off_tableView.delegate = self;
device_off_tableView.dataSource = self;
device_off_tableView.allowsSelection = NO;
device_off_tableView.tag = channel;
device_off_tableView.transform = CGAffineTransformMakeRotation(-M_PI/2);
device_off_tableView.autoresizesSubviews = NO;
// Add device_off_tableView to the view:
device_off_tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
off_record_index = expected_off_index = 0;
[device_off_tableView reloadData];
[[self view] addSubview: device_off_tableView];
Here is allocation of UIButton within cell...........................
// Put invisible UIButton on top of device icon, to detect start of drag: !!!
UIButton* invisible_drag_button = [UIButton buttonWithType:UIButtonTypeCustom];
invisible_drag_button.frame = CGRectMake (x,y, w,h); // location and size of device off icon
invisible_drag_button.tag = cell_record_index; // store user device's record index
[invisible_drag_button addTarget: self
action:#selector( delegate_drag_start: )
forControlEvents: UIControlEventTouchDown ];
[cell.contentView addSubview: invisible_drag_button ];
Here are touch delegates:................................
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
printf("touchesBegan \n");
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// Get touch event's details:
UITouch *touch = [[event allTouches] anyObject];
// Touching image to be dragged?
if([touch view] == self.device_drag_UIImageView)
{
printf("touchesMoved device_drag_UIImageView \n");
CGPoint location = [touch locationInView: self.view];
self.device_drag_UIImageView.center=location;
}
else
{
printf("touchesMoved WRONG IMAGE \n");
}
}

This should work assuming you have touchesMoved:withEvent: inside the cell class.
Try the following on your UITableViewController
self.tableView.canCancelContentTouches = NO;
self.tableView.delaysContentTouches = NO;

Image views have the userInteractionEnabled set to NO. Which means that you wont get the touch events. Set that to YES and it may fix your problem. However the better way to do this is to use a UIPanGestureRecognizer. You would still need to set userInteractionEnabled to YES but it works better with the tableview

Related

objective c UIImage click event is not firing

my image is not click table
-(void)makeBlockAction{
blocksArr = [NSMutableArray new];
}
and my function for event is
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch* myTouch = [[touches allObjects] objectAtIndex:0];
NSLog(#"test2");
if ( [ blocksArr containsObject: myTouch.view ])
{
myTouch.view.alpha = 0;
NSLog(#"test");
}
}
There are better ways to go about this, try adding a UITapGestureRecognizer to the UIImageView. That way you won't need to use the touchesEnded function and check all the touches.
Also, make sure you have set userInteractionEnabled on your UIImageView to YES and that your UIImageView is not underneath any other subviews that may be preventing the tap being detected.
EXAMPLE
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(imageViewTapped:)];
[self.myImageView addGestureRecognizer:tapGestureRecognizer];
self.myImageView.userInteractionEnabled = YES;
[self.view bringSubviewToFront: self.myImageView];
}
- (void)imageViewTapped:(UITapGestureRecognizer *)tapGestureRecognizer
{
//Do what you need to do.
}

Unable to call touchesBegan/touchesMoved method inside viewController in iOS

I have a viewController which contains a UITableView. This viewController implements UITableViewDelegate, and UITableViewDataSource, and I'm also trying to implement the following methods:
touchesBegan
touchesMoved
touchesEnded
However, these methods are not being called. I am trying to call these methods in response to the user touching a UIImageView that is inside a UITableView, but doing so only calls this method:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.view bringSubviewToFront:_imageView];
[UIView animateWithDuration:.3 animations:^{
CGRect rect = [self.view convertRect:[tableView rectForRowAtIndexPath:indexPath] fromView:tableView];
CGFloat floatx = _imageView.frame.origin.x - rect.origin.x;
_imageView.frame = CGRectMake(rect.origin.x + floatx, rect.origin.y, _imageView.frame.size.width, _imageView.frame.size.height);
}];
NSLog(#"Table row %d has been tapped", indexPath.row);
}
What I am hoping is to continue to call this method, but also call:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch view] == _imageView) {
//need to make sure user can only move the UIImageView up or down
CGPoint location = [touch locationInView:_imageView];
//ensure UIImageView does not move outside UIITableView
CGPoint pt = [[touches anyObject] locationInView:_imageView];
CGRect frame = [_imageView frame];
//Only want to move the UIImageView up or down, not sideways at all
frame.origin.y += pt.y - _startLocation.y;
[_imageView setFrame: frame];
_imageView.center = location;
return;
}
}
when the user is dragging the UIImageView inside the UITableView.
Can anyone see what I am doing wrong?
Thanks in advance to all who reply
I had a similar problem to this except I was trying to implement touch detection to an UIWebView. I eventually got over it by adding a UIPanGestureRecognizer to the UIWebView's .view property.
Implement this method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
and then add the UIPanGestureRecognizer to the UITableView like so:
UIPanGestureRecognizer *panGesture;
panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panGestureDetected:)];
panGesture.maximumNumberOfTouches = 1;
panGesture.minimumNumberOfTouches = 1;
panGesture.delegate = self;
[self.tableView addGestureRecognizer:panGesture];
and then implement the method
- (void)panGestureDetected:(UIPanGestureRecognizer *)recognizer {
}
Now, every time the UIPanGestureRecognizer detects a pan gesture, it will call that method and you can get the location of the UIPanGestureRecognizer by calling the method [recognizer locationInView:self.tableView.view]; which will return a CGPoint. You can also get the state of the UIPanGestureRecognizer by calling [recognizer state] which returns a UIGestureRecognizerState.
Have you set userInteractionEnabled on your view that the touches will be inside?

Stop and start an animation by touch. Objective C

I have made an animation that moves across the screen, my animation loops continuously. How can I stop the animation when you tap the animated image, Then let the animation continue when you lift the touch?
I know how to use TouchesMoved to move a specified button like this:
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
UIControl *control = sender;
control.center = point;
But getting it to work with my animation. I would like the animation to continue after I touch it.
SelectedCellViewController.h
// SelectedCellViewController.h
#import <Accounts/Accounts.h>
#import <QuartzCore/QuartzCore.h>
#interface SelectedCellViewController : UIViewController {
IBOutlet UIImageView *imageView;
UIImageView *rocket;
}
#end
viewControllertoShow.m
#import "SelectedCellViewController.h"
#interface SelectedCellViewController ()
#end
#implementation SelectedCellViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
}
return self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:#selector(imageSpawn:) withObject:nil afterDelay:3];
}
- (void) imageSpawn:(id) sender
{
UIImage* image = [UIImage imageNamed:#"ae"];
rocket = [[UIImageView alloc] initWithImage:image];
rocket.frame = CGRectMake(-25, 200, 25, 40);
[UIView animateWithDuration:5
delay:0.2f
options:UIViewAnimationCurveEaseInOut | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse
animations:^(){rocket.frame=CGRectMake(345, 200, 25, 40);}
completion:^(BOOL fin) {
}];
[self.view addSubview:rocket];
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(ballTapped:)];
tapped.numberOfTapsRequired = 1;
[rocket addGestureRecognizer:tapped];
[rocket setUserInteractionEnabled:YES];
}
-(void)ballTapped:(UIGestureRecognizer *)gesture
{
CGPoint location = [gesture locationInView:gesture.view];
//then write code to remove the animation
[self.view.layer removeAllAnimations];
NSLog(#"Tag = %d", gesture.view.tag);
rocket.frame = CGRectMake(location.x,location.y,25,40);
}
- (void)dismissView {
[self dismissViewControllerAnimated:YES completion:NULL];
}
- (void)viewDidUnload {
}
#end
As you had already stated in your question ,you can get the touched point using
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
Then check check whether this point lies inside the coordinates of the animated UIImageview and then stop animation.
But if you are using scrollview, you won't be able to use this because scrollview will not return any UIView touch events.
As your image view is animating, a better choice will be adding a UITapGestureRecogniser to the image view when you add it s subview, like this
- (void) imageSpawn:(id) sender
{
UIImage* image = [UIImage imageNamed:#"ae"];
UIImageView *rocket = [[UIImageView alloc] initWithImage:image];
rocket.frame = CGRectMake(-25, 200, 25, 40);
[UIView animateWithDuration:5
delay:0.2f
options:UIViewAnimationCurveEaseInOut | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse
animations:^(){rocket.frame=CGRectMake(345, 200, 25, 40);}
completion:^(BOOL fin) {
}];
[myScrollView addSubview:rocket];
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(ballTapped:)];
tapped.numberOfTapsRequired = 1;
[self.rocket addGestureRecognizer:tapped];
[rocket setUserInteractionEnabled:YES];
}
And in the target function write code to stop the animation:
-(void)ballTapped:(UIGestureRecognizer *)gesture
{
//here also you can get the tapped point if you need
CGPoint location = [gesture locationInView:gesture.view];
//then write code to remove the animation
[self.view.layer removeAllAnimations];
}
EDIT:
If you are trying to stop the image view at the touched point, you can add this to ballTapped event:
rocket.frame = CGRectMake(location.x,location.y,25,40);
But for this you have to declare UIImageView *rocket outside this particular method, i.e. declare to in your header file.
Another way is to add this to the parent view of the animation -
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
self.animating = NO;
return [super hitTest:point withEvent:event];
}
use an (atomic) property, then check the property in the animation to see if it should be stopped. We use this to stop a photo gallery which is running so that the user can manually move the photos. You could also check in here if the point is in a specific area if necessary. This method runs before any touch methods are called.
try like this may be it helps you, in the middle of the animation if you touch on the imageview then animation removes from the view .
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint lastLocation = [touch locationInView: self.view];
if([[touch view] isKindOfClass:[UIImageView class]]){
[youImageView.layer removeAllAnimations];
youImageView.center=lastLocation;//assign your image view center when the animation removes from the view.
}
}
and add #import <QuartzCore/QuartzCore.h> framework.

Buttons get stuck on highlighted

I have just started working on a project and I already have a few problems and errors. I was wondering if you guys could help me figure out where the bug is.
Quick overview: I have two files: (ViewController.m and Scroller.m). In the ViewController I have some code under ViewDidLoad (which I'll show in a second), I also have a function (addImagesToView) that does what it says, and some touchesBegan,moved and ended for intractability.
In the Scroller I decided to rewrite some of the "-(void)touches" functions implementations.
The problem I have: is that the buttons (coming from the addImagesToView function) get stuck on highlighted. I performed some tests with an NSLog to see which "touches" working and which don't. "touchesMoved" doesn't work properly. If the user drags downward, the log stops after about 3 or 4 lines of text. I think that it interferes with the scroll somehow.
This is the content of ViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"bgPNG.png"]];
imageView.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:imageView];
//UIColor *background = [[UIColor alloc]initWithPatternImage:imageView.image];
//self.view.backgroundColor = background;
CGRect fullScreen = [[UIScreen mainScreen] applicationFrame];
scroll = [[Scroller alloc] initWithFrame:fullScreen];
scroll.contentSize = CGSizeMake(320, 2730);
scroll.delaysContentTouches = NO;
//scroll.canCancelContentTouches = NO;
scroll.scrollEnabled = YES;
[self.view addSubview:scroll];
buttons = [[NSMutableArray alloc]init];
[self addImagesToView];
}
-(void) addImagesToView{
CGFloat yCoordinate = 35;
for (int i=1; i<=18; i++) {
UIImageView *image = [[UIImageView alloc]initWithImage:[UIImage imageNamed:[NSString stringWithFormat:#"picture%d.png",i]]highlightedImage:[UIImage imageNamed:[NSString stringWithFormat:#"picture%dHG.png",i]]];
CGRect position = CGRectMake(105, yCoordinate, IMAGE_SIZE, IMAGE_SIZE);
image.frame = position;
[scroll addSubview:image];
image.userInteractionEnabled = YES;
image.tag = i;
[buttons addObject:image];
yCoordinate += 150;
}
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Get any touch
UITouch *t = [touches anyObject];
if ([t.view class] == [UIImageView class])
{
// Get the tappedImageView
UIImageView *tappedImageView = (UIImageView*) t.view;
tappedImageView.highlighted = YES;
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *t = [touches anyObject];
if ([t.view class] == [UIImageView class])
{
// Get the tappedImageView
UIImageView *tappedImageView = (UIImageView*) t.view;
tappedImageView.highlighted = NO;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources th at can be recreated.
}
#end
and this is the Scroller.m
#import "Scroller.h"
#implementation Scroller
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.dragging)
[self.nextResponder touchesBegan: touches withEvent:event];
else
[super touchesBegan: touches withEvent: event];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *t = [touches anyObject];
if ([t.view class] == [UIImageView class])
{
// Get the tappedImageView
UIImageView *tappedImageView = (UIImageView*) t.view;
tappedImageView.highlighted = NO;
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.dragging)
[self.nextResponder touchesEnded: touches withEvent:event];
else
[super touchesEnded: touches withEvent: event]; // Get the tappedImageView
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
I have also tried to implement all the touches in the ViewController, but I don't know how to make it read from the scroll (please notice the diff. between SCROLL and SCROLLER).
As you can tell I've tried to order them like this: view -> backGroundImage ->scroller ->addImagesToView(function), so that the images that come out from [I]addImagesToView[/I] are on top of the scroll. That's my desired hierarchy.
Thank you very much.
You don't have to write your own touch handling routines for button presses. Instead of using UIImageViews, just create UIButtons instead and hook into their UIControlEventTouchUpInside event.
I think you'd be better off telling us what you are trying to accomplish as you're probably barking up the wrong tree here. As Jim said, there are better ways to select images, and even if you want to handle touches yourself, UIGestureRecognizers are probably a better option. If you are allowing users to select images, I'd recommend you take a look at iCarousel on github. It's an open source carousel that works great for image selection. Also, if you can target iOS 6 there is a new collection view that could be right up your alley.

Xcode iOS push down button and drag then up on a second button

Lets say I wan't to add 1 to an integer. This will only be done when I push down on a UIButton and then release my finger on another UIButton. A drag combo. Whats the easiest way I can make an IBAction occur out of a combo? This could be done with touch coordinates or maybe just UIButtons and IBActions.
How do I create a 2-button combo with IBActions
Try implementing the button you wish to touch down on as a "Touch Down", "Touch Up Inside", and "Touch Up Outside" button.
UIButtons can respond to many differing types of events
Touch Cancel
Touch Down
Touch Down Repeat
Touch Drag Enter
Touch Drag Exit
Touch Drag Inside
Touch Drag Outside
Touch Up Inside
Touch Up Outside
You can implement different action code for each of these for each button for best control of whatever you wish. The simplistic case only uses the 2 I mentioned above.
THIS CODE HAS BEEN TESTED AND DOES WORK
In your ViewController header file (here was mine):
#interface ViewController : UIViewController{
IBOutlet UIButton * upButton; // count up when finger released button
IBOutlet UIButton * downButton;
IBOutlet UILable * score;
BOOL isButtonDown;
unsigned int youCounter;
}
-(IBAction)downButtonDown:(id)sender;
-(IBAction)downButtonUpInside:(id)sender;
-(IBAction)downButtonDragOutside:(id)sender event:(UIEvent *)event;
-(IBAction)downButtonUpOutside:(id)sender event:(UIEvent *)event;
#end
In your .xib, connect the down button (the one you wish to be your original finger pressed button) to the proper actions above.
In your ViewController.m file
-(void)viewDidLoad{
[super viewDidLoad];
isButtonDown = NO;
youCounter = 0;
}
-(IBAction)downButtonDown:(id)sender{
isButtonDown = YES;
}
-(IBAction)downButtonUpInside:(id)sender{
isButtonDown = NO;
}
-(IBAction)downButtonDragOutside:(id)sender event:(UIEvent *)event{
NSArray theTouches = [[event allTouches] allObjects];
[downButton setHighlighted:YES];
if(YES == [upButton pointInside:[[theTouches objectAtIndex:0] locationInView:upButton] withEvent:event]){
[upButton setHighlighted:YES];
}else{
[upButton setHighlighted:NO];
}
}
-(IBAction)downButtonUpOutside:(id)sender event:(UIEvent *)event{
if(YES == [upButton pointInside:[[theTouches objectAtIndex:0] locationInView:upButton] withEvent:event]){
youCounter++;
score.text = [NSString stringWithFormat:#"Score = %d", youCounter];
}
[downButton setHighlighted:NO];
[upButton setHighlighted:NO];
}
//Initalize a BOOL variable to know if you started the touch in the right place.
BOOL correctStart = NO;
//Get the location of the first touch, if its in the first button make correctStart = YES.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
for (UITouch *touch in allTouches) {
if ([touch locationInView:button1.view]) {
correctStart = YES;
}
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
for (UITouch *touch in allTouches) {
if (([touch locationInView:button2.view]) && (correctStart == YES)) {
anInteger++;
}
}
correctStart = NO;
}
I did not try this code as I am not at my mac, so your results may vary, but this should get you going in the right direction.
Another approach is to use a UITapGestureRecognizer and UIPanGestureRecognizer and track the location in your buttons. I found this to be more readable. (I actually ended up using UILabels because I didn't need any further UIButton behavior.)
// Create a button, add targets
UIButton *cloudButton = [UIButton buttonWithType:UIButtonTypeCustom];
[cloudButton setImage:[UIImage imageNamed:#"notification_add.png"] forState:UIControlStateNormal];
[cloudButton setFrame:CGRectMake(0, 0, 30, 30)];
[cloudButton addTarget:self action:#selector(dragBegan:withEvent: )
forControlEvents: UIControlEventTouchDown];
[cloudButton addTarget:self action:#selector(dragMoving:withEvent: )
forControlEvents: UIControlEventTouchDragInside | UIControlEventTouchDragOutside];
[cloudButton addTarget:self action:#selector(dragEnded:withEvent: )
forControlEvents: UIControlEventTouchUpInside |
UIControlEventTouchUpOutside];
[self.view addSubview:cloudButton];
//event methods
- (void) dragBegan: (UIControl *) c withEvent:ev
{
NSLog(#"dragBegan......");
}
- (void) dragMoving: (UIControl *) c withEvent:ev
{
NSLog(#"dragMoving..............");
}
- (void) dragEnded: (UIControl *) c withEvent:ev
{
NSLog(#"dragEnded..............");
}
Do the following for the first UIButton in the ViewDidLoad method
[button1 addTarget:self action:#selector(dragMoving:withEvent: )
forControlEvents: UIControlEventTouchDragInside | UIControlEventTouchDragOutside];
[button1 addTarget:self action:#selector(dragEnded:withEvent: )
forControlEvents: UIControlEventTouchUpInside |
UIControlEventTouchUpOutside];
In the dragMoving method
- (void)dragMoving:(UIControl *)c withEvent:event{
NSSet* touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:[button2 superview]];
if ( CGRectContainsPoint(button2.frame, currentPoint) ) {
NSLog(#"over second button);
}
}
As for the dragEnded method:
- (void) dragEnded:(UIControl *)c withEvent:event{
NSSet* touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:[self.button1 superview]];
if ( CGRectContainsPoint(button2.frame, currentPoint) ) {
NSLog(#"ended on button 2");
//add 1 to the integer
}
else {
NSLog(#"not on button 2");
}
}

Resources