カテゴリー
iOS Swift

iOS & Swift 101 (初歩) Part 1

最初は取っ付きにくい部分はあまり語らず、出来るだけ直感的に手を動かせるように説明していきます。手を動かして行くと徐々に分かってくると思うからです!

また、後々役に立つため、今回はStoryboardを使用せずに全てコードで書いて行きます。

まずはXcodeのメニューから新しいプロジェクトを作成します。

iOSのApp、を選択し、プロジェクト名(なんでもOK)を入力、InterfaceはStoryboard、LanguageはSwiftを選択してください。

まずはこのまま空のプロジェクトをビルドしてみましょう。ビルド先にSimulatorもしくは実機を選択し、右向きの三角ボタン(プレイボタン)をクリックするか、ショートカットCommand + Rでビルド出来ます。

まっ白なスクリーンが表示されます。

この表示されているものがUIViewControllerです。もう少し正確にいうとViewControllerが標準で持っているviewという「部品」です。

Xcodeの一番左にナビゲーションが表示されているので、ViewControllerという名前のファイルをクリックして開きましょう。ちなみに、この赤く囲っているボタンを押すとナビゲーションを隠したり開いたり出来ます。

ViewController最初は以下のようになっています。「クラスの継承」が最初は分からないかも知れませんが、それは後々説明します。

ちなみに、// の後のテキストは、次に改行されるまで全てコメントとして扱われ、プログラム自体には影響を及ぼしません。プログラムというものは多くの場合、将来の自分が見てもよく分からないことがあります。そのため、どのようなつもり、背景でそう書いたのかを書き残しておくと半年後、一年後の自分に感謝されます ^^ このブログもそのようなきっかけで始めました。。。

import UIKit

// UIViewControllerというクラスを継承(inherit)したViewControllerというクラス
class ViewController: UIViewController {
  // UIViewControllerが持つ標準のfunc
  override func viewDidLoad() {
    super.viewDidLoad()
    
  }
}

ごく簡単に説明すると、iOSのスクリーン上に何かを表示させるためには、最低一つのUIViewController(Root ViewControllerと呼びます)が必要ということです。プロジェクト作成時にはXcodeがViewControllerをひとつ自動で作成してくれます。

viewDidLoadというfunctionは、UIViewControllerが標準で持っている関数ですが、これもまた後々Life Cycle(UIViewControllerが作成されてから破棄されるまで)を解説する時にもう少し詳しく説明します。

実際に手を動かすと徐々に分かってくるので、viewに色をつけてみましょう。viewDidLoad内に以下のように書きます。

class ViewController: UIViewController {
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .systemPink
  }
}

Command + Rでビルドしてみると、濃いピンクに変更されました。

iOS開発では、このviewに対して別のviewを追加し画面を組んで行きます。

では実際に別のviewを追加してみましょう。以下のように書きます。

class ViewController: UIViewController {
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .systemPink

    // UIViewクラスのインスタンスを作成しanotherViewという名前をつける
    let anotherView = UIView() 
  // 色をつける
    anotherView.backgroundColor = .systemCyan 
  // 親viewにsub viewとして追加
    view.addSubview(anotherView) 
    // 追加しただけだとまだサイズが指定されていないため表示されないので、CGRectを使って指定する
  anotherView.frame = CGRect(x: 0, y: 0, width: 100, height: 100) 
  }
}

Command + Rでビルドすると、左上コーナーにanotherViewが表示されました。

ここではCGRectというクラスを使ってanotherViewのframeを設定しています。frameは親viewに対してどの位置を起点に、どのサイズで表示するか、というものです。

iOSでは左上コーナーが(x: 0, y: 0)という座標でxは左方向へ、yは下方向へプラスの値ということになっています。(ちなみにmacOSの場合は逆で、左下コーナーが(0, 0)です。なぜでしょうね?中の人の派閥が違うんでしょうか??笑)

では、このCyan(シアン)色の四角を、親viewに対して中央に配置してみましょう。いくつかやり方があるのですが、最も簡単な方法は以下です。

class ViewController: UIViewController {
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .systemPink
    
    let anotherView = UIView()
    anotherView.backgroundColor = .systemCyan
    view.addSubview(anotherView)
    anotherView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
    // anotherViewのcenterを親viewのcenterに合わせる
    anotherView.center = view.center
  }
}

ビルドするとCyanの四角が中央に来ました。

別の方法としては、親viewの中のどこに配置するのかを数値で指定するものです。

そのためには親viewのサイズが分かると良さそうです。

先ほどのviewDidLoad内の各ポイントでいくつかの値をprint出力してみたいと思います。

ちなみに、swift標準のprint関数はとても便利です。print関数の引数(arugument)には、コンマ(,)で区切ることで幾つでもオブジェクトをprint出力出来ますし、”文字列”(string)の中に\( )でオブジェクトを囲ってもstringとして出力出来ます。#functionや#lineなどのキーワードを使うことで、どの関数の何行目の出力なのかが分かり、後々デバッグが楽になると思います。ここでは敢えて色々な書き方をしています ^^

class ViewController: UIViewController {
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    print("\(#function) printing view.bounds: ", view.bounds)
    print("printing view.frame: ", view.frame)
    view.backgroundColor = .systemPink
    
    let anotherView = UIView()
    anotherView.backgroundColor = .systemCyan
    view.addSubview(anotherView)
    anotherView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
    
    print(#line, " printing anotherView.frame: ", anotherView.frame)
    print("\(#line) printing anotherView.bounds: \(anotherView.bounds)")
    
    anotherView.center = view.center
    
    print("\(#line) frame after centered: ", anotherView.frame)
    print("\(#line) bounds after centered: ", anotherView.bounds)
  }
}

ここで注目したいのは、viewのframeとboundsです。簡単に言うと、frameは親viewの中の位置情報を含んだもの、boundsは自分自身におけるサイズです。これらはiOS開発でしょっちゅう使うので、とても大切です。

ビルドすると、以下のように出力されます。太字はコメントです。

view.boundsは親view自身におけるサイズ情報
viewDidLoad() printing view.bounds:  (0.0, 0.0, 390.0, 844.0)
親viewのframeの位置(起点、origin)は、root viewであるため(0.0, 0.0)
printing view.frame:  (0.0, 0.0, 390.0, 844.0)
centeringする前のanotherViewのframe
24  printing anotherView.frame:  (0.0, 0.0, 100.0, 100.0)
centeringする前のanotherViewのbounds
25 printing anotherView.bounds: (0.0, 0.0, 100.0, 100.0)
centering後のanotherViewのframeは、親view内の位置情報を含みます
29 frame after centered:  (145.0, 372.0, 100.0, 100.0)
centering後のboundsは自分自身における情報なので、変わらず
30 bounds after centered:  (0.0, 0.0, 100.0, 100.0)

では、親viewのサイズが分かったので、それを利用してcenter配置してみます。

x軸の中心値はview.bounds.width/2、y軸の中心値はview.bounds.height/2 でゲット出来ます。anotherViewのサイズは100なので、その半分の値100/2を引くことで、anotherViewのorigin(左上コーナー)とするべき値が得られます。ビルドすると同じ結果が得られます。

class ViewController: UIViewController {
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .systemPink
    
    let anotherView = UIView()
    anotherView.backgroundColor = .systemCyan
    view.addSubview(anotherView)
    // Swiftでは文(statement)の途中で改行も可能です。
    anotherView.frame = CGRect(
      x: view.bounds.width/2 - 100/2,
      y: view.bounds.height/2 - 100/2, width: 100, height: 100
    )
  }
}

同じ要領で、anotherViewの中に別のviewを配置してみましょう。

class ViewController: UIViewController {
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .systemPink
    
    let anotherView = UIView()
    anotherView.backgroundColor = .systemCyan
    view.addSubview(anotherView)
    anotherView.frame = CGRect(
      x: view.bounds.width/2 - 100/2,
      y: view.bounds.height/2 - 100/2, width: 100, height: 100
    )
    
    let oneMoreView = UIView()
    // .yellowとも書けますが、省略せずに書くとUIColor.yellowです。Swiftは型を推定出来る場合、型を省略して書くことが出来ます。
    oneMoreView.backgroundColor = UIColor.yellow
    // ここではCGFloat型の定数sizeを作成して使っています
    let size: CGFloat = 80
    anotherView.addSubview(oneMoreView)
    oneMoreView.frame = CGRect(x: anotherView.bounds.width/2 - size/2, y: anotherView.bounds.height/2 - size/2, width: size, height: size)
  }
}

黄色のoneMoreViewを円形にしてみましょう。

class ViewController: UIViewController {
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .systemPink
    
    let anotherView = UIView()
    anotherView.backgroundColor = .systemCyan
    view.addSubview(anotherView)
    anotherView.frame = CGRect(
      x: view.bounds.width/2 - 100/2,
      y: view.bounds.height/2 - 100/2, width: 100, height: 100
    )
    
    let oneMoreView = UIView()
    oneMoreView.backgroundColor = UIColor.yellow
    let size: CGFloat = 80
    anotherView.addSubview(oneMoreView)
    oneMoreView.frame = CGRect(x: anotherView.bounds.width/2 - size/2, y: anotherView.bounds.height/2 - size/2, width: size, height: size)
   // UIViewの持つlayerというオブジェクトのcornerRadiusというattributeにsize/2を入力します。
    oneMoreView.layer.cornerRadius = size/2
  }
}

UIView以外にもUIButtonやUILabelなどさまざまな部品がUIKitフレームワークには用意されていますが、配置の基本は同じです。

Part 2では変数(や定数)のスコープや、UIViewControllerのLife Cycleを説明するために、もう少しだけ機能を追加した画面を作ってみます。