UILongPressGestureRecognizer got added to UISegmentedControl.
Is there a way to detect selectedSegmentIndex when long-pressing down?
thanks, in advance.
Did you try adding a UILongPressGestureRecognizer to it? In viewDidLoad:
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPress:)];
longPress.delegate = self;
[segmentedControl addGestureRecognizer:longPress];
Don't forget to add UIGestureRecognizerDelegate to your header file.
To know where is pressed:
- (void)longPress:(UILongPressGestureRecognizer *)gestureRecognizer {
CGPoint p = [gestureRecognizer locationInView:segmentedControl];
}
Then you could check what segment of segmentedControl matches with CGPoint p, check for the Y-coordinate, for example. When it's left from the middle line of the UISegmentedControl it's segment 0, when it's right of that line it's segment 1.
You register for long press in UISegmentedControl
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(ListQuizViewController.segmentLongPress(_:)))
//longPress.delegate = self;
self.segmentedControl.addGestureRecognizer(longPress)
longPress.minimumPressDuration = 1
You get index of selected button as follows with the assumption that segments are equally spaced
func segmentLongPress(gestureRecognizer:UILongPressGestureRecognizer)
{
let p = gestureRecognizer.locationInView(self.segmentedControl)
let index = Int(ceil( p.x/(self.segmentedControl.frame.width/4))) - 1
self.segmentedControl.selectedSegmentIndex = index
}
Related
I have an imageview and I want to tap on only one side of imageview. Is it possible to set frame for a gesture? Can anyone help with a solution?
Use UIGestureRecognizerDelegate, i think you can get the idea on how to compare:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch locationInView:yourview].x < somePoint.x) {
return false;
} else {
return true;
}
}
you could overlay a view on top of the imageview and add the tap recognizer to this new view, something like this will make the left hand side of the image tapable
UIView tapView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, imageView.frame.size.width/2, imageView.frame.size.height)];
[imageView addSubView:tapView]
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[tapView addGestureRecognizer:singleFingerTap];
You can simply put UIView on top of your imageView with frame as per your requirement and put tap gesture on that UIView.
You can do this by storyboard / xib or by programmatically.
By programmatically, for example - you want to tap only within the area with width of 50 px of your imageView. For this:
UIView *vw = [[UIView alloc] initWithFrame:CGRectMake(imgView.frame.origin.x, imgView.frame.origin.y, 50, imgView.frame.size.height)];
// add gesture to view
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
tapGesture.numberOfTapsRequired = 2;
[vw addGestureRecognizer:tapGesture];
[imgView addSubview:vw];
now to handle your double tap
-(void)handleTapGesture:(UITapGestureRecognizer *)gesture
{
// handle double tap
}
I have a tableView with custom cells. I have in one cell a imageView. I want add to this imageView one tapGesture for load a function then I click the imageView. So I have this code into cellForRowAtIndexPath:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected:)];
singleTap.numberOfTapsRequired = 1;
[cell.image setUserInteractionEnabled:YES];
[cell.image addGestureRecognizer:singleTap];
and
-(void)tapDetected:(id)sender{
NSLog(#"single Tap on imageview");
}
My problem is that when I scroll the table view this tap is added multiple times and changes into imageView then first click changes.
How can I change add only one time the tapGesture to all cells?
if you have a custom cell you can a function like this:
-(void) addTapGesture:(UITapGestureRecognizer*)tapGesture {
if (self.tapGesture == nil) {
[self.image setUserInteractionEnabled:YES];
[self.image addGestureRecognizer:singleTap];
self.tapGesture = tapGesture
}
}
in this way you are sure to set the tapGesture just once per cell.
Let me know if this can fix your problem
The Problem
Right now, you are adding a new TapGestureRecognizer every time cellForRowAtIndexPath is called, which is every time a cell is about to appear on the screen!
Solution 1: Keep the Old Gesture Recognizer
You can also just check if a cell already contains a gesture recognizer and not add a new one if it does. This will ensure that only one TapGestureRecognizer is applied to each cell:
// Check if the cell already contains a gesture recognizer
// if not, add one!
if (cell.gestureRecognizers.count == 0) {
// Now add the tap gesture recognizer and it will be the only one
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected:)];
singleTap.numberOfTapsRequired = 1;
[cell.image setUserInteractionEnabled:YES];
[cell.image addGestureRecognizer:singleTap];
}
Note: You should probably check and make sure the cell contains
exactly the gesture recognizer that you desire- you may want to add
more gesture recognizers to your cells and then you'll have to make
sure it contains the right one!
Solution 2: Remove Gesture Recognizers
Remove all gesture recognizers from the cell before adding the TapGestureRecognizer. This will ensure that only one TapGestureRecognizer is applied to each cell:
// Removes all gesture recognizers in the cell
for (UIGestureRecognizer *recognizer in cell.gestureRecognizers) {
[cell removeGestureRecognizer:recognizer];
}
// Now add the tap gesture recognizer and it will be the only one
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected:)];
singleTap.numberOfTapsRequired = 1;
[cell.image setUserInteractionEnabled:YES];
[cell.image addGestureRecognizer:singleTap];
just in you custom cell,do this :(i use swift as example)
class YourCell:UITableViewCell{
//add a variable to track has added a tapgesture to image view
var isAddedTapGesture = false
......
}
in your cellForRowAtIndexPath:
if(cell.isAddedTapGesture == false){
//add the tap gesture to your image
cell.cell.isAddedTapGesture = true
}
In your custom cell header, create a property like
#property (strong, nonatomic) UITapGestureRecognizer *tapGesture;
Add Getter method for the gesture.
- (UITapGestureRecognizer*)tapGesture{
if (!_tapGesture) {
_tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected:)];
}
return _tapGesture;
}
and inside the awakeFomNib function, Remove and re - add the gesture for the image view like the below.
[self.image removeGestureRecognizer:self.tapGesture];
[self.image addGestureRecognizer:self.tapGesture];
Hope this will be helpfull.
I have a NSAttributedString like so:
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:#"testing it out #clickhere"];
NSInteger length = str.length;
[str addAttribute:NSForegroundColorAttributeName value:[UIColor bestTextColor] range:NSMakeRange(0,length)];
The NSMutableAttributedString gets set to a UILabel like so:
label.attributedText = str;
How do I make a tap gesture (or something clickable) to another viewcontroller for the words '#clickhere in the string above?
Thanks!
I think, the best way is adding the UIGestureRecognizer to your UILabel and validate the frame that you would like.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[_yourLabel addGestureRecognizer:singleTap];
- (void)handleTap:(UITapGestureRecognizer *)tapRecognizer
{
CGPoint touchPoint = [tapRecognizer locationInView: _yourLabel];
//Modify the validFrame that you would like to enable the touch
//or get the frame from _yourLabel using the NSMutableAttributedString, if possible
CGRect validFrame = CGRectMake(0, 0, 300, 44);
if(YES == CGRectContainsPoint(validFrame, touchPoint)
{
//Handle here.
}
}
Simply first add a gesture to your label
[label setUserInteractionEnabled:YES];
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[label addGestureRecognizer:gesture];
control your gesture area in the below method
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
static CGRect touchableRect = CGRectMake(100.0f, 0.0f, 100.0f, 50.0f); // Give your rect as you need.
CGPoint touchPoint = [gestureRecognizer locationInView:self.view];
if (CGRectContainsPoint(touchableRect, touchPoint))
{
//User has tap on where you want. Do your other stuff here
}
}
UITapGestureRecognizer *Tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected)];
Tap.numberOfTapsRequired = 1;
// label Name Is your Label Name
[labelName addGestureRecognizer:Tap];
-(void)tapDetected
{
//your code
}
I'd just like to add on Ramshad's answer, about how to deal with the valid frame.
For this you might want to consider using UITextView instead of UILabel, which doesn't give you access to how it manages layout the text. By disabling editing, selection and scrolling, UITextView behaves roughly the same as a UILabel, except some padding you have to remove.
For convenience, you might want to add a little category to UITextView, in which you write a method to test if a point touches any of the characters in range.
- (BOOL)point:(CGPoint)point touchesSomeCharacterInRange:(NSRange)range
{
NSRange glyphRange = [self.layoutManager glyphRangeForCharacterRange:range actualCharacterRange:NULL];
BOOL touches = NO;
for (NSUInteger index = glyphRange.location; index < glyphRange.location + glyphRange.length; index++) {
CGRect rectForGlyphInContainer = [self.layoutManager boundingRectForGlyphRange:NSMakeRange(index, 1) inTextContainer:self.textContainer];
CGRect rectForGlyphInTextView = CGRectOffset(rectForGlyphInContainer, self.textContainerInset.left, self.textContainerInset.top);
if (CGRectContainsPoint(rectForGlyphInTextView, point)) {
touches = YES;
break;
}
}
return touches;
}
This would also work for a fragment of text containing multiple words spreading across multiple lines due to word wrap. It would also work on localized texts as we deal with glyphs that are printed.
The idea is the same as the accepted answer. Here is the way in Swift.
Suppose you have set up your label ready.
youLabel.text = "please tab me!"
Add tapGestuerRecognizer to your label
let tap = UITapGestureRecognizer(target: self, action: #selector(tapAction))
yourLabel.addGestureRecognizer(tap)
Add the String extension method to String to calculate the string rect.
extension String {
func rect(font: UIFont) -> CGRect {
let label = UILabel(frame: .zero)
label.font = font
label.text = self
label.sizeToFit()
return label.frame
}
}
Calculate the available tap rect of the tap gesture.
let pleaseStringRect = "please".rect(font: yourFont)
let tapStringRect = "tap".rect(font: yourFont)
let tapAreaRect = CGRect(x: pleaseStringRect.width, y: tapStringRect.origin.y, width: tapStringRect.width, height: tapStringRect.height"
In the action do what you want
#objc private func tapAction(tap: UITapGestureRecognizer) {
let position = tap.location(in: content)
guard reporterFirstNameRect.contains(position) else {
return
}
// Do the tap action stuff
}
That's it, happy coding.
I have added longpressGesture recognizer on view & given NoofTouchesRequired=2.I want to get the coordinates of both the views on which i have longpressed.
MyCode is as below:-
//---long press gesture---
UILongPressGestureRecognizer *longpressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector (handleLongpressGesture:)];
longpressGesture.minimumPressDuration = 4;
longpressGesture.numberOfTouchesRequired = 2;
[viewLongPress addGestureRecognizer:longpressGesture];
[longpressGesture release];
UIGestureRecognizer has a locationInView: method just for that.
-(void)handleLongpressGesture:(UIGestureRecognizer *)reco{
UIView *theSuperview = self.view;
CGPoint touchPointInSuperview = [reco locationInView:theSuperview];
}
This question already has answers here:
exclude subview from UITapGestureRecognizer
(3 answers)
Closed 9 years ago.
This is how I add gesture on view
- (void)_addPanGestureToView:(UIView *)view {
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(_handlePan:)];
panGesture.delegate = self;
panGesture.maximumNumberOfTouches = 1;
panGesture.minimumNumberOfTouches = 1;
[view addGestureRecognizer:panGesture];
}
Everything is working perfectly, but gesture is on the whole view how could I do something like gesture respond only in half of view?
Why not just use CGRectContainsPoint() and check if the touches location within your view is within the area you want it to be. If it isn't, ignore it:
- (void)panGestureDetected:(UIPanGestureRecognizer *)sender
{
CGPoint location = [sender locationInView:sender.view];
CGRect someRect = ...
if (CGRectContainsPoint(someRect, location)) {
// point is in specified area
}
}
Easiest solution would be adding a transparent view on the area where you want you gesture recognizer to work, and add the gesture to that view (and that view as a subview of course).
Somthing like:
- (void)_addPanGestureToView:(UIView *)view {
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(_handlePan:)];
panGesture.delegate = self;
panGesture.maximumNumberOfTouches = 1;
panGesture.minimumNumberOfTouches = 1;
UIView *viewForGesture = [[UIView alloc] initWithFrame:CGRectMake(....)]; //your frame
[viewForGesture addGestureRecognizer:panGesture];
[view addSubview:viewForGesture];
}