I have 2 UIButtons that each one changes the number in the middle (please see the picture).
I want that when the user holds the button the numbers will still be changing (now, when you want to change from 100 to 200 you need to tap 100 times and it's not good, I want that when you hold the button the numbers will be changing), that probably means that each UIButon's action should be called again and again until the user releases the button.
How can I do that? Thanks!
Here's the code I have written that matches your requirements. Make sure to link the plus and minus button outlets and its target events(touch up inside) in your storyboard. If it's not clear just let me know.
#import "ViewController.h"
#interface ViewController () {
NSTimer *speedTimer;
}
//Link this in your storyboard Outlets
#property (weak, nonatomic) IBOutlet UILabel *speedUILabel;
#property (weak, nonatomic) IBOutlet UIButton *plusUIButton;
#property (weak, nonatomic) IBOutlet UIButton *minusUIButton;
//Link this in your storyboard events respectively
- (IBAction)plusUIButton:(id)sender;
- (IBAction)minusUIButton:(id)sender;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UILongPressGestureRecognizer *plusButtonPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressHandler:)];
UILongPressGestureRecognizer *minusButtonPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressHandler:)];
[_plusUIButton addGestureRecognizer:plusButtonPress];
[_minusUIButton addGestureRecognizer:minusButtonPress];
plusButtonPress.delegate = self;
minusButtonPress.delegate = self;
plusButtonPress.minimumPressDuration = 0.5;
minusButtonPress.minimumPressDuration = 0.5;
plusButtonPress.allowableMovement = 0.5;
minusButtonPress.allowableMovement = 0.5;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)plusUIButton:(id)sender {
NSInteger plus = [_speedUILabel.text integerValue] + 1;
if (plus >= 0) {
_speedUILabel.text = [NSString stringWithFormat:#"%ld", (long)plus];
}
}
- (IBAction)minusUIButton:(id)sender {
NSInteger minus = [_speedUILabel.text integerValue] - 1;
if (minus >= 0) {
_speedUILabel.text = [NSString stringWithFormat:#"%ld", (long)minus];
}
}
- (void) longPressHandler: (UILongPressGestureRecognizer *) gesture {
if (gesture.view == _plusUIButton) {
if(gesture.state == UIGestureRecognizerStateBegan) {
speedTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(plusUIButton:) userInfo:nil repeats:true];
}
else if(gesture.state == UIGestureRecognizerStateEnded) {
[speedTimer invalidate];
speedTimer = nil;
}
}
else if (gesture.view == _minusUIButton) {
if(gesture.state == UIGestureRecognizerStateBegan) {
speedTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(minusUIButton:) userInfo:nil repeats:true];
}
else if(gesture.state == UIGestureRecognizerStateEnded) {
[speedTimer invalidate];
speedTimer = nil;
}
}
}
#end
You have to use the UILongPressGestureRecognizer which is a continuous calling action instead of calling methods with button tap. So just put the left/Right buttons in separate views and add UILongPressGestureRecognizer to these left/Right views and add target to these recognizers e.g
UILongPressGestureRecognizer *leftLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(decreaseNum:)];
UILongPressGestureRecognizer *rightLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(increaseNum:)];
[leftView addGestureRecognizer:leftLongPress];
[rightView addGestureRecognizer:rightLongPress];
Hope this will resolve your problem .
Use UILongPressGestureRecognizer on both UIButton
UILongPressGestureRecognizer *LeftButtonPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressHandler:)];
UILongPressGestureRecognizer *RightButtonPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressHandler:)];
[btnLeft addGestureRecognizer:LeftButtonPress];
[btnRight addGestureRecognizer:RightButtonPress];
code on state change for update screen.
- (void) longPressHandler: (UILongPressGestureRecognizer *) gesture {
if(gesture.state == UIGestureRecognizerStateChanged) {
// update number on screen
}
}
You can do like this in Swift:
#IBOutlet weak var btn: UIButton!
override func viewDidLoad() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.Long)) //Tap function will call when user tap on button
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.Long)) //Long function will call when user long press on button.
tapGesture.locationInView(btn);
btn.addGestureRecognizer(tapGesture) // To set the tap gesture recognizer: the function Tap () will be calling when the user select the button normally.
btn.addGestureRecognizer(longGesture) // To set the long gesture recognizer: the function Long () will be calling when the user select the button with a long press.
}
func Tap() {
print("Tap happend")
}
func Long() {
print("Long press")
}
Related
Can anyone give me an example about Touch drag enter to drag from a button to another that triggering both button's event.
And how does it work?
For example, I want to drag from Do to Fa that event of Do, Re, Mi, Fa are triggered.
Here is my code:
- (void) setupVC {
soundBankPlayer = [[SoundBankPlayer alloc] init];
[soundBankPlayer setSoundBank:#"Piano"];
arrMusicalNotes = [NSArray arrayWithObjects:#"60", #"62", #"64", #"65", #"67", #"69", #"71", #"72", nil];
}
#pragma mark - Setup Musical Note
- (IBAction)btnMusicalNoteclick:(id)sender {
int numOfNote = [[arrMusicalNotes objectAtIndex:((UIButton*)sender).tag] intValue];
NSLog(#"%i", numOfNote);
[soundBankPlayer queueNote:numOfNote gain:1.0f];
[soundBankPlayer playQueuedNotes];
}
- (IBAction)btnDragOut:(id)sender {
NSLog(#"Out");
}
Oh I've seen that when i hold click out of Simulator, the method btnDragOut is triggered. And when i drag from out of Simulator to the button, the method of this button is triggered.
Now I want the method btnDragOut is triggered when i drag out of a button (finger is still in Simulator). Anyone know that?
You can add UIPanGestureRecognizer to your view of your UIViewController subclass via Storyboard or via code in viewDidLoad method:
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleDrag:)];
[self.view addGestureRecognizer:gestureRecognizer];
Then you can add property in implementation file of your UIViewController subclass of current UIButton being dragged:
#interface YourViewController ()
#property (weak, nonatomic) UIButton *currentButton;
#end
Now in action method you can detect UIControlEventTouchDragEnter and UIControlEventTouchDragExit events as follows:
- (void)handleDrag:(UIPanGestureRecognizer *)gestureRecognizer
{
CGPoint point = [gestureRecognizer locationInView:self.view];
UIView *draggedView = [self.view hitTest:point withEvent:nil];
if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {
if ([draggedView isKindOfClass:[UIButton class]] && !self.currentButton) {
self.currentButton = (UIButton *)draggedView;
NSLog(#"Enter: %ld", (long)self.currentButton.tag);
// send enter event to your button
[self.currentButton sendActionsForControlEvents:UIControlEventTouchDragEnter];
}
if (self.currentButton && ![self.currentButton isEqual:draggedView]) {
NSLog(#"Out: %ld", (long)self.currentButton.tag);
// send exit event to your button
[self.currentButton sendActionsForControlEvents:UIControlEventTouchDragExit];
self.currentButton = nil;
}
} else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
self.currentButton = nil;
}
}
I am currently building a custom keyboard and I am almost done. One problem that I have is with the delete button. When the user taps the delete button, it does what it should do and deletes the previous text entry. However when the user holds the button down, nothing happens. How do I make it so that when the user holds down the delete button, the keyboard continuously deletes like in the standard ios keyboard? This is my current code:
pragma mark Keyboards
- (void)addGesturesToKeyboard{
[self.keyboard.deleteKey addTarget:self action:#selector(pressDeleteKey)forControlEvents:UIControlEventTouchUpInside];
and:
-(void)pressDeleteKey{
[self.textDocumentProxy deleteBackward];
}
Thanks for your help.
Swift 3 Use "allowableMovement" property
override func viewDidLoad() {
super.viewDidLoad()
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(KeyboardViewController.handleLongPress(_:)))
longPress.minimumPressDuration = 0.5
longPress.numberOfTouchesRequired = 1
longPress.allowableMovement = 0.1
buttonDelete.addGestureRecognizer(longPress)
}
func handleLongPress(_ gestureRecognizer: UIGestureRecognizer) {
textDocumentProxy.deleteBackward()
}
you can do this by managing button’s events like touchdown, touchupinside and touchoutside.
When button press at that time start timer with delay of 0.2 seconds and delete last characters from textDocumentProxy until button’s touchup method will fire and after that you just need to invalidate timer.
[self.btnDelete addTarget:self action:#selector(btnTocuhDown:) forControlEvents:UIControlEventTouchDown];
[self.btnDelete addTarget:self action:#selector(btnTouchUp:) forControlEvents:UIControlEventTouchUpInside];
[self.btnDelete addTarget:self action:#selector(btnTouchUp:) forControlEvents:UIControlEventTouchUpOutside];
-(void) btnTocuhDown
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(kpTimerMethod:) userInfo:nil repeats:YES];
self.kpTimer = timer;
__weak typeof(self)weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void){
if (timer == self.kpTimer) {
[weakSelf.kpTimer fire];
}
});
-(void)kpTimerMethod:(NSTimer *)timer
if (self.btnDelete.highlighted)
{
[self deleteLastCharacter];
}
else
{
[timer invalidate];
self.kpTimer = nil;
}
-(void)deleteLastCharacter
NSString *strInput = self.textDocumentProxy.documentContextBeforeInput;
if (strInput.length > 1)
NSString *coupleOfLastCharacters = [strInput substringWithRange:NSMakeRange(strInput.length-2, 2)];
if( [#"yo" caseInsensitiveCompare:coupleOfLastCharacters] == NSOrderedSame ) {
[self.textDocumentProxy deleteLastCharacter];
}
}
[self.textDocumentProxy deleteLastCharacter];
-(void) btnTouchUp
[self.kpTimer invalidate];
self.kpTimer = nil;
- (void)addGesturesToKeyboard{
UILongPressGestureRecognizer *ges = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPress:)];
ges.minimumPressDuration = 0.1;
ges.numberOfTouchesRequired = 1;
ges.delegate = self;
[self.mykeyboard.deleteKey addGestureRecognizer:ges];
}
- (void)longPress:(UILongPressGestureRecognizer*)gesture {
[self.textDocumentProxy deleteBackward];
}
Set a counter as soon as the screen is touched, such as 2-5 seconds.
The situation known as Long press gesture, and here is the link to the simliar questions.
Long press gesture on UICollectionViewCell
If the user keeps clicking on button1 one or two , progress2.progress keeps increasing/decreasing on each click and progress1.progress keeps the same value until the user stops clicking. And in case he will surely lose , if he also keeps clicking nothing happens until he stops clicking. I don't want it to be that way since I want to hide/disable the buttons as soon as it's confirmed that he's losing to fix this issue. Any way to fix that?
Here is my .m :
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (BOOL)prefersStatusBarHidden { return YES; }
- (void)viewDidLoad
{
progress1.progress=arc4random() % 11 * 0.1;
count1=0;
count2=0;
label1.hidden = NO;
gameOver.hidden = YES;
score=0;
[super viewDidLoad];
;
}
// Do any additional setup after loading the view, typically from a nib.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)regulator{
if(timer1)
{
[timer1 invalidate];
timer1 = nil;
}
if(timer4)
{
[timer4 invalidate];
timer4 = nil;
}
timer4 =[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:#selector(conditioner) userInfo:nil repeats:YES];
;}
-(void)conditioner {
if (fabs(progress2.progress-progress1.progress)<=0.25 )
{
score=score+1;
scorenumber.text= [NSString stringWithFormat:#"%i",score];
[self newGame];
;
} else{
stop1=YES;
stop2=YES;
gameOver.hidden=NO;
stick.hidden=YES;
bg.hidden=YES;
progress1.hidden=YES;
progress2.hidden=YES;
supply.hidden=YES;
demand.hidden=YES;
}}
-(void)newGame{
progress1.progress=arc4random() % 11 * 0.1;}
- (IBAction)start:(UIButton *)sender {
progress2.progress=arc4random() % 11 * 0.1;
if(timer4)
{
[timer4 invalidate];
timer4 = nil;
timer1 = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(regulator) userInfo:nil repeats:YES];
[self regulator];
stop1=NO;
stop2=NO;
label1.hidden=YES;
UIButton *button1 = (UIButton *)sender;
button1.enabled = NO;
UIButton *button2 = (UIButton *)sender;
button2.enabled = NO;
}
- (IBAction)button1:(UIButton *)sender {
if(stop1==YES){button12.hidden = TRUE;}
progress2.progress=progress2.progress-0.05;
;
[self regulator];
count2=0;
count1 = count1 +1;
}
- (IBAction)button2:(UIButton *)sender {
[self regulator];
progress2.progress=progress2.progress+0.05;
if(stop2==YES){button22.hidden = TRUE;}
count1 =0;
count2 = count2+1;
}
#end
and my .h:
#import <UIKit/UIKit.h>
int count1;
int count2;
int score;
void *regulator;
void *newGame;
void *conditioner;
BOOL stop1;
BOOL stop2;
void *firstLaunch;
#interface ViewController : UIViewController{
IBOutlet UILabel *scorenumber;
IBOutlet UIImageView *stick;
IBOutlet UILabel *label1;
IBOutlet UIImageView *bg;
IBOutlet UILabel *supply;
IBOutlet UILabel *demand;
IBOutlet UILabel *gameOver;
IBOutlet UIProgressView *progress1;
IBOutlet UIProgressView *progress2;
IBOutlet UIButton *button12;
IBOutlet UIButton *button22;
NSTimer *timer1;
NSTimer *timer2;
NSTimer *timer3;
NSTimer *timer4;
}
- (IBAction)button1:(UIButton *)sender;
- (IBAction)button2:(UIButton *)sender;
#end
Thanks a lot for any help or information. I edited my question with the full code to give further explanation about the issue I'm facing. Regards.
This is actually a coding issue. MVC basics.
I believe you miss some understanding of things. So I'll explain:
IBAction - It's an action sent from the view to the controller.
IBOutlet - Meant for the controller to control the view.
On your code you are getting the sender (which should be read only when coding right) and you are trying to set it up. I assume you need to define a new IBOutlet to represent the button then connect it on your storyboard and then inside this function to make it enable/disabled.
Also a good practice would be to use "TRUE" and "FALSE" and not "YES/NO".
Hope this helps.
There are couple of ways you can approach this to make sure when user touches the button then it doesn't do anything.
It wasn't clear from your question so I assume on touch down of button you call (IBAction)button1. So Try
- (IBAction)button1:(UIButton *)sender
{
if(stop1==YES)
{
//game has stopped so don't do anything
}
else
{
progress2.progress=progress2.progress-0.05;
[self regulator];
}
}
If you want to hide it so that the user can't do anything try this
- (IBAction)button1:(UIButton *)sender
{
if(stop1==YES)
{
//game has stopped so hide this button
//assuming you have connected an IBOutlet to your button1
button1.hidden = YES;
}
else
{
button1.hidden = NO;
progress2.progress=progress2.progress-0.05;
[self regulator];
}
}
In my project I would like to make a hidden image view appear when it is tapped for more than 3 seconds. I know I need to use NSTimer, but I have never created a UIImageView touch event. How can I combine the TapGestureRecognizer with NSTimer to achieve what I want to do? I am completely new to touch events in iOS, and I am just beginning to explore this. So, any help would be appreciated. Thank you!
UPDATE:
I implemented the UILongPressGestureRecognizer as below, but now, the hidden image appears even if I press somewhere outside of the image. How can I make it appear only if pressing the hidden image itself?
- (void)viewDidLoad
{
[super viewDidLoad];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(handleLongPress:)];
longPress.numberOfTouchesRequired = 1;
longPress.minimumPressDuration = 3;
[self.view addGestureRecognizer:longPress];
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan)
{
BrokenGlass.hidden = NO;
}
}
You don't want a UITapGestureRecognizer and a timer, you want a UILongPressGestureRecognizer.
The image is appearing because you are using the gesture recognizer in the entire view.
[**self.view** addGestureRecognizer:longPress];
The gesture will not trigger on a hidden element.
Here is my solution:
#interface ViewController () <UIGestureRecognizerDelegate>
#property (nonatomic, strong) UIImageView *imageView;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// create the imageView
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
// enable the user interaction in the imageView (otherwise it will not receive events)
_imageView.userInteractionEnabled = YES;
// add as a subview of the main view
[self.view addSubview:_imageView];
// create the gesture recognizer
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressHandler:)];
longPressGesture.delegate = self;
longPressGesture.minimumPressDuration = 3;
// add the gesture to the imageView
[_imageView addGestureRecognizer:longPressGesture];
}
#pragma mark - UIGestureRecognizerDelegate
- (void)longPressHandler:(UILongPressGestureRecognizer *)gestureRecognizer {
// show the image
_imageView.image = [UIImage imageNamed:#"cat.jpeg"];
}
I want to implement , when swipe bottom to top of screen the keyboard is shown on screen and when swipe from top to bottom on screen the keyboard hides.
Its like iOS 7 effect when we swipe on screen the search textfield and keyboard is shown and when swipe down its hide.
Try this:
//declare a property to store your current responder
#property (nonatomic, assign) id currentResponder;
//in viewDidLoad:
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(resignOnSwipe:)];
[self.collectionView addGestureRecognizer:swipe];
//Implement the below delegate method:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
self.currentResponder = textField;
}
//Implement resignOnSwipe:
- (void)resignOnSwipe:(id)sender {
[self.currentResponder resignFirstResponder]
}
Try Something like this,.. It works fine
In xib,
Add a textfield and hide it. Connect that to your .h file and name it as tf.
In .h file,
Add
#import <UIKit/UIKit.h>
#interface KeyboardDisplay : UIViewController <UIGestureRecognizerDelegate>
{
__weak IBOutlet UITextField *tf;
}
In .m file,
- (void)viewDidLoad
{
[super viewDidLoad];
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeGesture:)];
swipeGesture.direction = UISwipeGestureRecognizerDirectionUp;
[self.view addGestureRecognizer:swipeGesture];
UISwipeGestureRecognizer *swipeGesture2 = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeGesture:)];
swipeGesture2.direction = UISwipeGestureRecognizerDirectionDown;
[self.view addGestureRecognizer:swipeGesture2];
}
-(void)handleSwipeGesture:(UISwipeGestureRecognizer *) sender
{
//Gesture detect - swipe up/down , can be recognized direction
if(sender.direction == UISwipeGestureRecognizerDirectionUp)
{
[tf becomeFirstResponder];
NSLog(#"Up");
}
else if(sender.direction == UISwipeGestureRecognizerDirectionDown)
{
[tf resignFirstResponder];
NSLog(#"down");
}
}
NOTE : Don't forget to hide the textfield in xib.