UIButton не может быть затронут во время анимации с помощью UIView animateWithDuration
У меня есть следующий код:
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationCurveEaseOut | UIViewAnimationOptionAllowUserInteraction
animations:^{
CGRect r = [btn frame];
r.origin.y -= 40;
[btn setFrame: r];
}
completion:^(BOOL done){
if(done){
[UIView animateWithDuration:0.3
delay:1
options:UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionAllowUserInteraction
animations:^{
CGRect r = [btn frame];
r.origin.y += 40;
[btn setFrame: r];
}
completion:^(BOOL done){if(done) zombiePopping = 0; }];
}
}];
Проблема в том, что кнопка не реагирует на касания во время анимации, хотя я использую UIViewAnimationOptionAllowInteraction
, что для меня немного странно.
Возможно, это больше всего сделать с Core Animation для работы? и если да, то как я могу это сделать?
Ответы
Ответ 1
Прикосновенная часть кнопки не будет совпадать с видимой рамкой кнопки при ее анимировании.
Внутренне рамка кнопки будет установлена на конечное значение из вашей анимации. Вы должны обнаружить, что можете использовать эту область, и это сработает.
Чтобы попасть в движущуюся кнопку, вам нужно выполнить тестирование при нажатии кнопки .layer.presentationLayer
(нужно импортировать среду QuartzCore для этого). Обычно это делается в методах обработки касания в вашем контроллере вида.
Я рад расширить этот ответ, если вам нужно больше.
Вот как вы могли бы реагировать на событие касания, используя уровни тестирования тестирования тестирования. Этот код находится в подклассе контроллера представления, который управляет вашими кнопками. Когда я это сделал, меня интересовал исходный штрих, а не осязание (что обычно бывает при регистрации крана), но принцип тот же.
Не забудьте импортировать среду QuartzCore и добавить ее в свой проект.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
for (UIButton *button in self.buttonsOutletCollection)
{
if ([button.layer.presentationLayer hitTest:touchLocation])
{
// This button was hit whilst moving - do something with it here
break;
}
}
}
Ответ 2
В моем случае я установил superView.alpha = 0
, он останавливает взаимодействие кнопки, хотя я настраиваю UIViewAnimationOptionAllowUserInteraction
.
Решение? Просто уменьшите alpha
до 0,1 вместо 0
[UIView animateWithDuration:durationTime delay:0 options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionOverrideInheritedOptions | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations: ^{
superView.alpha = 0.1; // 0.0 will make the button unavailable to touch
} completion:nil];
Ответ 3
Порядок параметров - это вопрос, сначала нужно поместить UIViewAnimationOptionAllowUserInteraction
, а затем добавить другие параметры.
В Swift 3 используйте: .allowUserInteraction
Ответ 4
Я достиг этого, используя NSTimer:
Во-первых, выполните анимацию запуска, затем вы должны запустить таймер, это демонстрационный код:
-(void)fun···
{
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationCurveEaseOut | UIViewAnimationOptionAllowUserInteraction
animations:^{
CGRect r = [btn frame];
r.origin.y -= 40;
[btn setFrame: r];
}
completion:^(BOOL done){}];
then , you should start an timer,example:
//start timer
if (timer != nil)
{
[timer invalidate];
timer = nil;
}
[self performSelector:@selector(closeButton) withObject:nil afterDelay:0];
}
- (void)closeButton
{
if (timer != nil)
{
return;
}
//start timer
timer = [NSTimer scheduledTimerWithTimeInterval:1.5f target:self selector:@selector(timerEvent) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)timerEvent
{
[UIView animateWithDuration:0.3
delay:1
options:UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionAllowUserInteraction
animations:^{
CGRect r = [btn frame];
r.origin.y += 40;
[btn setFrame: r];
}
completion:^(BOOL done){if(done) zombiePopping = 0; }];
[timer invalidate];
timer = nil;
}
Ответ 5
Тот же ответ в Swift (2.0), для ленивого. При необходимости замените петлей и розеткой:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.locationInView(self.view)
if self.button.layer.presentationLayer()!.hitTest(touchLocation) != nil {
action() // Your action, preferably the original button action.
}
}
Ответ 6
Swift 3.0
Создайте супервизор сверху в viewdidload
let superView = UIView(frame: view.frame)
superView.isUserInteractionEnabled = true
superView.backgroundColor = UIColor.clear
superView.alpha = 0.1
view.addSubview(superView)
теперь реализует touchhesbagan, как это
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = (touches as NSSet).anyObject() as? UITouch else {
return
}
let touchLocation = touch.location(in: self.view)
if btnone.layer.presentation()?.hitTest(touchLocation) != nil {
print("1") // Do stuff for button
}
if btntwo.layer.presentation()?.hitTest(touchLocation) != nil {
print("2") // Do stuff
}
if btnthree.layer.presentation()?.hitTest(touchLocation) != nil {
print(3) // Do stuff
}
if btnfour.layer.presentation()?.hitTest(touchLocation) != nil {
print(4) // Do stuff
}
}
Ответ 7
Если у вас есть подкласс UIButton самым простым способом является переопределение Трассировка как
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
return self.layer.presentation()?.hitTest(self.convert(point, to: superview)).flatMap { _ in return self } ?? nil
}
Ответ 8
Быстрая версия:
"999" - значение тега, используемое для идентификации целевого представления.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = (touch?.locationInView(self.rootView))!
for view in self.view.subviews {
if let layer = view.layer.presentationLayer()?.hitTest(touchLocation) where view.tag == 999 {
// Here view is the tapped view
print(view)
}
}
}
Ответ 9
работает как шарм
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
if bounds.contains(point) && !hidden && userInteractionEnabled && enabled {
return self
}
return super.hitTest(point, withEvent: event)
}
Хотя этот ответ также верен
Ответ 10
У меня было 4 кнопки на экране, которые должны были выполнять навигацию влево, вправо, вниз и вверх. Я использовал простой ответ от @nahung89 и добавил завершение, чтобы получить полный эффект, который мне нужен.
Вот код:
Подключил все кнопки к коллекции Outlet в ViewController
@IBOutlet var navigationButtons: [UIButton]!
Добавил эту функцию в viewDidAppear:
navigationButtons.forEach { button in
UIView.animate(withDuration: 0.5,
delay: 5,
options: [.curveLinear, .allowUserInteraction],
animations: {
button.alpha = 0.1
}) { _ in button.alpha = 0 }
}