見出し画像

iOS開発初心者だったあの頃の自分にアドバイスしたいこと UI編

概要

ふと学生時代に作ったプロジェクトを見返していて、なんとも言えない気持ちになったので、Swift を始めたばかりで、独学+手探りで勉強していたあの頃の自分に「こうしたほうがいいよ」と思ったことをまとめたいと思います。

その中でも今回は UI に関連することについてです。

Swift を始めたばかりの初心者の方にも役に立つ内容だと思います。
不明点などがあれば気軽に質問していただけると嬉しいです🙇‍♂️

main.storyboard に全画面作るのはやめよう

まずはこちらをご覧ください。

スクリーンショット 2020-07-21 11.00.17

これは僕が学生の頃に作ったアプリの main.storyboard ですが、
アプリ内の全ての画面が一つの Storyboard で管理されています。

画面数が少ないアプリならこの管理の仕方でも問題ないと思いますが、
この方法で管理するといくつかデメリットがあるので実体験を踏まえて紹介します。

■ 画面が増えるにつれて Storyboard を開くのに時間がかかる

タイトル通りで ViewController の数が増えるほど Storyboard が重くなります。

上の画像のプロジェクトでは、全ての画面が重くなった Storyboard にあるので、開きたくても重くてなかなか開けないといった状態になっていました。

■ ViewController の生成が面倒

一つの Storyboard で画面を管理している場合、
ViewController をコードから生成する処理は以下のようになります。

// Storyboard を生成して、そこから Storyboard ID を指定して ViewController を生成
let vc = UIStoryboard(name: "StoryboardName", bundle: nil).instantiateViewController(withIdentifier: "StoryboardID")

コメントにも書いてありますが、
Storyboard をインスタンス化した上で Storyboard ID を指定して ViewController を生成する必要があります。

そのため Storyboard 側で全ての画面に Storyboard ID を設定する必要があるのと、文字リテラルを入れる箇所が2つもあるのでタイプミスの可能性が高くなってしまいます。

コードで ViewController を生成する際には Storyboard ID を確認するために Storyboard を確認しにいって...
と言うふうにいちいち Storyboard を開いて確認する必要がありました。

■ 今ならどうするか?

Storyboard と ViewController は1対1になるようにします。
また、プロジェクト作成時に自動で作られる main.storyboard は削除してしまっても問題ないので削除します。

1対1 になるようにすることで、Storyboard が重くなることが避けられます。他にも Storyboard と ViewController の名前を同じにしてあげることで、簡単に ViewController を生成できる extension が使えるようになります。

この辺は以前 Qiita に記事としてあげたので、よかったらチェックしてください。

【Swift】プロジェクト作成時に生成されるMain.storyboardを削除する

他にも画面ごとに Storyboard を作って、Storyboard Reference を使って遷移したりするのもありだと思います。

IBInspectable と Storyboard を活用しよう

View の角を丸くしたり、影をつけたりするのは Storyboard からは通常設定できません。

そこで IBInspectable に対応させたカスタムの View を作って、
Storyboard の Custom Class に設定します。

class CustomView: UIView {

   // MARK: IBInspectable

   @IBInspectable var cornerRadius: CGFloat = 0
   @IBInspectable var shadowRadius: CGFloat = 0
   @IBInspectable var shadowColor: UIColor = .clear
   @IBInspectable var shadowOffset: CGSize = .zero
   @IBInspectable var shadowOpacity: Float = 0

   // MARK: Override

   override init(frame: CGRect) {
       super.init(frame: frame)
       commonInit()
   }

   required init?(coder aDecoder: NSCoder) {
       super.init(coder: aDecoder)
   }

   override func awakeFromNib() {
       super.awakeFromNib()
       commonInit()
   }

   override func prepareForInterfaceBuilder() {
       super.prepareForInterfaceBuilder()
       commonInit()
   }

   // MARK: Common init

   private func commonInit() {
       isExclusiveTouch = true

       layer.cornerRadius = cornerRadius
       layer.shadowColor = shadowColor.cgColor
       layer.shadowOpacity = shadowOpacity
       layer.shadowOffset = shadowOffset
       layer.shadowRadius = shadowRadius
   }
}

スクリーンショット 2020-07-22 10.46.40

こうすることで Storyboard の Attributes Inspector から IBInspectable で指定したプロパティの項目が設定できるようになります。

上記のコードの場合、
View の角丸の半径、影の色やぼかし具合、位置などを設定できるようになります。

スクリーンショット 2020-07-22 10.50.05

これらのテクニックやコードは投資サービスを運営する Folio の Github アカウントで公開されているリポジトリのものを参考にしています。
アニメーションの実装や Auto Layout の設定など参考になるものが多いのでオススメです。

このように Storyboard で設定できる物は極力 Storyboard で設定することで、どうしても多くなりがちな UI 関連のコードをスッキリさせることができて個人的には気に入っています。

マシンスペックに余裕がある場合は IBDesignable を活用して、変更をビルドなしですぐに確認できるようにするのもありだと思います。

StackView を使おう

例えば以下のようなレイアウトを作る場合、どのように作りますか?

画像4

左上から地道に Auto Layout の制約をつけて行きますか?

スクリーンショット 2020-07-27 15.38.27

とても芸術的な xib ファイルが出来上がりましたが、
地道に Auto Layout の制約をつけていくより StackView を使ったほうがシンプルになります。

スクリーンショット 2020-07-27 16.13.49

今回の例の場合 Auto Layout の制約の数も半分以下にすることができました。

他にも StackView を使うメリットがいくつかあるので紹介します。

■ 入れ替えが簡単

上の例で「シェア」のボタンと「コメント」のボタンの順番を左右反対にしたい場合、芸術的な Auto Layout で実装した方は、一度 Auto Layout の制約を外す必要があるのでものすごく大変です。場合によっては Auto Layout を一から貼り直す必要があると思います。

一方 StackView を使用して実装した方は簡単に実現できます。
StackView 内の View の順番を入れ替えるだけです。

画像7

■ トルツメも簡単

同じく上の例で「真ん中の高さ128pxで固定した View の表示、非表示を切り替えれるようにして、非表示の場合はトルツメしたい」となったときはどうでしょうか?

芸術的な Auto Layout で実装した場合は高さの制約を Outlet 接続して、コードでいじった上で isHidden プロパティを切り替える必要がありそうです。

対して StackView の方は isHidden プロパティを切り替えるだけで自動でトルツメをしてくれます。

画像8

データがないときには UI には表示しないみたいなケースにも簡単に対応することができます。

他にも isHidden プロパティの切り替えのタイミングでアニメーションができたり、ScrollView との相性が良かったりするので、個人的には欠かせないコンポーネントだと思っています。

最後に

初心者だったあの頃から2、3年ほど経っていろんなテクニックを身に付けましたが、ほとんどは経験豊富なエンジニアの方が情報を公開してくれていたおかげで身に付けることができました。

今後は自分も貢献できるように、「あの頃の自分にアドバイスしたいこと」として公開していきたいと思います。

この記事が気に入ったらサポートをしてみませんか?