私は次のコードを持っています:
[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
を使用しているにもかかわらず、アニメーション中にボタンがタッチに反応しないことです。これは少し奇妙です。
多分これはコアアニメーションでうまくいくのでしょうか?もしそうなら、どうすればいいですか?
ボタンのタッチ可能な部分は、アニメーション化されているときにボタンの表示フレームと一致しません。
内部的には、ボタンのフレームはアニメーションの最終的な値に設定されます。この領域をタップできることがわかるはずです。これでうまくいきます。
移動するボタンを押すには、ボタンの.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;
}
}
}
私の場合、button.alpha = 0
、オプションとしてUIViewAnimationOptionAllowUserInteraction
を設定しても、ボタンの相互作用が機能しなくなります。
アニメーションを定義するかどうかにかかわらず、ビューのプロパティはビューのレイヤーにすぐに適用されます。このため、view.alpha=0
、view
を完全に非表示にします。
簡単、単純にalpha=0.1
(あるいは 0.05
)
UIView.animate(withDuration: 2,
delay: 0,
options: [.allowUserInteraction, .overrideInheritedOptions, .curveEaseOut, .repeat, .autoreverse],
animations: {
self.button.layer.opacity = 0.01 // 0.0 will make the button unavailable to touch
})
オプションの順序は重要です。最初にUIViewAnimationOptionAllowUserInteraction
を配置してから、他のオプションを追加する必要があります。
Swift 3使用:.allowUserInteraction
私は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;
}
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
}
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.
}
}
Swift 3. viewdidloadの上部にスーパービューを作成します
let 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
}
}
Swiftバージョン: '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)
}
}
}
魅力のように働く
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 答えも正しいけど
画面には4つのボタンがあり、左、右、下、上へのナビゲーションとして機能します。私は@ nahung89の回答からシンプルなハックを使用し、補完を追加して、必要な効果を最大限に引き出しました。これがコードです:
すべてのボタンをViewControllerのOutletコレクションに接続しました
@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 }
}