LoginSignup
1
1

More than 3 years have passed since last update.

遷移しよー!with CircleMenu

Last updated at Posted at 2020-04-06

こんにちは!!!

手元からPCが消え去って1ヶ月。やっっっとパソコンが買えたので投稿。

今回はCircleMenuというオシャレなライブラリがあることを(今更)知ったのでこのアニメーションを利用してふわっと遷移しようという趣旨。

別にCircleMenuのオシャレなアニメーションに乗っかって遷移してるだけのハリボテです。

ブランクあるんや、、リハビリみたいなもんや、、

成果物

なんかgifだと残念な感じに円が残るけど実際には普通にスゥーっ!っと消えます!!!(血眼)

Unknown

コード


import UIKit
import CircleMenu

class ViewController: UIViewController {

    let menuButton: CircleMenu = {
        let view = CircleMenu(frame: CGRect(x: UIScreen.main.bounds.width / 2 - 25, y: UIScreen.main.bounds.height / 2 - 25, width: 50, height: 50), normalIcon: "menu", selectedIcon: "error", buttonsCount: 5, duration: 0.3, distance: 150)
        view.backgroundColor = .green
        view.layer.cornerRadius = view.frame.size.width / 2.0
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        menuButton.delegate = self

        self.view.addSubview(menuButton)

    }
}

extension ViewController: CircleMenuDelegate {
    func circleMenu(_ circleMenu: CircleMenu, buttonDidSelected button: UIButton, atIndex: Int) {
        var vc: UIViewController?
        switch atIndex {
        case 0:
            vc = NextViewController()
        case 1:
            vc = NextViewController()
        case 2:
            vc = NextViewController()
        case 3:
            vc = NextViewController()
        case 4:
            vc = NextViewController()
        default:
            print("no vc")
        }
        guard let VC = vc else { return }
        VC.modalPresentationStyle = .overCurrentContext
        self.present(VC, animated: false, completion: nil)
    }
}



import UIKit

class NextViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .red

        let tap = UITapGestureRecognizer(target: self, action: #selector(dismissAction))
        self.view.addGestureRecognizer(tap)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.view.alpha = 0
        UIView.animate(withDuration: 0.5) {
            self.view.alpha = 1
        }

    }

    @objc func dismissAction() {
        self.dismiss(animated: false, completion: nil)
    }
}

解説

import らへん


import CircleMenu

今回のメインであるライブラリのインポートですね。githubではbuildの項目がfailingになってましたけど普通に使えますね。なんででしょ。余裕があったら読みたいものですな。

view らへん


let menuButton: CircleMenu = {
        let view = CircleMenu(frame: CGRect(x: UIScreen.main.bounds.width / 2 - 25, y: UIScreen.main.bounds.height / 2 - 25, width: 50, height: 50), normalIcon: "menu", selectedIcon: "error", buttonsCount: 5, duration: 0.3, distance: 150)
        view.backgroundColor = .green
        view.layer.cornerRadius = view.frame.size.width / 2.0
        return view
    }()

viewの宣言をクロージャで宣言してるんや。これは宣言してるviewが使われるときに一度だけ初期化されるヨ。
この形をとることでひとまとまりになってるし、viewDidload内が汚れないから見やすいね!
あとはあんまり良くないかもしれないけど、中で宣言するインスタンス名をviewにすることで他のviewを宣言するときコピペがとっても楽になるよ!笑

delegate らへん

delegateは移譲って言って、こいつがいるときは処理を他人任せにしてる証拠だ!!(そして大抵僕に丸投げされてるんだ。 これは私情。)

もし君が仕事を任されたとき自分なりのやり方でやるよね???(異論ナシ。)
delegateも任された側のやり方で処理することができるから便利なんだ。
delegateと一緒だね!!!!(歓喜)

あと、通知の役割も大きいけど今回は使ってないからパス _ (:3 」)_


menuButton.delegate = self

このコードからは、menuButton先輩が、self、つまり私(ViewController)に仕事をぶん投げるということを高らかに宣言しているのだ。(やめてくれよ)

逆に言えば、このように高らかに宣言してくれないとdelegateできない。つまり仕事を任せられていないので、

「お前これ頼んだよな?(威圧)」
「は?寝ぼけてんのか?(えっ、??いや、頼まれてないですよ、、?)」

なんてことが起こる。(特に良く僕のコード内で。うっかり。照)

Extension らへん

swiftに限らず継承はとても便利だ。
ここでは便利なextensionの継承の、書き方について触れておこうと思う。


extension ViewController: CircleMenuDelegate {
  //省略
}

プロトコルを継承することで決まった形のクラスや構造体を作れるし、うまくかければ具象への依存かなり減らせてそれだけでとても変更しやすくなる。

しかし、ViewControllerの定義でついつい一度に継承するものを羅列してしまいがちだ。


class ViewController: UIViewController, UITableViewDelegate, CircleMenuDelegate {
  //省略
}

これではどの関数がどのクラス・プロトコルから継承してきたものかかなり分かりづらいし、区切りのないコードが一気に肥大してしまう。

そのため、今回のように一つ一つ優しくextensionしてあげよう。これだけで見通しが良くなるし、「あっ、こいつイラネ!w」となった時もどこを消せばいいかすぐわかる。
追加もしやすい。

書き方をちょっと変えるだけでいいことづくめなのだ。

guard らへん

guardとif。ifが便利すぎでわざわざguardを使う意味がわからないという方もいるのではなかろうか。

ペーペーの僕がいうのもなんだが、僕なんかよりずっといいコードを書いている人でもguardを使わずifを使っていることがあるから頭に「?」が浮かぶ。

こんなに良い関数は他にないんじゃないか? それは無いか。
(ちなみに僕的、昨今の推しはmapです。)


guard let VC = vc else { return }

guardはなんと言っても一眼で役割が分かるのがいい。

  • guardを使う場面はreturnされて本土(呼び出し元)に返されるか、fatalErrorでも呼ばれてアプリがクラッシュするかくらいだ。

「いやそれifでもできるやーん?」

そうなんだけど、あえてguardを使うことで自分や他の人がそこを読む時、一瞬で意図がわかる。

素敵だ。(イケボ)

そしてしばしばletとセットでオプショナル回避に用いられる。

let optional: Int? = 3

guard let Nakami = optional else { return }
// optional : Optional<3>
// Nakami : 3

このように中身を簡単かつ安全に、そして中身がない時は本土に返還するスグレモノなのだ。

lifecycle と animation らへん

animationを行うことで今回はそれっぽーく仕上げでいる。
透明度を表すalphaの値を事前に0にして完全に透明にしておく。

viewWillAppearが呼ばれたらアニメーションを行って、alphaを1すればふわっと素敵っぽい遷移が実現できた。(急に完了する。)


override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.view.alpha = 0
        UIView.animate(withDuration: 0.5) {
            self.view.alpha = 1
        }
    }

ここで大事なのでviewWillAppearで呼ぶことだ。

これより前のviewDidloadで呼ぶと、そもそもアニメーションが行われない。
しかもvcを再利用していればviewDidloadは一回しか呼ばれない。

この後のviewWillLayoutSubviewsは名前の通りサブビューの描画準備のためにあるので役割として明らかにおかしい。

ここら辺に関してはもっと良い書き方があるんだろうなぁという感覚なので勉強します。

ここまで読んでいただきありがとうございました。

キーボードは配列が前のは海外仕様だったから逆に日本仕様に慣れない、、

書くつもりなかったのにPCきたの嬉しすぎて夢中になって書いてしまった、、
明日仕事なのに。もう寝なきゃ。

おやすみなさい

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1