I have a UILabel
as child in my UIView
. I use it as status panel which slides out of the view if nothing has to be shown. I do that by simply animating it to origin.y of minus the height of the label.
As soon as a message has to be displayed, I slide the label back into the view. After a delay of a few seconds it slides back out. That works fine.
I also added a UITapGestureRecognizer
to the label, so the user can dismiss the message right away without waiting for it to go away automatically.
My problem is, that the gesture recognizer is not firing as once the label moved outside the view. I initialize and add the gesture recognizer when the label is completely inside the view and visible. It works as expected the first time. But when the message comes back in, the gesture recognizer seems to be removed or disabled.
I also tried to add a gr every time the label is completely on the screen in the complete block of my animation, but that didn't help either.
Can someone explain to me what happens here and how I can make the recognizer work all the time?
If you need and further information let me know.
I did some further testing and I get this when I log the lblError.gestureRecognizers in the showError call:
<UITapGestureRecognizer: 0x6b153f0; state = Possible; view = <UILabel 0x6b14fa0>; target= <(action=dismissError:, target=<OptionViewController 0x686d2a0>)>>
It's exactly the same I get right after it's creation. So it's still there and I guess the touch events don't get to it.
I get a step further.
The problem seems to be that I move the label to y coordinate 0. That's probably a bug in the GestureRecognizer
code because when I set it 0.1 it works!
Looks like the system "thinks" that the label is not in the view and therefore disables the touch handling or something. ^^
This solves one half of the problem but creates a new one on the other side. Now that the gesture recognizer works, the delayed move out animation don't get triggered anymore.
So I think the real problem is, that the move out animation is triggered right after the move in. Even though it is delayed, it prevents the label from receiving any kind of touch events.
// add gesture recognizer (in viewDidLoad)
UITapGestureRecognizer *errorDismissGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissError:)];
[lblError addGestureRecognizer:errorDismissGesture];
// display error
- (void)showError:(NSString *)message {
[lblError setText:message];
[UIView animateWithDuration:0.5
animations:^(void) {
CGRect frame = lblError.frame;
frame.size.width = self.view.bounds.size.width;
frame.origin.y = 0;
lblError.frame = frame;
}
completion:^(BOOL finished) {
[UIView animateWithDuration:0.5
delay:2.0
options:UIViewAnimationOptionCurveEaseOut
animations:^(void) {
CGRect frame = lblError.frame;
frame.origin.y = -40.0f;
lblError.frame = frame;
}
completion:^(BOOL finished) {}];
}];
}
- (void)dismissError:(UIGestureRecognizer *)sender {
[UIView animateWithDuration:0.3
animations:^(void) {
CGRect frame = lblError.frame;
frame.origin.y = -40.0;
lblError.frame = frame;
}
completion:^(BOOL finished) {}];
}
Thanks and Greets, Thomas
I finally solved it!
It seems like the delayed move out animation somehow prevents the label from receiving any touch events. Even a UIAnimationOptionAllowUserInteraction did not help.
So I replaced the delayed animation with a timed call which makes the code even a little for readable. This is how it looks now.
- (void)showError:(NSString *)message {
[lblError setText:message];
[UIView animateWithDuration:0.5
animations:^(void) {
CGRect frame = lblError.frame;
frame.size.width = self.view.bounds.size.width;
frame.origin.y = 0.1;
lblError.frame = frame;
}
completion:^(BOOL finished) {
if (finished) {
[_moveOutTimer invalidate];
_moveOutTimer = nil;
_moveOutTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(dismissError:) userInfo:nil repeats:NO];
}
}];
}
- (void)dismissError:(UIGestureRecognizer *)sender {
[_moveOutTimer invalidate];
[UIView animateWithDuration:0.3
animations:^(void) {
CGRect frame = lblError.frame;
frame.origin.y = -40.0;
lblError.frame = frame;
}
completion:^(BOOL finished) {}];
}