I have set animation with UILabel. And I add UITapGestureRecognizer for UILabel. But, I can not tap on UILabel.
This is my code:
Add gesture for UILabel:
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapOnLabel:)];
gesture.numberOfTapsRequired = 1;
_lbAnimation.userInteractionEnabled = YES;
[_lbAnimation addGestureRecognizer:gesture];
Animation UILabel
[UIView animateKeyframesWithDuration:6 delay:0 options:UIViewAnimationOptionAllowUserInteraction|UIViewAnimationOptionCurveEaseOut animations:^{
_lbAnimation.frame=CGRectMake(0-(rect.size.width), _lbAnimation.frame.origin.y, rect.size.width, _lbAnimation.frame.size.height);
} completion:^(BOOL finished)
{
_viewAnimation.hidden = YES;
}];
handleTapOnLabel function
- (void)handleTapOnLabel:(UITapGestureRecognizer *)tapGesture
{
CGPoint locationOfTouchInLabel = [tapGesture locationInView:tapGesture.view];
NSLog(#"_lbAnimation: %f : %f", locationOfTouchInLabel.x, locationOfTouchInLabel.y);
}
I don't know cause UILabel not tap.
Please help me.
Related
When my user taps on my UITextView (NOT uitextfield...), an animation occurs. However after the UITextView begins editing, no other UITapGesture seems to be recognized (e.g. if I add a tapGesture to my UIView to dismiss this animation, it doesn't execute at all). I've been trying to fix this for what feels like forever. Help is appreciated, I'm stumped.
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.replyField.delegate = self;
[self.replyField setUserInteractionEnabled:YES];
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(textViewTapped)];
[self.view addGestureRecognizer:gestureRecognizer];
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
-(void)textViewTapped {
NSLog(#"DISMISS PLEASE!");
[self animateTextView:NO];
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
[self animateTextView: YES];
self.replyField.gestureRecognizers = nil;
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
[self animateTextView:NO];
}
- (void) animateTextView:(BOOL) up
{
const int movementDistance = 206;
const float movementDuration = 0.3f;
int movement= movement = (up ? -movementDistance : movementDistance);
NSLog(#"%d",movement);
[UIView beginAnimations: #"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.inputView.frame, 0, movement);
[UIView commitAnimations];
}
- (void)textViewDidChange:(UITextView *)textView
{
}
Your problem is not related to gesture recognizer.
Problem caused by line:
self.view.frame = CGRectOffset(self.inputView.frame, 0, movement);
You set frame for self.view from self.inputView with offset.
And when self.view size is changed, its subviews (including text view) may have positions out of superview bound. And UIView doesn't respond touch event if touch point is out of superview bounds.
You can easily check this by setting background color for views and show they frames in log:
...
- (void) animateTextView:(BOOL) up
{
NSLog(#"self.view state1:%#", self.view);
NSLog(#"self.replyField state1:%#", self.replyField);
self.view.backgroundColor = [UIColor redColor];
self.replyField.backgroundColor = [UIColor blueColor];
const int movementDistance = 206;
const float movementDuration = 0.3f;
int movement= movement = (up ? -movementDistance : movementDistance);
NSLog(#"%d",movement);
[UIView beginAnimations: #"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
//self.view.frame = CGRectOffset(self.inputView.frame, 0, movement);
self.replyField.frame = CGRectOffset(self.replyField.frame, 0, movement);
[UIView setAnimationDidStopSelector:#selector(afterAnimationStops)];
[UIView commitAnimations];
}
- (void)afterAnimationStops {
NSLog(#"self.view state2:%#", self.view);
NSLog(#"self.replyField state2:%#", self.replyField);
}
...
Also what is self.inputView? is it properly set?
BTW: What goal of the code? Do you want to move text view to avoid overlapping by keyboard? Then consider placing it in UIScrollView.
e.g see discussion here: How to make a UITextField move up when keyboard is present?.
I have encountered similar issues use follow below code to dismiss keyboard by tapping anywhere on screen view. Hope will helpful to you.
Objective c
- (void)viewDidLoad
{
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:gestureRecognizer];
gestureRecognizer.cancelsTouchesInView = NO;
}
- (void)dismissKeyboard
{
[self.view endEditing:YES];
}
Swift 4
func viewDidLoad() {
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
view.addGestureRecognizer(gestureRecognizer)
gestureRecognizer.cancelsTouchesInView = false
}
func dismissKeyboard() {
view.endEditing(true)
}
In ViewDidLoad :
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
Create one method :
-(void)dismissKeyboard {
[textView resignFirstResponder];
}
Not clearly understand what you want BTW let me explain.
First of all if you want to hide your keyboard you can do it by single line code.
Objective C
[self.view endEditing:YES];
Swift
view.endEditing(true)
Now in your code, you added tap gesture on self.view it means if you touch main view anywhere then your gesture method will be call. If you want that my keyboard will be hide when I touch on main view then in tap gesture's method you should write above code ([self.view endEditing:YES];) But make sure keyboard will be open if you tap on your textView.
But If you want keyboard should not open when I click on UITextView then there are many ways but follow below
Objective C
UIView* dummyInputView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
myTextView.inputView = dummyInputView;
Swift
let dummyInputView = UIView(frame: CGRect(x: 0, y: 0, width: 1, height: 1))
myTextView.inputView = dummyInputView
Here keyboard will not be open but cursor will be blinking if you want to hide cursor then you can do by below code
Objective C
myTextView.tintColor = [UIColor clearColor];
Swift
myTextView.tintColor = UIColor.clear
If you have any issue then do comment.
In viewController you can do this
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self.view endEditing:Yes];
}
In my Xib. I have included 3 sub views and 3 small imageviews
![I Have to include animation to right swipe and left swipe for each view separately. Simple swipe for one view works fine according to the direction of swipe the item gets Favorited and the image position also could change ][2]
//........towards right Gesture recogniser for swiping.....//
UISwipeGestureRecognizer *rightRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(rightSwipeHandle:)];
rightRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[rightRecognizer setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:rightRecognizer];
//........towards left Gesture recogniser for swiping.....//
UISwipeGestureRecognizer *leftRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(leftSwipeHandle:)];
leftRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[leftRecognizer setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:leftRecognizer];
- (void)rightSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
NSLog(#"Right Gesture");
self.Favimage.hidden = false;
self.closeImage.hidden = true;
}
- (void)leftSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
NSLog(#"Left Gesture");
self.Favimage.hidden = true;
self.closeImage.hidden = false;
}
This what im tried now. I have to do it with better animation. Thanks in advance
i think. This is what you are looking for
- (void)rightSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
NSLog(#"Right Gesture");
self.closeImage.hidden = true;
// self.shoe.hidden = true;
//Do moving
CGRect finalFrame = CGRectMake(150,5, 64, 63);
[UIView animateWithDuration:0.5 animations:^{
_shoe.frame = finalFrame;
self.Favimage.hidden = true;
} completion:^(BOOL finished) {
self.Favimage.hidden = false;
// [_Favimage removeFromSuperview];
//[_Favimage removeFromSuperview];
//[self.view removeGestureRecognizer:gestureRecognizer];
}];
}
- (void)leftSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
NSLog(#"Left Gesture");
self.Favimage.hidden = true;
self.closeImage.hidden = false;
CGRect finalFrame = CGRectMake(77,5, 70, 63);
[UIView animateWithDuration:0.5 animations:^{
_shoe.frame = finalFrame;
} completion:^(BOOL finished) {
//self.Favimage.hidden = false;
//[_Favimage removeFromSuperview];
//[_Favimage removeFromSuperview];
//[self.view removeGestureRecognizer:gestureRecognizer];
}];
// do moving
}
try this one
I have a uiimageview in my detail view, and I want to make it so that when I tap on the image, it opens the image full screen. However, my code below doesn't seem to be working. Any idea what I seem to be doing wrong?
FullViewController.h
#interface FullArticleViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIGestureRecognizerDelegate>
{
IBOutlet UITapGestureRecognizer *tap;
IBOutlet UIScrollView *scroller;
IBOutlet UILabel *firstnameLabel;
IBOutlet UILabel *bodyLabel;
IBOutlet UILabel *descriptionLabel;
BOOL isFullScreen;
CGRect prevFrame;
}
FullViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
if ([[articleDetail objectForKey:#"ytID"] isEqualToString:#"none"]) {
featureImage.userInteractionEnabled = YES;
NSString *imageUrl = [NSString stringWithFormat:#"image/%#",cellImageLink];
[self.featureImage sd_setImageWithURL:[NSURL URLWithString:imageUrl]];
[scroller setScrollEnabled:YES];
featureImage.userInteractionEnabled = YES;
[scroller bringSubviewToFront:featureImage];
UITapGestureRecognizer *tapgesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgToFullScreen)];
[tapgesture setNumberOfTapsRequired:1];
[featureImage addGestureRecognizer:tap];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
{
BOOL shouldReceiveTouch = YES;
if (gestureRecognizer == tap) {
shouldReceiveTouch = (touch.view == featureImage);
}
return shouldReceiveTouch;
}
-(void)imgToFullScreen{
if (!isFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
prevFrame = featureImage.frame;
[featureImage setFrame:[[UIScreen mainScreen] bounds]];
}completion:^(BOOL finished){
isFullScreen = true;
}];
return;
} else {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[featureImage setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = false;
}];
return;
}
}
Edit: See code updated above, and hierarchy below
Try this in your viewDidLoad: method:
[featureImage setUserInteractionEnables:YES];
UITapGestureRecognizer *tapgesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgToFullScreen)];
[tapgesture setNumberOfTapsRequired:1];
[featureImage addGestureRecognizer:tapgesture];
I implemented the feature to display a fullscreen image when it is tapped. However this only enlarge the image but does not show it with a black background (the other elements of the view are still in the bakcground). How can I do this?
//Setup touch up inside of the imageview (in viewdidload)
userPictImageView.userInteractionEnabled = YES;
userPictImageView.contentMode = UIViewContentModeScaleAspectFit;
UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageViewFullScreenTouchHandler:)];
tapper.numberOfTapsRequired = 1;
[userPictImageView addGestureRecognizer:tapper];
//present a full screen image (without black background)
-(IBAction)imageViewFullScreenTouchHandler:(id)sender {
//goto new ViewController and set the image
UIImageView *imageView = userPictImageView;
if (!imageIsFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
prevFrame = imageView.frame;
blackView=[[UIView alloc]initWithFrame:self.view.frame];
[blackView setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:blackView];
CGRect frame = self.view.frame;
[imageView setFrame:frame];
[blackView addSubview:imageView]; }
completion:^(BOOL finished){
imageIsFullScreen = TRUE;
}];
return;
}
else{
self.view.backgroundColor = [UIColor clearColor];
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[imageView setFrame:prevFrame];
}completion:^(BOOL finished){
imageIsFullScreen = FALSE;
}];
return;
}
}
You could change to UIViewContentModeScaleToFill, or, probably better, build a UIView with a black background whose frame matches the view frame. Make the image view a subview of that black view.
I'd do it something like this. Create a method that I can call to zoom and unzoom the imageView. To zoom, build a background view and attach the image. To unzoom, do the reverse, and then destroy the background view.
Since the background view will be full screen, attach a gesture recognizer to it so the user can tap to dismiss.
- (void)setUserPictImageViewZoomed:(BOOL)zoom animated:(BOOL)animated {
UIView *blackView = [self.view viewWithTag:128];
BOOL isZoomed = blackView != nil;
// if our current state (isZoomed) matches the desired state (zoomed), then we're done
if (isZoomed == zoom) return;
NSTimeInterval duration = (animated)? 0.3 : 0.0;
if (zoom) {
blackView = [[UIView alloc] initWithFrame:self.view.frame];
blackView.backgroundColor = [UIColor blackColor];
blackView.tag = 128;
blackView.alpha = 0.0;
[self.view addSubview:blackView];
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(unzoom:)];
[blackView addGestureRecognizer:tapGR];
UIImageView *zoomImageView = [[UIImageView alloc] initWithImage:self.userPictImageView.image];
zoomImageView.contentMode = UIViewContentModeScaleAspectFit;
zoomImageView.tag = 129;
zoomImageView.frame = [self.userPictImageView convertRect:self.userPictImageView.frame toView:blackView];
[blackView addSubview:zoomImageView];
[UIView animateWithDuration:duration animations:^{
zoomImageView.frame = blackView.bounds;
blackView.alpha = 1.0;
}];
} else {
UIImageView *zoomImageView = (UIImageView *)[blackView viewWithTag:129];
[UIView animateWithDuration:duration animations:^{
zoomImageView.frame = self.userPictImageView.frame;
blackView.alpha = 0.0;
} completion:^(BOOL finished) {
[blackView removeFromSuperview];
}];
}
}
- (void)unzoom:(UIGestureRecognizer *)gr {
[self setUserPictImageViewZoomed:NO animated:YES];
}
I tested this quickly in a simulator and it looked pretty slick.
I have a simple program that creates a subview and animates it across the screen.
As part of this program, I would like to add functionality when the subview is tapped. I am using the following method to create the subview, add the UITapGestureRecognizer and then animate the subview:
int randomName = arc4random() % ([pieceNames count] - 1);
int animationDuration = arc4random() % 5 + 5 ;
NSString *randomPiece = [pieceNames objectAtIndex:randomName];
float yStart = arc4random() % 650;
float yEnd = arc4random() % 650;
UIView *piece = [[PieceView alloc]initWithFrame:CGRectMake(100.0, yStart, 75.0, 75.0)];
[piece setValue:randomPiece forKey:#"name"];
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc]initWithTarget:self
action:#selector(handleTouch:)];
[piece addGestureRecognizer:recognizer];
[[self view] addSubview:piece];
[UIView animateWithDuration:animationDuration
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^(void){
piece.center = CGPointMake(950.0, yEnd);
} completion:^(BOOL done){
[piece removeFromSuperview];
}];
Here is the code that handles the tap:
PieceView *pv = (PieceView *) recognizer.view;
NSLog(#"%# was tapped", pv.name);
What happens is when a PieceView is touched the program does not respond. However, if I remove the animation block then the program responds to the tap.
Why does the UITapGestureRecognizer fail to respond to PieceView when it is animated?
I struggled with this same problem, and it boils down to this: the animated view only ever is in two places: the starting position, and the ending position. Core Animation simply renders the view's layer in interpolated positions between the start and end points over a period of time.
It's almost like when you look to the stars and realize that what you see is not actually what is happening right now. :)
Luckily, the solution is pretty simple. You can put a tap recognizer on the superview and then inspect your animated view's presentationLayer (which does give you an accurate frame at any point in time) to determine if your tap is a hit or not.
I've built a simple UIViewController that demonstrates both the problem and solution:
#import <UIKit/UIKit.h>
#interface MSMViewController : UIViewController
#end
And the implementation:
#import "MSMViewController.h"
#interface MSMViewController ()
#property (nonatomic, strong) UIView *animatedView;
#end
#implementation MSMViewController
- (void)viewDidLoad {
[super viewDidLoad];
CGRect startFrame = CGRectMake(125, 0, 70, 70);
CGRect endFrame = CGRectMake(125, 400, 70, 70);
// draw a box to show where the animated view begins
UIView *startOutlineView = [[UIView alloc] initWithFrame:startFrame];
startOutlineView.layer.borderColor = [UIColor blueColor].CGColor;
startOutlineView.layer.borderWidth = 1;
[self.view addSubview:startOutlineView];
// draw a box to show where the animated view ends
UIView *endOutlineView = [[UIView alloc] initWithFrame:endFrame];
endOutlineView.layer.borderColor = [UIColor blueColor].CGColor;
endOutlineView.layer.borderWidth = 1;
[self.view addSubview:endOutlineView];
self.animatedView = [[UIView alloc] initWithFrame:startFrame];
self.animatedView.backgroundColor = [UIColor yellowColor];
[self.view addSubview:self.animatedView];
[UIView animateWithDuration:10 delay:2 options:UIViewAnimationOptionAllowUserInteraction animations:^{
self.animatedView.frame = endFrame;
} completion:nil];
// this gesture recognizer will only work in the space where endOutlintView is
UITapGestureRecognizer *boxTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(boxTap:)];
[self.animatedView addGestureRecognizer:boxTap];
// this one will work
UITapGestureRecognizer *superviewTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(superviewTap:)];
[self.view addGestureRecognizer:superviewTap];
}
- (void)boxTap:(UITapGestureRecognizer *)tap {
NSLog(#"tap. view is at %#", NSStringFromCGPoint(self.animatedView.frame.origin));
}
- (void)superviewTap:(UITapGestureRecognizer *)tap {
CGRect boxFrame = [self.animatedView.layer.presentationLayer frame];
if (CGRectContainsPoint(boxFrame, [tap locationInView:self.view])) {
NSLog(#"we tapped the box!");
}
}
#end
The solution is much simpler, you just need to set the animation's option UIViewAnimationOptions.allowUserInteraction.
UIView.animate(withDuration: duration, delay: 0.1, options: [.allowUserInteraction], animations: {
...
}, completion: { (completed) in
...
}