UILongPressGestureRecognizer not working for all UIButtons - ios

I'm having a problem that I fear has a simple solution. Each time the 'createNewSetInDB:' method is called, a new UIButton* is created, assigned a target for when the user presses the button, and assigned a UILongPressGesture* for when a user long presses the button.
The 'openSet:' method is correctly being called when a user taps one of these buttons. The 'showHandles:' long press method is only being called for the LAST UIButton* that was created. So if the 'createNewSetInDB:' method gets called 4 times and therefore creates 4 UIButtons, the first three do not handle the UILongPressGesture. The 4th UIButton does.
Any ideas?
UILongPressGestureRecognizer *showHandlesLongPress;
- (void)viewDidLoad
{
showHandlesLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(showHandles:)];
showHandlesLongPress.minimumPressDuration = .5;
}
- (void)createNewSetInDB:(BOOL)doWeAddItToTheDatabase
{
UIButton *newSet = [[UIButton alloc]initWithFrame:
CGRectMake((sliderMusic.frame.origin.x + imgWhiteLine.frame.size.width / 2) + (_musicPlayer.currentPlaybackTime * 10),
6,
35,
25)];
[newSet addTarget:self action:#selector(openSet:) forControlEvents:UIControlEventTouchUpInside];
[newSet setTitleColor:[MobileMarcherVariables sharedVariableInstance].systemColor forState:UIControlStateNormal];
[newSet.layer setBorderColor:[[MobileMarcherVariables sharedVariableInstance].systemColor CGColor]];
[newSet.layer setBorderWidth:1];
[newSet.titleLabel setFont:[UIFont systemFontOfSize:15]];
[newSet setTitle:[NSString stringWithFormat:#"%i",totalNumberOfSets] forState:UIControlStateNormal];
[scrollviewMusic addSubview:newSet];
[arrayofSetButtons addObject:newSet];
[newSet addGestureRecognizer:showHandlesLongPress];
if (doWeAddItToTheDatabase) [[NSNotificationCenter defaultCenter] postNotification:newSetNotification];
}
- (void)showHandles:(UILongPressGestureRecognizer*)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan)
{
NSLog(#"long press");
for (UIButton *but in arrayofSetButtons)
{
if (but.tag != gesture.view.tag)
{
but.alpha = .5;
}
}
[scrollviewMusic bringSubviewToFront:lefthandle];
[scrollviewMusic bringSubviewToFront:righthandle];
lefthandle.hidden = NO;
righthandle.hidden = NO;
lefthandle.frame = CGRectMake(gesture.view.frame.origin.x - 1,
gesture.view.frame.origin.y - gesture.view.frame.size.height,
2, 50);
righthandle.frame = CGRectMake((gesture.view.frame.origin.x - 1) + gesture.view.frame.size.width,
gesture.view.frame.origin.y - gesture.view.frame.size.height,
2, 50);
}
}

You have to assign one UILongPressGestureRecognizer per UIButton. They can all point to the same method.
- (void)createNewSetInDB:(BOOL)doWeAddItToTheDatabase
{
UIButton *newSet = [[UIButton alloc]initWithFrame:
CGRectMake((sliderMusic.frame.origin.x + imgWhiteLine.frame.size.width / 2) + (_musicPlayer.currentPlaybackTime * 10),
6,
35,
25)];
[newSet addTarget:self action:#selector(openSet:) forControlEvents:UIControlEventTouchUpInside];
[newSet setTitleColor:[MobileMarcherVariables sharedVariableInstance].systemColor forState:UIControlStateNormal];
[newSet.layer setBorderColor:[[MobileMarcherVariables sharedVariableInstance].systemColor CGColor]];
[newSet.layer setBorderWidth:1];
[newSet.titleLabel setFont:[UIFont systemFontOfSize:15]];
[newSet setTitle:[NSString stringWithFormat:#"%i",totalNumberOfSets] forState:UIControlStateNormal];
[scrollviewMusic addSubview:newSet];
[arrayofSetButtons addObject:newSet];
// Add gesture recognizer
//
UILongPressGestureRecognizer *showHandlesLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(showHandles:)];
showHandlesLongPress.minimumPressDuration = .5;
[newSet addGestureRecognizer:showHandlesLongPress];
if (doWeAddItToTheDatabase) [[NSNotificationCenter defaultCenter] postNotification:newSetNotification];
}

A gesture recognizer can only be attached to one view at a time. You're only creating one gesture recognizer. Each time you create a button, you attach the existing gesture recognizer to the new button, which removes it from the prior button.
Create a new gesture recognizer for each new button.
- (void)createNewSetInDB:(BOOL)doWeAddItToTheDatabase
{
UIButton *newSet = [[UIButton alloc]initWithFrame:
CGRectMake((sliderMusic.frame.origin.x + imgWhiteLine.frame.size.width / 2) + (_musicPlayer.currentPlaybackTime * 10),
6,
35,
25)];
[newSet addTarget:self action:#selector(openSet:) forControlEvents:UIControlEventTouchUpInside];
[newSet setTitleColor:[MobileMarcherVariables sharedVariableInstance].systemColor forState:UIControlStateNormal];
[newSet.layer setBorderColor:[[MobileMarcherVariables sharedVariableInstance].systemColor CGColor]];
[newSet.layer setBorderWidth:1];
[newSet.titleLabel setFont:[UIFont systemFontOfSize:15]];
[newSet setTitle:[NSString stringWithFormat:#"%i",totalNumberOfSets] forState:UIControlStateNormal];
[scrollviewMusic addSubview:newSet];
[arrayofSetButtons addObject:newSet];
UILongPressGestureRecognizer *showHandlesLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(showHandles:)];
showHandlesLongPress.minimumPressDuration = .5;
[newSet addGestureRecognizer:showHandlesLongPress];
if (doWeAddItToTheDatabase) [[NSNotificationCenter defaultCenter] postNotification:newSetNotification];
}

Related

Select/Deselect for dynamically created UIButtons

I will explain the Scenario:
I am dynamically creating three UIButtons inside a for loop.The condition is by default the first button should be bordered.Now if we select other buttons the previous button's border should go and now the border should be present for selected button.
for (int btnsCount = 0 ; btnsCount <[DataList count]; btnsCount++) {
self.graphSubDataButton = [[UIButton alloc] init];
self.graphSubDataButton.frame = CGRectMake(buttonsOffset, 0, 120, 40);
[self.graphSubDataButton setTitleColor:UIColorFromRGB(0x548DCD) forState:UIControlStateNormal];
[self.graphSubDataButton.titleLabel setFont:[UIFont fontWithName:AVENIR_NEXT_MEDIUM size:13.0f]];
self.graphSubDataButton.tag = btnsCount+1;
[self.graphSubDataButton addTarget:self action:#selector(enableRespectiveButton2:) forControlEvents:UIControlEventTouchUpInside];
buttonsOffset = buttonsOffset+30 + self.graphSubDataButton.frame.size.width ;
if (self.graphSubDataButton.tag==1)
{
[self.graphSubDataButton.layer setBorderWidth:1.2f];
[self.graphSubDataButton.layer setBorderColor:[UIColorFromRGB(0x3070BA) CGColor]];
[self.graphSubDataButton.layer setCornerRadius:8.0f];
}
}
-(void) enableRespectiveButton2:(UIButton *) sender
{
}
I have changed your code structure little to make it work properly, you can comment if you don't understand something.
NSInteger defaultSelectedTag = 1;
for (int btnsCount = 0 ; btnsCount <[DataList count]; btnsCount++) {
UIButton *graphSubDataButton = [UIButton buttonWithType:UIButtonTypeCustom];
graphSubDataButton.frame = CGRectMake(buttonsOffset, 0, 120, 40);
[graphSubDataButton setTitleColor:UIColorFromRGB(0x548DCD) forState:UIControlStateNormal];
[graphSubDataButton.titleLabel setFont:[UIFont fontWithName:AVENIR_NEXT_MEDIUM size:13.0f]];
graphSubDataButton.tag = btnsCount+1;
[graphSubDataButton addTarget:self action:#selector(enableRespectiveButton:) forControlEvents:UIControlEventTouchUpInside];
buttonsOffset = buttonsOffset+30 + self.graphSubDataButton.frame.size.width ;
//add your button somewhere
//e.g.
//[self.view addSubview:graphSubDataButton];
if (graphSubDataButton.tag == defaultSelectedTag) {
[self setBorderForButton:graphSubDataButton];
}
}
- (void) setBorderForButton:(UIButton *)sender {
[sender.layer setBorderWidth:1.2f];
[sender.layer setBorderColor:[UIColorFromRGB(0x3070BA) CGColor]];
[sender.layer setCornerRadius:8.0f];
}
- (void) enableRespectiveButton2:(UIButton *) sender {
for(UIButton *buttons in [sender.superview subviews]) {
if([buttons isKindOfClass:[UIButton class]]) {
if(![buttons isEqual:sender]) {
//add logic to, remove borders
//buttons.layer.borderWidth = 0.0f;
}
}
}
[self setBorderForButton:sender];
}
Use tag to get current selected button or much simple: iterate through all subviews and set border to 0 for UIButtons
for (UIView *subview in [uiv_ButtonsView subviews]) {
if([subview isKindOfClass:[UIButton class]]) {
subview.layer setBorderWidth:0.0f;
}
}
then use:
UIButton *button=(UIButton *)sender;
[button.layer setBorderWidth:1.2f];
[button.layer setBorderColor:[UIColorFromRGB(0x3070BA) CGColor]];
[button.layer setCornerRadius:8.0f];
Create dynamic buttons like :
int buttonsOffset = 50;
for (int btnsCount = 0 ; btnsCount <3; btnsCount++)
{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.backgroundColor = [UIColor blueColor];
btn.frame = CGRectMake(buttonsOffset, 100, 120, 40);
[btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[btn.titleLabel setFont:[UIFont systemFontOfSize:13.0f]];
btn.tag = btnsCount+1;
[btn addTarget:self action:#selector(enableRespectiveButton2:) forControlEvents:UIControlEventTouchUpInside];
buttonsOffset = buttonsOffset+30 + btn.frame.size.width;
if (btn.tag==1)
{
[btn.layer setBorderWidth:1.2f];
[btn.layer setBorderColor:[UIColor greenColor].CGColor];
[btn.layer setCornerRadius:8.0f];
self.graphSubDataButton = btn;
}
[self.view addSubview:btn];
}
And click event of button is as following
- (void)enableRespectiveButton2:(UIButton *)sender
{
sender.selected = TRUE;
[sender.layer setBorderWidth:1.2f];
[sender.layer setBorderColor:[UIColor greenColor].CGColor];
[sender.layer setCornerRadius:8.0f];
self.graphSubDataButton.selected = FALSE;
[self.graphSubDataButton.layer setBorderWidth:0.0f];
[self.graphSubDataButton.layer setBorderColor:[UIColor clearColor].CGColor];
[self.graphSubDataButton.layer setCornerRadius:0.0f];
self.graphSubDataButton = sender;
}
Create dynamic buttons with for loop as shown below.
for(int i = 0 ;i <3; i++) {
UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
NSString * title = [NSString stringWithFormat:#"Button %d",i];
[btn setTitle:title forState:UIControlStateNormal];
[btn setBackgroundImage:[UIImage imageNamed:#"BorderImg"] forState:UIControlStateSelected];
[btn setBackgroundImage:[UIImage imageNamed:#"UnBordered"] forState:UIControlStateNormal];
if(i == 0) [btn setSelected:YES];
else [btn setSelected:NO];
[btn setTag:i];
[btn addTarget:self action:#selector(btnTapped:) forControlEvents:UIControlEventTouchUpInside];
}
Have 2 images
Highlighted border (BorderImg)
Normal border (UnBordered)
Set those images to button while creating in for loop
- (void)btnTapped:(UIButton *) btn {
if(! btn.isSelected) {
[btn setSelected:YES];
}
Inside button selector method, based on the sender selection state , update the button selected state. (In side selector method i.e btnTapped set other buttons selected state to false)

Send button on Long press gesture

how can send button name, tag or text in long press gesture? I need to know the button name that long presed on.
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTagS:[[ToalData objectAtIndex:i] objectAtIndex:4]];
[button addTarget:self action:#selector(siteButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
///For long//
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleLongPress:)];
longPress.minimumPressDuration = 1.0;
[button addGestureRecognizer:longPress];
////
NSString *string1 = [NSString stringWithFormat:#"%#", [[ToalData objectAtIndex:i] objectAtIndex:1]];
[button setTitle:string1 forState:UIControlStateNormal];
button.frame = CGRectMake(XLocatioan, YLocation, 90, 30);
[self.view addSubview:button];
(void)handleLongPress:(UILongPressGestureRecognizer*)sender
{
if (sender.state == UIGestureRecognizerStateEnded)
{
NSLog(#"UIGestureRecognizerStateEnded");
}
else if (sender.state == UIGestureRecognizerStateBegan){
NSLog(#"UIGestureRecognizerStateBegan");
}
}
Every gesture recognizer is attached to a "view", which is a property on the gesture recognizer.
So in your "handleLongPress" method, you can do something like:
UIButton *button = (UIButton *)sender.view;
NSLog(#"title is %#", button.titleLabel.text);
NSLog(#"tag is %d", button.tag);

Popover for button created via code for long press

I know how to create popovers if my button added to story board, but how can I create popover if my button created via code.
UIButtonS *button = [UIButtonS buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:#selector(siteButtonPressed:)forControlEvents:UIControlEventTouchUpInside];
[button setTitle:string1 forState:UIControlStateNormal];
button.frame = CGRectMake(XLocatioan, YLocation, 90, 30);
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleLongPress:)];
longPress.minimumPressDuration = 1.0;
[button addGestureRecognizer:longPress];
[self.view addSubview:button];
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
}
else if (sender.state == UIGestureRecognizerStateBegan){
//create popover for button
}
}
You are already doing it right, but you are overthinking. There is no need to check the state of the gesture recognizer. If the target function has been triggered, it means that the user has done a long press. Also, note that not all of the values of the property state may be supported. As the documentation says: Some of these states are not applicable to discrete gestures.
So your code should look like this (unless you want to implement dragging or something similar):
UIButtonS *button = [UIButtonS buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:#selector(siteButtonPressed:)forControlEvents:UIControlEventTouchUpInside];
[button setTitle:string1 forState:UIControlStateNormal];
button.frame = CGRectMake(XLocatioan, YLocation, 90, 30);
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleLongPress:)];
longPress.minimumPressDuration = 1.0;
[button addGestureRecognizer:longPress];
[self.view addSubview:button];
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
//create popover for button
}
If your target is iOS 6+ you should use a UIPopoverController to create the popover, otherwise use UIAlertView.

drag drop issue in buttons

i have created a few butttons via code
for(int i=0;i<2;i++)
{
UIButton *btn_pin = [[UIButton alloc] initWithFrame:CGRectMake(100*i,100*i, 20, 20)];
[btn_pin setBackgroundColor:[self colorFromHexString:#"5DBBAB"]];
[btn_pin setTitle:[NSString stringWithFormat:#"%d",[arr_product count]+1] forState:UIControlStateNormal];
[btn_pin.titleLabel setFont:[UIFont fontWithName:#"ProximaNova-Regular" size:10.0]];
btn_pin.layer.cornerRadius = 10.0;
btn_pin.layer.masksToBounds = YES;
btn_pin.layer.borderColor = [UIColor whiteColor].CGColor;
btn_pin.layer.borderWidth = 1.0;
btn_pin.userInteractionEnabled = TRUE;
btn_pin.titleEdgeInsets = UIEdgeInsetsMake(2, 0, 0, 0);
[btn_pin.layer setBorderColor:[UIColor whiteColor].CGColor];
[btn_pin addTarget:self action:#selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDown];
[btn_pin addTarget:self action:#selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[img_main addSubview:btn_pin];
[tbl_product reloadData];
}
and now i want to move those buttons aroudn via drag , i have created a drag drop already but how do i get the reference of this button .
in your loop:
btn_pin.tag = i;
and in imageMoved :
UIButton *btn_pin = (UIButton *)sender;
int refIndex = btn_pin.tag;

UILongPressGestureRecognizer coordinates of press

I am using UILongPressGestureRecogniser on a UIImageView in this way:
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPress:)];
[ImageViewPhotoCard addGestureRecognizer:longPress];
- (void)longPress:(UILongPressGestureRecognizer*)gesture {
if ( gesture.state == UIGestureRecognizerStateEnded ) {
//NSString *key = [array objectAtIndex:i];
UIButton* ButtonNote = [UIButton buttonWithType:UIButtonTypeRoundedRect];
ButtonNote.frame = CGRectMake(100, 200, 80, 80); // position in the parent view and set the size of the button
[ButtonNote addTarget:self action:#selector(OpenNote:) forControlEvents:UIControlEventTouchUpInside];
ButtonNote.backgroundColor = [UIColor clearColor];
UIImage* btnImage = [UIImage imageNamed:#"purple_circle.png"];
[ButtonNote setBackgroundImage:btnImage forState:UIControlStateNormal];
[self.ViewA addSubview:ButtonNote];
[ArrayNotes addObject:ButtonNote];
[ButtonNote setTitle:#"" forState:UIControlStateNormal];
[ButtonNote setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
}
How is it possible to get the x and y coordinates of the point where the user has pressed?
CGPoint location = [gesture locationInView:self.view];
Is probably what you are looking for. This gives you a CGPoint of the touched point, according to the self.view coordinates

Resources