20200529のSwiftに関する記事は10件です。

【swift】セグメントでの分岐の仕方

セグメントの基本設定

UISegmentedControlの基本設定はstorybord上でできます。
スクリーンショット 2020-05-29 22.32.53.png
セグメントの数や、それぞれに入れる文言はここで設定します。

セグメントによって処理を分岐する

選ばれたセグメントの場所(番号)でスイッチするのが良いでしょう。

@IBOutlet weak var segmentedControl: UISegmentedControl!

// セグメントコントロールが何番目に止まっているかでスイッチ
switch segmentedControl.selectedSegmentIndex {
  case 0:
    break

  case 1:
    break

  case 2:
    break

  case 3:
    break

  default:
    break
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

storybordでUIButtonを角丸にする方法

UIButtonを角丸にしたい

UIButtonをコードなしで角丸にする方法です。
UIButtonを選択肢、画像の場所に書き込みます。

layer.cornerRadius Number 好きな数

スクリーンショット 2020-05-29 22.11.27.png

ビルドすると角丸になっています
スクリーンショット 2020-05-29 22.12.37.png

コーナーラディウスを100にすると、完全なる円になります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SF symbolsの使い方

iOSでよく使われる画像を使いたい

clip_image.jpg test1.png test2.png

上のような画像が使いたい時、あると思います。
これらの画像はそれぞれ
Image(systemName: "paperclip")
Image(systemName: "folder.fill")
Image(systemName: "square.and.arrow.up")
で表示することができます。(SwiftUIを想定しています)

App公式サイトにある download the SF Symbols app をクリックしダウンロードをし表示される手続きに従うと、Launchpadにアプリが追加されます。
スクリーンショット 2020-05-29 16.11.15.jpg

このアプリでは上で表示したpaperclipなどの名前とその画像が表示されます。
スクリーンショット 2020-05-29 16.14.42.jpg

あとは使いたい画像を選択し、Image(systemName: "")のようにすれば、画像を表示することができます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swiftでのビットによるカテゴリ分類の表現方法

ビットマスク

SpriteKitなどの物理エンジンではノード(オブジェクト)の衝突判定などにビットマスクを用いる。

ビットマスクをするために、ノードにはカテゴリとなるbitを割り当てる必要がある。

ビットマスクによる衝突判定処理は、簡単に言えばカテゴリ同士でAND演算を行い、結果が0以外なら有効(衝突)、0なら無効というふうに行う。

例えばノードA(カテゴリ: 0001)とノードB(衝突カテゴリ: 0001)は衝突するが、ノードC(衝突カテゴリ: 0010)とAは衝突しない。

カテゴリビットの定義

基本的にはenumに定義する。そのほうが保守性が高くなる。

最初はbit演算を使えばいけると思った。

mask.swift
enum Category: Int {
    case a = 1 << 0
    case b = 1 << 1
    case c = 1 << 2
    case d = 1 << 3
    case f = 1 << 4
    case g = 1 << 5
    case h = 1 << 6
    case g = 1 << 7
    ...
}

しかし、eunmは要素の初期化時に処理を行うことはできない。enumの値はリテラルである必要がある。

mask.swift:2:14: error: raw value for enum case must be a literal
    case a = 1 << 0
             ^
mask.swift:3:14: error: raw value for enum case must be a literal
    case b = 1 << 1
             ^
mask.swift:4:14: error: raw value for enum case must be a literal
    case c = 1 << 2
...

二進数(0bリテラル)を使う方法と十六進数(0xリテラル)を使う方法が見やすくて良さそう。

二進数

enum CategoryB: Int {
    case a = 0b0000000000001
    case b = 0b0000000000010
    case c = 0b0000000000100
    case d = 0b0000000001000
    case f = 0b0000000010000
    case g = 0b0000000100000
    case h = 0b0000001000000
    case g = 0b0000010000000
    ...
}

十六進数

enum CategoryX: Int {
    case a = 0x0001
    case b = 0x0002
    case c = 0x0004
    case d = 0x0008
    case f = 0x0010
    case g = 0x0020
    case h = 0x0040
    case g = 0x0080
    ...
}

それぞれの生の値は等しい。

assert(CategoryB.h.rawValue == CategoryX.h.rawValue)

個人的には十六進数の方が文字が少なくて良い。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Xcode11でscrollViewを使う

ScrollViewをXcode11で使いたい!

Xcode11からscrollViewの設定のなんやかんやが結構変わったの!で!scrollViewの設定方法が変わりました!よ!
ググっても全然出てこなかったから備忘録として書く!

早速やっていこう

1. ViewControllerにScrollViewを置く

image.png
このscrollViewをViewの中に配置して、
image.png
こんな感じで画面いっぱいに広げよう!
image.png
そしたらこんな感じで制約を追加
image.png
この状態だとまだこんな感じにXcodeに怒られるけど後で追加で設定するから今は気にしないように!

2. ScrollViewにStackViewを置く

image.png
こいつを
image.png
またこんな感じで画面全体に広げる

3. ScrollViewとStackViewをいい感じにする

image.png
StackViewからContent Layout Guideにcontrolキーを押しながらドラッグすると
image.png
こんな感じのポップアップが出るから、
image.png
上の4つにチェック入れよう
で今度はStackViewからFrame Layout Guideにcontrolキーを押しながらドラッグして、
image.png
Equal Widthにチェック!
でここまでやったらConstraintsを見てみて、
image.png
こんな感じで + 414とか + 896とかになってるやつを0にしよう!
image.png

4. ScrollViewにViewを置く

ここまでできたらViewを置くだけ!
image.png
こいつをScrollViewに置いて
image.png
高さを指定してあげれば
image.png
こんな感じになる!!!!
もう1個下にViewを置きたいときは
image.png
こうやって上のViewの一番下に持ってって、StackViewの表示が出るところで離せばオッケ!
image.png
追加したViewにも高さを指定してあげることを忘れずに!

5.Viewの上になんやかんや好きなものを置く

いろいろ置こう!!!!
ViewControllerのサイズを大きくしてあげると作業しやすいかも?
image.png

6.完成!

動いた動画↓
ビデオ開けなかったわ...ぴえん...
一応Githubあげといた↓
https://github.com/sugijotaro/scrollView

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Xcode11でScrollViewを使う

ScrollViewをXcode11で使いたい!

Xcode11からscrollViewの設定のなんやかんやが結構変わったの!で!scrollViewの設定方法が変わりました!よ!
ググっても全然出てこなかったから備忘録として書く!

早速やっていこう

1. ViewControllerにScrollViewを置く

image.png
このscrollViewをViewの中に配置して、
image.png
こんな感じで画面いっぱいに広げよう!
image.png
そしたらこんな感じで制約を追加
image.png
この状態だとまだこんな感じにXcodeに怒られるけど後で追加で設定するから今は気にしないように!

2. ScrollViewにStackViewを置く

image.png
こいつを
image.png
またこんな感じで画面全体に広げる

3. ScrollViewとStackViewをいい感じにする

image.png
StackViewからContent Layout Guideにcontrolキーを押しながらドラッグすると
image.png
こんな感じのポップアップが出るから、
image.png
上の4つにチェック入れよう
で今度はStackViewからFrame Layout Guideにcontrolキーを押しながらドラッグして、
image.png
Equal Widthにチェック!
でここまでやったらConstraintsを見てみて、
image.png
こんな感じで + 414とか + 896とかになってるやつを0にしよう!
image.png

4. ScrollViewにViewを置く

ここまでできたらViewを置くだけ!
image.png
こいつをScrollViewに置いて
image.png
高さを指定してあげれば
image.png
こんな感じになる!!!!
もう1個下にViewを置きたいときは
image.png
こうやって上のViewの一番下に持ってって、StackViewの表示が出るところで離せばオッケ!
image.png
追加したViewにも高さを指定してあげることを忘れずに!

5.Viewの上になんやかんや好きなものを置く

いろいろ置こう!!!!
ViewControllerのサイズを大きくしてあげると作業しやすいかも?
image.png

6.完成!

動いた動画↓
ビデオ開けなかったわ...ぴえん...
一応Githubあげといた↓
https://github.com/sugijotaro/scrollView

参考

https://useyourloaf.com/blog/scroll-view-layouts-with-interface-builder/
https://youtu.be/KmE50giVuLA

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

こんなソースコードはイヤだ-システムに依存する処理には意味ある名前を

プログラムのソースコードのより良い書き方をまとめていこうと思います。

システムに依存する処理には意味ある名前を

sample.swift
  func showSample() {
    UIApplication.shared.open(URL(string: "https://sample.com")!)
  }

  func showExample() {
    UIApplication.shared.open(URL(string: "https://example.com")!)
  }

どのようにリファクタリングできるのか

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UITableViewのドラッグ・アンド・ドロップ・サポートの追加 / テーブルビュー (UITableView) 間のドラッグ

今日は何を学びますか?

アプリケーションのたくさんのテーブルビューにドラッグ・アンド・ドロップ・サポートを追加します。

テーブルビュー間でアイテムをドラッグ・アンド・ドロップできるようになります。

Screen Shot 2020-05-27 at 2.26.54 PM.png

ストーリー

私はかわいい猫を3匹飼っていて、猫用のおもちゃも3つ持っています(実際にはもっとたくさん持っていますが、この例では3つだけということにしておきましょう)。どの猫がどのおもちゃを持っているか追跡したいと思い、簡単なアプリを作りました。

スタータープロジェクト

このチュートリアルに従っていただくために、UITableView が2つ以上あるアプリを持っている必要があります。この例では、1つのCollectionView の中に3つのテーブルビューがあります。

スタータープロジェクトはこちらからダウンロードしてください: https://github.com/mszmagic/DragAndDropNekoApp/tree/StartTemplate

リンク先で最初のバージョンをダウンロードしてください。

完成したプロジェクト

プロジェクトを直接 git clone したら完成したプログラムが手に入ります。

https://github.com/mszmagic/DragAndDropNekoApp

:sparkles:

ドラッグのサポート

ドラッグがサポートされると、システムユーザーが UITableViewCell を長押しし、それをドラッグして現在のテーブルの表示から外に出せるようになります。

tableView.dragInteractionEnabled = true
tableView.dragDelegate = self

デリゲート (Delegate) インプリメンテーションの追加

/*
 Drag delegate
 */
extension catCollectionViewCell: UITableViewDragDelegate {

    func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {

    }

}

ここでは UIDragItem を提供する必要があります。UIDragItem には UITableViewCell 間で移動するデータが必要です。この例では、移動したいデータはオモチャの名前になります。

まずオモチャの名前を入手し:

let toyName = toys[indexPath.row]

次にこれを Data オブジェクト内にエンコード

guard let toyNameData = toyName.data(using: .utf8) else { return [] }

アイテムプロバイダーを生成し、toyNameData をこのプロバイダーにセット。

let provider = NSItemProvider()
provider.registerDataRepresentation(forTypeIdentifier: kUTTypePlainText as String, visibility: .all) { completion in
    completion(toyNameData, nil)
    return nil
}

ここで、その結果を戻す

let item = UIDragItem(itemProvider: provider)
return [item]

ただし、最初のネコの名前が必要になるので、これを session.localContext に保存

session.localContext = catName

これで1つのテーブル表示のセルをドラッグしてテーブル表示から外に出せるようになったはずです。そして、そのテーブル表示のセルを別のテーブル表示にドロップできるはずです。 

https://github.com/mszmagic/DragAndDropNekoApp/blob/master/NekoApp/Views/catCollectionViewCell.swift#L50...L72

でも、ここまでは送り手側の作業を完了しただけです。まだ、これから受け手側のコーディング作業が少し残っています。

ドロップ (Drop) サポートを追加する

ドロップサポートを使うと、別のオブジェクトを現在のビューにドロップできます。ドロップサポートを追加するには、まずテーブルビューにデリゲートを割り当てます。

tableView.dropDelegate = self

次に、delegate を実装します:

extension catCollectionViewCell: UITableViewDropDelegate {

    func tableView(_ tableView: UITableView, performDropWith     coordinator: UITableViewDropCoordinator) {

    }

}

coordinator.session から2つの関数が必要になります。 (https://developer.apple.com/documentation/uikit/uidropsession)

hasItemsConforming(to:)

https://developer.apple.com/documentation/swiftui/dropinfo/3284316-hasitemsconforming

この関数を使うと、ビューにドロップしたデータのタイプを確認することができます。この記事の1つ前の節で次のコード行を使ったことを思い出してください:

provider.registerDataRepresentation(forTypeIdentifier: kUTTypePlainText as String, visibility: .all) { completion in

データのタイプは kUTTypePlainText as String です。次のコードを実行して確認できます:

if coordinator.session.hasItemsConforming(toTypeIdentifiers: [kUTTypePlainText as String]) { }

loadObjects(ofClass:completion:)

この関数を使うと、coordinator 内にあるデータオブジェクトを抽出できます。

coordinator.session.loadObjects(ofClass: NSString.self) { (fetchedItems) in
    //TODO
}
func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
    //データのタイプは `kUTTypePlainText as String` です。次のコードを実行して確認できます
    if coordinator.session.hasItemsConforming(toTypeIdentifiers: [kUTTypePlainText as String]) {
        //この関数を使うと、`coordinator` 内にあるデータオブジェクトを抽出できます。
        coordinator.session.loadObjects(ofClass: NSString.self) { (fetchedItems) in
            guard let toyName = fetchedItems.first as? String else { return }
            //TODO
        }
    }
}

そして、おもちゃの名前が分かれば、そのおもちゃを1匹目の猫から削除して、2匹目の猫に追加できます。

ここでは、おもちゃの名前、1匹目の猫の名前、2匹目の猫の名前が必要です:

おもちゃの名前:

名前の情報は変数toyNameから取得できます。

1匹目の猫の名前

次のコード行を書いたことを思い出してください:

session.localContext = catName

猫の名前は session.localContext に保存してあるので、このコードを使って取得できます:

if let originalCatName = coordinator.session.localDragSession?.localContext as? String {
    //1匹目の猫の名前
}
2匹目の猫の名前

self.catName を呼び出すことで取得できます。

ドラッグ機能の追加に関するコードはここで見ることができます:https://github.com/mszmagic/DragAndDropNekoApp/blob/master/NekoApp/Views/catCollectionViewCell.swift#L50...L72

ドロップ機能の追加に関するコードはここで見ることができます:https://github.com/mszmagic/DragAndDropNekoApp/blob/master/NekoApp/Views/catCollectionViewCell.swift#L74...L93

データを更新する

これで、次のプログラム値が得られました。
- おもちゃの名前
- 最初の猫の名前
- 2番目の猫の名前

次のことが必要です。
- 最初の猫からおもちゃを外す
- 2番目の猫におもちゃを追加する
- テーブルビューをリロードする

これら3つのタスクは ViewController で完了するため、プログラム・デリゲート (Delegate) を使用してこの情報を伝達できます。

protocol dragAndDropActionDelegate: AnyObject {
    func moveToy(toyName: String, fromCat: String, toCat: String)
}

そして、そこでアクションを実行できるよう、このデリゲート (delegate) を ViewController 内にインプリメントします。

extension ViewController: dragAndDropActionDelegate {

    func moveToy(toyName: String, fromCat: String, toCat: String) {
        //最初の猫からおもちゃを外す
        var fromCatToys = catToys[fromCat] ?? []
        fromCatToys.removeAll { (toyNameInArray) -> Bool in
            return toyNameInArray == toyName
        }
        catToys[fromCat] = fromCatToys
        //2番目の猫におもちゃを追加する
        var toCatToys = catToys[toCat] ?? []
        toCatToys.append(toyName)
        catToys[toCat] = toCatToys
        //テーブルビューをリロードする
        collectionView.reloadData()
    }

}

テーブル (catCollectionViewCell) 表示に変数を登録。

//catCollectionViewCell.swift
weak var delegate: dragAndDropActionDelegate?

delegate 変数をセット:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    ...
    cell.delegate = self
    ...
}

そして、ドロップのアクションが実行されたときにデリゲートファンクションをコール。

self.delegate?.moveToy(toyName: toyName, fromCat: originalCatName, toCat: self.catName)

データ配列のアップデートに関連するコードは以下の通り https://github.com/mszmagic/DragAndDropNekoApp/commit/97fb908ce09b031b07c6bbc835fe43a59a9780c2

完成したプロジェクト: https://github.com/mszmagic/DragAndDropNekoApp

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UITableView のドラッグ・アンド・ドロップ (Drag & Drop)・サポートの追加

今日は何を学びますか?

アプリケーションのたくさんのテーブルビューにドラッグ・アンド・ドロップ・サポートを追加します。

テーブルビュー間でアイテムをドラッグ・アンド・ドロップできるようになります。

Screen Shot 2020-05-27 at 2.26.54 PM.png

ストーリー

私はかわいい猫を3匹飼っていて、猫用のおもちゃも3つ持っています(実際にはもっとたくさん持っていますが、この例では3つだけということにしておきましょう)。どの猫がどのおもちゃを持っているか追跡したいと思い、簡単なアプリを作りました。

スタータープロジェクト

このチュートリアルに従っていただくために、UITableView が2つ以上あるアプリを持っている必要があります。この例では、1つのCollectionView の中に3つのテーブルビューがあります。

スタータープロジェクトはこちらからダウンロードしてください: https://github.com/mszmagic/DragAndDropNekoApp/tree/StartTemplate

リンク先で最初のバージョンをダウンロードしてください。

完成したプロジェクト

プロジェクトを直接 git clone したら完成したプログラムが手に入ります。

https://github.com/mszmagic/DragAndDropNekoApp

:sparkles:

ドラッグのサポート

ドラッグがサポートされると、システムユーザーが UITableViewCell を長押しし、それをドラッグして現在のテーブルの表示から外に出せるようになります。

tableView.dragInteractionEnabled = true
tableView.dragDelegate = self

デリゲート (Delegate) インプリメンテーションの追加

/*
 Drag delegate
 */
extension catCollectionViewCell: UITableViewDragDelegate {

    func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {

    }

}

ここでは UIDragItem を提供する必要があります。UIDragItem には UITableViewCell 間で移動するデータが必要です。この例では、移動したいデータはオモチャの名前になります。

まずオモチャの名前を入手し:

let toyName = toys[indexPath.row]

次にこれを Data オブジェクト内にエンコード

guard let toyNameData = toyName.data(using: .utf8) else { return [] }

アイテムプロバイダーを生成し、toyNameData をこのプロバイダーにセット。

let provider = NSItemProvider()
provider.registerDataRepresentation(forTypeIdentifier: kUTTypePlainText as String, visibility: .all) { completion in
    completion(toyNameData, nil)
    return nil
}

ここで、その結果を戻す

let item = UIDragItem(itemProvider: provider)
return [item]

ただし、最初のネコの名前が必要になるので、これを session.localContext に保存

session.localContext = catName

これで1つのテーブル表示のセルをドラッグしてテーブル表示から外に出せるようになったはずです。そして、そのテーブル表示のセルを別のテーブル表示にドロップできるはずです。 

https://github.com/mszmagic/DragAndDropNekoApp/blob/master/NekoApp/Views/catCollectionViewCell.swift#L50...L72

でも、ここまでは送り手側の作業を完了しただけです。まだ、これから受け手側のコーディング作業が少し残っています。

ドロップ (Drop) サポートを追加する

ドロップサポートを使うと、別のオブジェクトを現在のビューにドロップできます。ドロップサポートを追加するには、まずテーブルビューにデリゲートを割り当てます。

tableView.dropDelegate = self

次に、delegate を実装します:

extension catCollectionViewCell: UITableViewDropDelegate {

    func tableView(_ tableView: UITableView, performDropWith     coordinator: UITableViewDropCoordinator) {

    }

}

coordinator.session から2つの関数が必要になります。 (https://developer.apple.com/documentation/uikit/uidropsession)

hasItemsConforming(to:)

https://developer.apple.com/documentation/swiftui/dropinfo/3284316-hasitemsconforming

この関数を使うと、ビューにドロップしたデータのタイプを確認することができます。この記事の1つ前の節で次のコード行を使ったことを思い出してください:

provider.registerDataRepresentation(forTypeIdentifier: kUTTypePlainText as String, visibility: .all) { completion in

データのタイプは kUTTypePlainText as String です。次のコードを実行して確認できます:

if coordinator.session.hasItemsConforming(toTypeIdentifiers: [kUTTypePlainText as String]) { }

loadObjects(ofClass:completion:)

この関数を使うと、coordinator 内にあるデータオブジェクトを抽出できます。

coordinator.session.loadObjects(ofClass: NSString.self) { (fetchedItems) in
    //TODO
}
func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
    //データのタイプは `kUTTypePlainText as String` です。次のコードを実行して確認できます
    if coordinator.session.hasItemsConforming(toTypeIdentifiers: [kUTTypePlainText as String]) {
        //この関数を使うと、`coordinator` 内にあるデータオブジェクトを抽出できます。
        coordinator.session.loadObjects(ofClass: NSString.self) { (fetchedItems) in
            guard let toyName = fetchedItems.first as? String else { return }
            //TODO
        }
    }
}

そして、おもちゃの名前が分かれば、そのおもちゃを1匹目の猫から削除して、2匹目の猫に追加できます。

ここでは、おもちゃの名前、1匹目の猫の名前、2匹目の猫の名前が必要です:

おもちゃの名前:

名前の情報は変数toyNameから取得できます。

1匹目の猫の名前

次のコード行を書いたことを思い出してください:

session.localContext = catName

猫の名前は session.localContext に保存してあるので、このコードを使って取得できます:

if let originalCatName = coordinator.session.localDragSession?.localContext as? String {
    //1匹目の猫の名前
}
2匹目の猫の名前

self.catName を呼び出すことで取得できます。

ドラッグ機能の追加に関するコードはここで見ることができます:https://github.com/mszmagic/DragAndDropNekoApp/blob/master/NekoApp/Views/catCollectionViewCell.swift#L50...L72

ドロップ機能の追加に関するコードはここで見ることができます:https://github.com/mszmagic/DragAndDropNekoApp/blob/master/NekoApp/Views/catCollectionViewCell.swift#L74...L93

データを更新する

これで、次のプログラム値が得られました。
- おもちゃの名前
- 最初の猫の名前
- 2番目の猫の名前

次のことが必要です。
- 最初の猫からおもちゃを外す
- 2番目の猫におもちゃを追加する
- テーブルビューをリロードする

これら3つのタスクは ViewController で完了するため、プログラム・デリゲート (Delegate) を使用してこの情報を伝達できます。

protocol dragAndDropActionDelegate: AnyObject {
    func moveToy(toyName: String, fromCat: String, toCat: String)
}

そして、そこでアクションを実行できるよう、このデリゲート (delegate) を ViewController 内にインプリメントします。

extension ViewController: dragAndDropActionDelegate {

    func moveToy(toyName: String, fromCat: String, toCat: String) {
        //最初の猫からおもちゃを外す
        var fromCatToys = catToys[fromCat] ?? []
        fromCatToys.removeAll { (toyNameInArray) -> Bool in
            return toyNameInArray == toyName
        }
        catToys[fromCat] = fromCatToys
        //2番目の猫におもちゃを追加する
        var toCatToys = catToys[toCat] ?? []
        toCatToys.append(toyName)
        catToys[toCat] = toCatToys
        //テーブルビューをリロードする
        collectionView.reloadData()
    }

}

テーブル (catCollectionViewCell) 表示に変数を登録。

//catCollectionViewCell.swift
weak var delegate: dragAndDropActionDelegate?

delegate 変数をセット:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    ...
    cell.delegate = self
    ...
}

そして、ドロップのアクションが実行されたときにデリゲートファンクションをコール。

self.delegate?.moveToy(toyName: toyName, fromCat: originalCatName, toCat: self.catName)

データ配列のアップデートに関連するコードは以下の通り https://github.com/mszmagic/DragAndDropNekoApp/commit/97fb908ce09b031b07c6bbc835fe43a59a9780c2

完成したプロジェクト: https://github.com/mszmagic/DragAndDropNekoApp

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【iOS】iOSアプリ開発入門~ 画面遷移編2~

はじめに

前回はsegueを使った画面遷移の方法とパラメータの受け渡しについて投稿しました。
画面遷移編2:https://qiita.com/euJcIKfcqwnzDui/items/679b1cd30694519f4916#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB

前回の説明で「画面遷移の方式はいくつかある」というように説明しました。
今回はそのそれぞれの方式について説明します。

前提

その前にアプリのUI、画面設計において覚えておいてほしいことがあります。
UI、または画面の目的は原則として1つにするということです。

世の中に出回っているアプリを思い出してみるとわかるかもしれませんが、例えばボタンの場合、保存、削除、検索など1つのボタンが担う役割は基本的に1つです。
「このボタンは保存も削除も検索もできるボタン」ということにはなり得ません。

画面についても同じことが言えます。
画面の場合はもう少し大きな機能ベースになります。
例えばログイン機能、カメラ撮影機能、動画の再生機能など。
この大きな機能については、どこまでを1機能として捉えるか人によって若干変わるかもしれませんし例外もあります。
ですが1画面に対して1機能が基本だということは覚えておきましょう。

さらにいうとアプリが提供する機能も1つに限定すべきというのが本来の思想でもあります。
例えばiOSの標準アプリの場合、カメラと写真アプリはそれぞれ別アプリとして提供されています。
これはカメラで撮影する機能と写真を管理する機能は別機能として考えられているためです。
Googleアプリについても「Googleサービス」というまとまったアプリではなく、メール、ドライブ、カレンダーなどそれぞれの機能別でリリースされています。

実際のところ複数の機能を提供してしまっているアプリは多く存在しますが原則として1アプリ1機能と認識しておいてください。

画面遷移の種類

少し話が逸れましたがアプリ内において各画面は提供する機能は異なります。
同じ「機能」というものではありますが、それぞれアプリ内での立ち位置が異なりその目的に合わせた画面遷移をさせるのが望ましいとされています。

どういうときにどのような遷移を使った方がいいのかはAppleがHuman Interface Guidelinesで説明しています。
こちらにも一度目を通すことをおすすめします。
Apple Human Interface Guidelines - Modality -
Apple Human Interface Guidelines - Navigation -

この画面遷移の方式は大きく3種類あります。
アニメーションの仕方もそれぞれ異なります。

モーダル

これは前回説明した方式です。

このような下からにゅっと出てくるアニメーションで表現されます。
ezgif-3-85d655783f9d.gif
モーダルで開かれた画面はモーダル画面モーダルウィンドウと言います。
modalは「モードを持つ」という意味で、アプリ機能の主軸とは違う一時的な処理をさせたい時などに使います。
モードが切り替わるというようなイメージでしょうか。
Apple Human Interface Guidelinesでは** Modality**と紹介されています。

iPhoneのAppStoreではアカウント表示に使われています。
AppStoreはアプリの入手するためのアプリです。
アカウント情報やログインはアプリに必要な機能ではありますが、「アプリを入手する」というメイン機能とは違います。

このようにアプリのメインタスクではなくサブタスクを行う場合はモーダルで画面を表示します。

プッシュ

最もよく見る遷移方式です。
右から画面がスライドしてくるアニメーションで表現されます。
ezgif-3-a6efc3b6d4c2.gif
プッシュは詳細が画面を表示する際に使用します。
AppStoreの場合はじめ多くアプリが表示されていますが、その1つをタップすると対象のアプリの詳細な画面が表示されています。
さらにその中からバージョン情報などをタップするとバージョン履歴が表示されるという構成になります。

最もイメージしやすいのはiOS標準の設定アプリです。
複数の項目があり→詳細→詳細と遷移していきます。

Apple Human Interface GuidelinesではHierarchical Navigationと紹介されています。
Hierarchicalとあるように根本となるルート画面があり、そこから階層構造になっています。

タブ

最後はタブによる画面遷移です。
「タブ」とあるように画面最下部に表示されているタブをタップすると画面が切り替わるあれです。
基本的にアニメーションはなく即切り替わります。
ezgif-3-0ca2bb80278b.gif
タブは異なるカテゴリ間の遷移です。目的の画面の検索方法とでもいいましょうか?
とはいえ入りとなるカテゴリは別ですが、全て同じ目的に行き着きます。

AppStoreでは[Today]、[ゲーム]、[App]、[Arcade]、[検索]というタブがあります。
ですが結局のところ目当てのアプリを見つけやすくしているだけで、どのタブからもアプリの画面にたどり着きます。

Apple Human Interface GuidelinesではFlat Navigationと紹介されています。
Flat、つまりは並列です。
基本的に互いに影響は与え合わずそれぞれのタブがそれぞれルートとなる画面を持ちます。
AppStoreを見ればわかりますがそれぞれのルート画面からプッシュで遷移していくことも可能です。

最後に

今回はiOSアプリの画面遷移の方式について紹介しました。
いつどの画面遷移を採用するのか、今はその概要さえ押さえられていれば大丈夫です。

実際のところHuman Interface Guidelinesに書かれてはいるのですが、そこまで詳細ではないのでアプリによって多少違いがあります。
よくタブの1つにマイページタブを置くアプリを見ますが、本来はモーダルの役割ではないかなとも思ったりもします。
(あくまで私見ですのであしからず。。。)

現場ではAndroidアプリも一緒に開発することが多いのですがAndroidにはAndroidの思想があり、どちらを採用するのかを話し合って決めます。
なので結局開発チームに依るところも多いので基本はこんな感じという認識でいてください。

次回はプッシュ、タブ遷移の実装方法について説明します。
画面遷移編3:https://qiita.com/euJcIKfcqwnzDui/items/c0c0ccbd8d301b96d8b7

本連載ではプログラミング未経験からiOSアプリ開発が行えるようになることを目的としています。
今までの投稿をまとめていますのでこちらもご覧ください。
アジェンダ:https://qiita.com/euJcIKfcqwnzDui/items/0b480e96166e88945684

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む