我有以下代码:
[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来完成这项工作?如果是的话,我该怎么做呢?
答案 0 :(得分:52)
按钮的可触摸部分在设置动画时与按钮的可见帧不一致。
在内部,按钮的框架将设置为动画的最终值。你会发现你可以点击这个区域,它会起作用。
要点击移动按钮,您需要对按钮的.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;
}
}
}
答案 1 :(得分:49)
就我而言,我设置了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];
答案 2 :(得分:27)
选项的顺序很重要,您必须先放置UIViewAnimationOptionAllowUserInteraction
,然后添加其他选项。
在Swift 3中使用:.allowUserInteraction
答案 3 :(得分:1)
我使用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;
}
答案 4 :(得分:1)
同样的答案在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.
}
}
答案 5 :(得分:1)
Swift 3.0 在viewdidload
中创建一个superviewlet superView = UIView(frame: view.frame)
superView.isUserInteractionEnabled = true
superView.backgroundColor = UIColor.clear
superView.alpha = 0.1
view.addSubview(superView)
现在像这样实施touchesbagan
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
}
}
答案 6 :(得分:0)
Swift版本: &#39; 999&#39;是用于标识目标视图的标记值。
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)
}
}
}
答案 7 :(得分:0)
就像一个魅力
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
if bounds.contains(point) && !hidden && userInteractionEnabled && enabled {
return self
}
return super.hitTest(point, withEvent: event)
}
虽然this回答也是正确的
答案 8 :(得分:0)
如果您有UIButton的子类,最简单的方法是通过覆盖hitTest之类的方式
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
}
答案 9 :(得分:0)
我在屏幕上有4个按钮,这些按钮应该用作向左,向右,向下和向上导航。我使用来自@ nahung89答案的简单技巧,并添加了完成功能,以获取所需的完整效果。 这是代码:
将所有按钮连接到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 }
}