(Swiftを数日前に使い始めたばかりで、プログラミングに比較的慣れていないので、しばらくお待ちください。)画面にランダムなブロックを表示させようとしているので、ユーザーはブロックを作成することはできましたが、実際にタップ可能にする方法がわかりません。誰かが私を助けてくれませんか?これが今のところ私のコードです:
func createBlock(){
let imageName = "block.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: xPosition, y: -50, width: size, height: size)
self.view.addSubview(imageView)
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
imageView.backgroundColor = UIColor.redColor()
imageView.frame = CGRect(x: self.xPosition, y: 590, width: self.size, height: self.size)
}, completion: { animationFinished in
imageView.removeFromSuperview()
})
}
編集:これは私が試している新しいコードです:
func createBlock(){
let imageName = "block.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: xPosition, y: -50, width: size, height: size)
self.view.addSubview(imageView)
imageView.userInteractionEnabled = true
let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("imageTapped"))
imageView.addGestureRecognizer(tapRecognizer)
func imageTapped(gestureRecognizer: UITapGestureRecognizer) {
let tappedImageView = gestureRecognizer.view!
tappedImageView.removeFromSuperview()
score += 10
}
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
imageView.backgroundColor = UIColor.redColor()
imageView.frame = CGRect(x: self.xPosition, y: 590, width: self.size, height: self.size)
}, completion: { animationFinished in
imageView.removeFromSuperview()
})
}
ビューを作成したら、そのuserInteractionEnabledプロパティをtrueに設定する必要があります。次に、それにジェスチャーを添付する必要があります。
imageView.userInteractionEnabled = true
//now you need a tap gesture recognizer
//note that target and action point to what happens when the action is recognized.
let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("imageTapped:"))
//Add the recognizer to your view.
imageView.addGestureRecognizer(tapRecognizer)
ここでも関数が必要です。この場合はimageTapped:で、ジェスチャーが認識されたときにアクションが発生します。認識されたジェスチャーは引数として送信され、ジェスチャービューのプロパティからどのimageViewがタップされたかを確認できます。
func imageTapped(gestureRecognizer: UITapGestureRecognizer) {
//tappedImageView will be the image view that was tapped.
//dismiss it, animate it off screen, whatever.
let tappedImageView = gestureRecognizer.view!
}
Swift 3.0:
imvEditName.isUserInteractionEnabled = true
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
imvEditName.addGestureRecognizer(tapRecognizer)
そしてターゲットメソッド:
func imageTapped(sender: UIImageView) {
print("image tapped")
}
私の以前の答えは、タップレコグナイザをUIImageViewに追加することについてはまだ正確ですが、アニメーション化しているビューの目的には十分ではありません。実際にゲームを作成している場合、SpriteKitは文字通りこれに合わせて作成されているので、調べたくなるでしょう。ただし、これは通常のUIKitで実現できます。私は2つのアプローチをテストしましたが、どちらも機能します。
両方のアプローチは、シミュレーターよりも実際のデバイスではるかにうまく機能しました
アプローチ1、シンプルですが少し正確ではありませんテストでは10分の1秒遅くなります。
UIImageViewにタップジェスチャを追加する代わりに、ジェスチャをスーパービューに追加します。配列プロパティにブロックへの参照を保持し、ブロックがタップによってインターセプトされているかどうかを確認します。
class ViewController: UIViewController {
let size = CGFloat(40)
let xPosition = CGFloat(14)
let options = UIViewAnimationOptions.Autoreverse
var blocks = [UIImageView]()
override func viewDidLoad() {
super.viewDidLoad()
// Adding recognizer to the whole view.
let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("screenTapped:"))
view.addGestureRecognizer(tapRecognizer)
blocks.append(createBlock())
}
//changed to return the created block so it can be stored in an array.
func createBlock() -> UIImageView {
let imageName = "block.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: xPosition, y: -40, width: size, height: size)
self.view.addSubview(imageView)
UIView.animateWithDuration(2, delay: 0.0, options: options, animations: {
imageView.backgroundColor = UIColor.redColor()
imageView.frame = CGRect(x: self.xPosition, y: 590, width: self.size, height: self.size)
}, completion: { animationFinished in
imageView.removeFromSuperview()
self.blocks.append(self.createBlock())
})
return imageView
}
func screenTapped(gestureRecognizer: UITapGestureRecognizer) {
let tapLocation = gestureRecognizer.locationInView(view)
//This is to keep track of the blocks to remove from the array.
//If you remove them as you iterate the array, and you have more than
//one block to remove, you may end up removing the wrong block
//or with an index out of bounds.
var removeBlocks = [Int]()
for (index, block) in enumerate(blocks) {
//this is the frame of the view as we see it on screen.
//unfortunately block.frame is not where we see it making a recognizer
//on the block itself not work.
if block.layer.presentationLayer().frame.contains(tapLocation) {
//Then this block was clicked.
block.removeFromSuperview()
removeBlocks.append(index)
}
}
//get the indexes ro remove backwards so we are removing from
//back to front.
for index in removeBlocks.reverse() {
blocks.removeAtIndex(index)
}
}
}
アプローチ2、最高のパフォーマンスSpriteKit以外
アプローチ2では、UIViewをサブクラス化し、メインビューをUIViewではなくそれに設定します。 1つのメソッドをオーバーライドするだけで済みます。便宜上、ブロック配列をビューに格納しています。
最初にTouchView。
import UIKit
class TouchView: UIView {
var blocks = [UIImageView]()
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
// ignoring multiple touches for now
if touches.count == 1 {
if let touch = touches.first as? UITouch {
let touchLocation = touch.locationInView(self)
//This is to keep track of the blocks to remove from the array.
//If you remove them as you iterate the array, and you have more than
//one block to remove, you may end up removing the wrong block
//or with an index out of bounds.
var removeBlocks = [Int]()
for (index, block) in enumerate(blocks) {
//this is the frame of the view as we see it on screen.
//unfortunately block.frame is not where we see it making a recognizer
//on the block itself not work.
if block.layer.presentationLayer().frame.contains(touchLocation) {
//Then this block was clicked.
block.removeFromSuperview()
removeBlocks.append(index)
}
}
//get the indexes ro remove backwards so we are removing from
//back to front.
for index in removeBlocks.reverse() {
blocks.removeAtIndex(index)
}
}
}
}
}
これで、ViewControllerは次のようになります。
import UIKit
class ViewController: UIViewController {
let size = CGFloat(40)
let xPosition = CGFloat(14)
let options = UIViewAnimationOptions.Autoreverse
var blocks = [UIImageView]()
// computed get only property for conveniece of accessing block array
var touchView:TouchView {
get {
return self.view as! TouchView
}
}
override func viewDidLoad() {
super.viewDidLoad()
touchView.blocks.append(createBlock())
// Do any additional setup after loading the view, typically from a nib.
}
func createBlock() -> UIImageView {
let imageName = "block.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: xPosition, y: -40, width: size, height: size)
self.view.addSubview(imageView)
UIView.animateWithDuration(2, delay: 0.0, options: options, animations: {
imageView.backgroundColor = UIColor.redColor()
imageView.frame = CGRect(x: self.xPosition, y: 590, width: self.size, height: self.size)
}, completion: { animationFinished in
imageView.removeFromSuperview()
self.touchView.blocks.append(self.createBlock())
})
return imageView
}
}
私のテストでは、すばやくアニメーション化された「ブロック」を使用しても、これはかなりうまくいくようです。繰り返しますが、本格的なゲームを作成することを計画している場合は、SpriteKitを確認する必要があります。本当に簡単なチュートリアル here があります。承認済みの回答を以前の回答から削除できる場合、移動していないUIImageViewにジェスチャーを追加することだけを目的としているのでない限り、他の人が間違った道をたどらないようにするのに役立ちます。
デフォルトでは、画像表示のユーザー操作は無効になっているため、必ずオフにしてください。
let myImageView = UIImageView()
myImageView.isUserInteractionEnabled = true
UIImageView
を使用する代わりに、Custome UIButton
を使用して、デフォルトのボタン画像を自分のものに置き換えることができます。したがって、UIImageViewごとにUITapGestureRecognizer
を追加する必要はありません。 @JeremyPopeのアプローチは、実際にはこのアプローチよりも効率的です。
処理 UIButton
は非常にシンプルで、そのサブクラスはUIControl
なので、hide
やenabled
などのプロパティがあり、それらを操作できます。あなたが望む方法で。
UIButton
を作成するのと同じように、プログラムでUIImageView
を作成する必要があります。それらを作成する方法はUIImageView
に似ています。詳細は IButtonをプログラムでSwiftで作成 を参照してください。
以下の画像は、カスタムUIButton
の外観です。
さらに情報が必要な場合はコメントを残してください。