【Swift5】Instructionsを使って超簡単にアプリのチュートリアルを作る

5 min read読了の目安(約4600字

はじめに

個人でアプリ開発をしているとき、アプリの使い方の説明を自分で一から作るのは大変だと思います
そこで、Instructionsを使うと、結構お手軽にチュートリアルを実装することができます(どういう感じかは下にスクロールするとわかります)

ライブラリの情報

Instructions

https://github.com/ephread/Instructions

インストール

Podfileに以下を追記しましょう

pod 'Instructions', '~> 2.0.1'

完成イメージ

画像はgithubからお借りしました

実装していく

Instructionsのチュートリアル系の要素はCoach(指導者的な意味)が名前につきます

インポート

チュートリアルを表示したいViewControllerでInstructionsをインポートします

HogeViewController.swift
import Instructions

extensionで拡張

とりあえず拡張するだけで中身はまだ作りません

HogeViewController.swift
//MARK: Instructions
extension HogeViewController: CoachMarksControllerDataSource, CoachMarksControllerDelegate {
    //ここにはあとで色々追加していく
}

コーチコントローラーを作成し、データソースを紐付ける

HogeViewController.swift
class HogeViewController {
	//コーチビューコントローラーを作成
	let coachMarksController = CoachMarksController()
	
	//viewDidLoad()で
	override func viewDidLoad() {
	    super.viewDidLoad()
		
	    //データソースを紐付けます
	    self.coachMarksController.dataSource = self
	    //extensionで先に拡張しておかないとエラーになります
	}
}

チュートリアルのステップ数を決める

チュートリアルのステップ数を先ほどのextensionの中できめ、返してあげます
ステップ数というのは、「ここを押すとこうなりますよ|OK!」という吹き出しの数だと思ってください

HogeViewController.swift
//先ほどのextensionの中に追記します

/// 吹き出しの数を決める場所
func numberOfCoachMarks(for coachMarksController: CoachMarksController) -> Int {		
	/// 自分の設定したいステップ数に合わせて変更してください
	return 3
}

スポットライトを当てるViewを決める

吹き出しが出てくる元のViewを決めます
こちらもextensionの中に追記します

HogeViewController.swift
/**
    スポットライトが当たるビューを返します
    - Parameters:
        - index: 何ステップ目か
*/
func coachMarksController(_ coachMarksController: CoachMarksController,
                          coachMarkAt index: Int) -> CoachMark {
			  
    //基本的にはチュートリアルの対象にしたいボタンやビューをチュートリアルの順にArrayに入れ、indexで指定する形がいいかなと思います(もっといい方法があったら教えてください)
    let highlightViews: Array<UIView> = [hogeLabel, fugaButton, piyoSwtich]
    //(hogeLabelが最初、次にfugaButton,最後にpiyoSwitchという流れにしたい)

    //チュートリアルで使うビューの中からindexで何ステップ目かを指定
    return coachMarksController.helper.makeCoachMark(for: highlightViews[index])
}

2021/3/26 追記

ナビゲーションバーのアイテムにスポットライトを当てたい場合

そのままではArrayに入れられない上、coachMarksController.helper.makeCoachMark()にすら入りません
ナビゲーションアイテムにスポットライトを当てるには以下のようにします

HogeViewController.swift
let highlightViews: Array<UIView> = [hogeLabel, 
				     fugaButton, 
				     piyoSwtich,
				     someNaviBarItem .value(forKey: "view") as! UIView]
				     //アイテムのビューを取得して入れる

吹き出しの内容を決める

ビューにスポットライトが当たって出てくる吹き出しの中身などの設定をします
こちらもextensionの中に追記します

HogeViewController.swift
/** 
    吹き出しの詳細を決めます
    - Parameters: 
        - coachMarksController: チュートリアル用のVC
	- index: 何ステップ目か
	- coachMark: 吹き出し
    - Returns: 吹き出し
*/
func coachMarksController(
    _ coachMarksController: CoachMarksController,
    coachMarkViewsAt index: Int,
    madeFrom coachMark: CoachMark
) -> (bodyView: UIView & CoachMarkBodyView, arrowView: (UIView & CoachMarkArrowView)?) {

    //吹き出しのビューを作成します
    let coachViews = coachMarksController.helper.makeDefaultCoachViews(
        withArrow: true,    //三角の矢印をつけるか
        arrowOrientation: coachMark.arrowOrientation    //矢印の向き(吹き出しの位置)
    )

    //index(ステップ)によって表示内容を分岐させます
    switch index {
    case 0:    //hogeLabel
        coachViews.bodyView.hintLabel.text = "これはhogeLabelです"
        coachViews.bodyView.nextLabel.text = "OK!"
	
    case 1:    //fugaButton
	coachViews.bodyView.hintLabel.text = "このボタンを押すといいことがあります"
        coachViews.bodyView.nextLabel.text = "👌"
    
    case 2:    //piyoSwitch
        coachViews.bodyView.hintLabel.text = "このスイッチで設定を切り替えられます"
        coachViews.bodyView.nextLabel.text = "了解"
    
    default:
        break
	
    }
    
    //その他の設定が終わったら吹き出しを返します
    return (bodyView: coachViews.bodyView, arrowView: coachViews.arrowView)
}

チュートリアルを開始する

チュートリアルを開始するには以下の一文を実行するだけでできます

self.coachMarksController.start(in: .currentWindow(of: self))

GitHubのサンプルでは

self.coachMarksController.start(in: .window(over: self))

となっていましたが、筆者の環境では動かなかったので先述の方をお勧めします

通常は画面を読み込んだらチュートリアルを始めさせたいと思うでしょうからviewDidAppear()で呼んであげます

HogeViewController.swift
override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    //チュートリアル開始!
    self.coachMarksController.start(in: .currentWindow(of: self))
}

また、チュートリアルをスキップさせるなど、途中でチュートリアルを止めたい場合は、

self.coachMarksController.stop(immediately: true)

これを実行してあげましょう

細かいパラメーターなどについてはGitHubの方を参照ください

終わり

直感的に使えて便利
個人開発にとても重宝しそうだと思いました

もし間違っているところがあれば教えてください