質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.02%

【Swift】タップして画面に波紋

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 866

sakuradaiya

score 9

 前提・実現したいこと

Swift勉強中です。
今回はタップした場所から波紋を実現したいと思いましたが上手くいきません。

参考にしたサイト:http://tech-gym.com/2018/02/未分類/2602.html

 発生している問題・エラーメッセージ

Value of type 'ViewController' has no member 'contentView'; did you mean 'tapContentView'?
Replace 'contentView' with 'tapContentView'

 該当のソースコード

import UIKit

extension UIView {
    func 波紋(touch: UITapGestureRecognizer) {

        // ①: タップされた場所にlayerを置き、半径200の円を描画
        let location = touch.location(in: self)
        let layer = CAShapeLayer.init()
        self.layer.addSublayer(layer)
        layer.frame = CGRect.init(x: location.x, y: location.y, width: 100, height: 100)
        layer.position = CGPoint.init(x: location.x, y: location.y)
        layer.contents = {
            let size: CGFloat = 200.0
            UIGraphicsBeginImageContext(CGSize.init(width: size, height: size))
            let context = UIGraphicsGetCurrentContext()!
            context.saveGState()
            context.setFillColor(UIColor.clear.cgColor)
            context.fill(self.frame)
            let r = CGFloat.init(size/2-10)
            let center = CGPoint.init(x: size/2, y: size/2)
            let path : CGMutablePath = CGMutablePath()
            path.addArc(center: center, radius: r, startAngle: 0, endAngle: CGFloat(Double.pi*2), clockwise: false)
            context.addPath(path)
            context.setFillColor(UIColor.lightGray.cgColor)
            context.setStrokeColor(UIColor.lightGray.cgColor)
            context.drawPath(using: .fillStroke)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            context.restoreGState()
            return image!.cgImage
        }()

        // ②: 円を拡大しつつ透明化するAnimationを用意
        let animationGroup: CAAnimationGroup = {
            let animation: CABasicAnimation = {
                let animation = CABasicAnimation(keyPath: "transform.scale")
                animation.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeOut)
                animation.duration = 0.5
                animation.isRemovedOnCompletion = false
                animation.fillMode = CAMediaTimingFillMode.forwards
                animation.fromValue = NSNumber(value: 0.5)
                animation.toValue = NSNumber(value: 5.0)
                return animation
            }()

            let animation2: CABasicAnimation = {
                let animation = CABasicAnimation(keyPath: "opacity")
                animation.duration = 0.5
                animation.isRemovedOnCompletion = false
                animation.fillMode = CAMediaTimingFillMode.forwards
                animation.fromValue = NSNumber(value: 0.5)
                animation.toValue = NSNumber(value: 0.0)
                return animation
            }()

            let group = CAAnimationGroup()
            group.beginTime = CACurrentMediaTime()
            group.animations = [animation, animation2]
            group.isRemovedOnCompletion = false
            group.fillMode = CAMediaTimingFillMode.backwards
            return group
        }()

        // ③: layerにAnimationを適用
        CATransaction.setAnimationDuration(5.0)
        CATransaction.setCompletionBlock({
            layer.removeFromSuperlayer()
        })
        CATransaction.begin()
        layer.add(animationGroup, forKey: nil)
        layer.opacity = 0.0
        CATransaction.commit()
    }
}

class ViewController: UIViewController {
    override func awakeFromNib() {
        super.awakeFromNib()

        let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(self.tapContentView(touch:)))
        self.contentView.addGestureRecognizer(tapGesture)
    }

    @objc func tapContentView(touch: UITapGestureRecognizer) {

        self.contentView.波紋(touch: touch)
    }



}

 試したこと

storyboardでの作業は特に行なっていません。。必要でしょうか?
→成功したコードには必要ありませんでした。

 成功したソースコード添付

import UIKit

extension UIView {
    func 波紋(touch: UITapGestureRecognizer) {

        // ①: タップされた場所にlayerを置き、半径200の円を描画
        let location = touch.location(in: self)
        let layer = CAShapeLayer.init()
        self.layer.addSublayer(layer)
        layer.frame = CGRect.init(x: location.x, y: location.y, width: 100, height: 100)
        layer.position = CGPoint.init(x: location.x, y: location.y)
        layer.contents = {
            let size: CGFloat = 200.0
            UIGraphicsBeginImageContext(CGSize.init(width: size, height: size))
            let context = UIGraphicsGetCurrentContext()!
            context.saveGState()
            context.setFillColor(UIColor.clear.cgColor)
            context.fill(self.frame)
            let r = CGFloat.init(size/2-10)
            let center = CGPoint.init(x: size/2, y: size/2)
            let path : CGMutablePath = CGMutablePath()
            path.addArc(center: center, radius: r, startAngle: 0, endAngle: CGFloat(Double.pi*2), clockwise: false)
            context.addPath(path)
            context.setFillColor(UIColor.lightGray.cgColor)
            context.setStrokeColor(UIColor.lightGray.cgColor)
            context.drawPath(using: .fillStroke)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            context.restoreGState()
            return image!.cgImage
        }()

        // ②: 円を拡大しつつ透明化するAnimationを用意
        let animationGroup: CAAnimationGroup = {
            let animation: CABasicAnimation = {
                let animation = CABasicAnimation(keyPath: "transform.scale")
                animation.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeOut)
                animation.duration = 0.5
                animation.isRemovedOnCompletion = false
                animation.fillMode = CAMediaTimingFillMode.forwards
                animation.fromValue = NSNumber(value: 0.5)
                animation.toValue = NSNumber(value: 5.0)
                return animation
            }()

            let animation2: CABasicAnimation = {
                let animation = CABasicAnimation(keyPath: "opacity")
                animation.duration = 0.5
                animation.isRemovedOnCompletion = false
                animation.fillMode = CAMediaTimingFillMode.forwards
                animation.fromValue = NSNumber(value: 0.5)
                animation.toValue = NSNumber(value: 0.0)
                return animation
            }()

            let group = CAAnimationGroup()
            group.beginTime = CACurrentMediaTime()
            group.animations = [animation, animation2]
            group.isRemovedOnCompletion = false
            group.fillMode = CAMediaTimingFillMode.backwards
            return group
        }()

        // ③: layerにAnimationを適用
        CATransaction.setAnimationDuration(5.0)
        CATransaction.setCompletionBlock({
            layer.removeFromSuperlayer()
        })
        CATransaction.begin()
        layer.add(animationGroup, forKey: nil)
        layer.opacity = 0.0
        CATransaction.commit()
    }
}

class ViewController: UIViewController {
    override func awakeFromNib() {
        super.awakeFromNib()

        let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(self.tapContentView(touch:)))
        self.View.addGestureRecognizer(tapGesture)
    }

    @objc func tapContentView(touch: UITapGestureRecognizer) {

        self.View.波紋(touch: touch)
    }



}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    2018/10/15 09:08

    複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

  • sakuradaiya

    2018/10/15 23:52

    大変申し訳ございません。おっしゃる通り、最初はサイトからのコピペにて「出来たらいいな」と軽い気持ちから入ってやっていました。ただ、丸投げしているつもりはありません。調べても調べても分からず、最後の希望にすがる気持ちで投稿しています。純粋に理解できておらずに、質問内容に到達していないレベルなのかもしれません。不快な思いをされている方、大変申し訳ございませんでした。

    キャンセル

回答 2

checkベストアンサー

+2

ViewControllerにcontentViewというメンバーが無い、という意味でエラーが出ています。

試していませんが、viewに変えるだけで期待する動きになるのではないかと思われます。

class ViewController: UIViewController {
    override func awakeFromNib() {
        super.awakeFromNib()

        let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(self.tapContentView(touch:)))
        self.view.addGestureRecognizer(tapGesture)
    }

    @objc func tapContentView(touch: UITapGestureRecognizer) {

        self.view.波紋(touch: touch)
    }
}

追記:2018/10/16
手元で試しましたがうまく動いているように見えます。
イメージ説明

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/15 22:57

    ご回答いただき、有難うございます。
    ただviewに変えてみましたが上手くいきませんでした。
    ご回答いただいたのに活かしきれず申し訳ないです。

    キャンセル

  • 2018/10/16 09:19

    上手くいかないとはどういう意味でしょうか?

    キャンセル

  • 2018/10/16 23:40

    返信有難うございます。
    再度、やってみたら出来ました!
    昨日はなぜ出来なかったのか。。ベストアンサーつけさせて頂きます!
    今後もお時間ありましたら、よろしくお願いします。

    キャンセル

+1

「使い方」に書かれているコードはUITableViewCellUICollectionViewCellのカスタムクラスに実装して下さい。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/15 23:43

    ご回答いただき有難うございます。
    UITableViewCellをストーリーボードで実装し、ViewController.swiftから分けてUITableViewCell.swiftに使い方に書かれているコードを記載しましたが、上手くいきませんでした。fuzzballさんが言われてる
    「カスタムクラスに実装」とは上記の事ですよね?
    やり方はfuzzballさんの方法だと思いますので、さらに調べてからやってみます。

    キャンセル

  • 2018/10/16 09:20 編集

    質問文にも書かれていますが「上手くいきませんでした」では、こちらは何も分からないのですよ。
    何を調べたか、何をやったか、その結果どうなったか、をこちらに伝えて下さい。

    試したコードは質問に追記(もしくは編集)して下さい。

    キャンセル

  • 2018/10/16 23:37

    返信有難うございます。
    上手くいかないじゃ伝わらないですよね。。質問に慣れてないので今後注意していきます。
    今回は追記しているやり方で解決しました!
    今後もどんどん質問するので、お時間ありましたらよろしくお願いします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る