タッチする毎に画像を生成。生成後コントロール可能。(UIImageView, swift 1.2, viewDidLayoutSubviews)
手から沢山のトランプが出現するマジックをアプリケーションで表現したくなりました。 Githubは以下です。
自分ポイント1
プロジェクトを確認頂くとわかると思うのですが、imageを指定していないviewを予め用意しています。このviewをタッチ時にカード画像へ変化させようという算段です。
class ViewController: UIViewController { @IBOutlet var imageCurrectCardView: UIImageView! //Magic開始範囲 & 生成中のカードView ... }
自分ポイント2
特定範囲をタッチ時にカードを生成します。ポイント1でも述べた通り、imageを指定していないviewを予め用意して、その範囲をタッチしたら、そのviewをカード画像に変化させてます。後ほど使い回すために、cardViewを見える化する関数displayImageCardViewWithPoint
も作成。
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) { let touch = touches.first as! UITouch touchPoint = touch.locationInView(self.view) //タッチ座標を取得 let tag = touch.view.tag startTouchPoint = touchPoint if tag == 999 { //imageCurrectCardViewをタッチした場合のみ以下の処理を行う let size = CGSizeMake(100, 100) //サイズ格納用変数size作成 imageCurrectCardView.contentMode = UIViewContentMode.ScaleAspectFit //画像の表示方法を設定 displayImageCardViewWithPoint( touchPoint!, size: size, imgName: "card.png", imageView: imageCurrectCardView, isControlImageCardView: true) //cardViewを見える化関数を実行 } } //cardViewを見える化する関数 func displayImageCardViewWithPoint(point: CGPoint, size: CGSize, imgName: String, imageView: UIImageView, isControlImageCardView :Bool) { //, imgName: String, contentMode: String, isControlImageCurrectCardView :Bool imageView.frame.size = size //sizeをカードviewに適応 imageView.center = point //pointをviewに適応 imageView.image = UIImage(named: imgName) //imgName画像を表示 isControlImageCurrectCardView = isControlImageCardView //imageCurrectCardViewが操作中 or not self.view.bringSubviewToFront(imageView) //imageView最前面に }
自分ポイント3
viewDidLayoutSubviewsを作成し、内部でごにょごにょしてます。これをしとかないと1回目のタッチ時の画像の大きさと座標が意図したものではないものなります。Auto LayoutをDisableにすると、この処理は必要ありませんが、今後の勉強のためにAuto Layout Enable状態で実装してみました。
AutoLayoutがEnableではview.frameの決定はviewDidLayoutSubviewsのタイミングで行われる(らしい)。view更新時、touchesBeganの後に呼ばれているっぽいです。
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if isControlImageCurrectCardView != false { //imageCurrectCardViewの操作中でなければ var size = CGSizeMake(100, 100) //サイズ格納用変数size作成 imageCurrectCardView.frame.size = size //sizeをカードviewに適応 imageCurrectCardView.center = touchPoint! //タッチ座標をカードviewに適応 } else { //Do nothing } }
自分ポイント4
touchesEnded時、カードを生成したviewを初期状態に戻します。見えているカードviewについては、内部的には新たに作成します。複数の画像が生成されることを考慮して配列にUIImageViewを格納。タグ付けを行い、後ほどコントロールすることを考慮済。
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) { let touch = touches.first as! UITouch touchPoint = touch.locationInView(self.view) //タッチ座標を取得 let tag = touch.view.tag if tag == 999 { //imageCurrectCardViewをタッチした場合のみ以下の処理を行う //1. imageCurrectCardViewを初期状態に戻す let initialPoint = CGPointMake(187.5, 334.0) //center座標格納変数point作成 (初期値に戻す) let initialSize = CGSizeMake(157, 210) //サイズ格納用変数size作成 (初期値に戻す) imageCurrectCardView.contentMode = UIViewContentMode.ScaleToFill //contentModeを変更 displayImageCardViewWithPoint( initialPoint, size: initialSize, imgName: "", imageView: imageCurrectCardView, isControlImageCardView: false) //cardViewを見える化(コレは厳密に言うと見えない化...)関数を実行 //2. imageCurrectCardViewをimageOldCardViewArrayに格納する(ようなイメージの処理) var img = UIImage(named: "") imageOldCardViewArray.append(UIImageView(image:img)) //imageOldCardViewArrayに要素を追加 let count = imageOldCardViewArray.count //imageOldCardViewArrayの数を保存 let size = CGSizeMake(100, 100) //サイズ格納用変数size作成 imageOldCardViewArray[count - 1].contentMode = UIViewContentMode.ScaleAspectFit //contentModeを変更 imageOldCardViewArray[count - 1].tag = count //配列番号でタグ付け displayImageCardViewWithPoint( touchPoint!, size: size, imgName: "card.png", imageView: imageOldCardViewArray[count - 1], isControlImageCardView: false) //cardViewを見える化関数を実行 self.view.addSubview(imageOldCardViewArray[count - 1]) //画像生成 imageOldCardViewArray[count - 1].userInteractionEnabled = true //タッチ操作を有効に } else { //Do nothing } }
自分ポイント5
生成したカードは全て後からでもコントロール可能にしています。
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) { let touch = touches.first as! UITouch touchPoint = touch.locationInView(self.view) //タッチ座標を取得 let tag = touch.view.tag startTouchPoint = touchPoint if tag == 999 { .... } else if tag > 0 { startImagePoint = imageOldCardViewArray[tag - 1].center //タッチしたカードのスタート位置を保存 self.view.bringSubviewToFront(imageOldCardViewArray[tag - 1]) //imageOldCardViewArrayを最前面に } else { //Do nothing } }
自分ポイント6
ボタンを押したら、カード画像と配列を消去します。画像の消去にはremoveFromSuperview
, 配列の削除にはremoveAll()
を使用します。今回はアニメーションを使用して画像を見えなくしたのでremoveFromSuperview
は使用していません。何故使用しなくてOKなのかは、はっきり言って理解していません...。
@IBAction func pressClean(sender: AnyObject) { for (index, val) in enumerate(imageOldCardViewArray) { UIView.animateWithDuration(2, animations: { () -> Void in self.imageOldCardViewArray[index].layer.opacity = 0.0 }) //self.imageOldCardViewArray[index].removeFromSuperview() } imageOldCardViewArray.removeAll() }
自分の中では、もっと簡単に作成できると思ったのですが、かなり時間がかかりました。(3日くらい...)
もっとおしゃれに書けるようになりたいなぁ...。