しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

MYBlurIntroductionViewを使ったチュートリアル作成

MYBlurIntroductionViewというウォークスルーを作るライブラリを試してみました。

f:id:llcc:20171106132253g:plain

github.com

インストールはCocoaPodsで行います。

target 'MyApp' do
  use_frameworks!

  pod 'MYBlurIntroductionView'
end

実際に使うにあたって、まずは適当なアイコンをプロジェクトに追加します。

f:id:llcc:20171106141433p:plain

アイコンは下サイトのものを利用しました。

icooon-mono.com

アイコンを追加したら実際に実装していきます。
おおまかな流れとしては「MYIntroductionPanel(ウォークスルーの各ページに相当)を複数個作成、それを元にMYBlurIntroductionViewを作って画面にセットする」という流れです。

import UIKit
import MYBlurIntroductionView

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let headerView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 100))
        headerView.backgroundColor = UIColor.blue
        
        let panel1 = MYIntroductionPanel(frame: view.bounds, title: "Welcome to MYBlurIntroductionView", description: "MYBlurIntroductionView is a powerful platform for building app introductions and tutorials. Built on the MYIntroductionView core, this revamped version has been reengineered for beauty and greater developer control.", image: #imageLiteral(resourceName: "book"), header: headerView)
        panel1?.backgroundColor = UIColor.darkGray
        
        let panel2 = MYIntroductionPanel(frame: view.bounds, title: "Automated Stock Panels", description: "Need a quick-and-dirty solution for your app introduction? MYBlurIntroductionView comes with customizable stock panels that make writing an introduction a walk in the park. Stock panels come with optional overlay on background images. A full panel is just one method away!", image: #imageLiteral(resourceName: "pen"))
        panel2?.backgroundColor = UIColor.lightGray
        
        let introductionView = MYBlurIntroductionView(frame: view.bounds)
        introductionView.buildIntroduction(withPanels: [panel1, panel2])
        view.addSubview(introductionView)
        introductionView.backgroundImageView.image = #imageLiteral(resourceName: "pen")
    }
}

アプリを起動すると、下のように2ページだけのウォークスルーを作成できました。

f:id:llcc:20171106141614g:plain

各ラベルへのアクセスできるので、フォントや文字色も簡単に変更できます。

let panel1 = MYIntroductionPanel(frame: view.bounds, title: "Welcome to MYBlurIntroductionView", description: "MYBlurIntroductionView is a powerful platform for building app introductions and tutorials. Built on the MYIntroductionView core, this revamped version has been reengineered for beauty and greater developer control.", image: #imageLiteral(resourceName: "book"), header: headerView)
panel1?.panelTitleLabel.textColor = UIColor.darkGray
panel1?.panelDescriptionLabel.textColor = UIColor.lightGray

f:id:llcc:20171106142014p:plain

delegateで、下のイベントを取ることが可能です。

extension ViewController: MYIntroductionDelegate {
    func introduction(_ introductionView: MYBlurIntroductionView!, didFinishWith finishType: MYFinishType) {
    }
    
    func introduction(_ introductionView: MYBlurIntroductionView!, didChangeTo panel: MYIntroductionPanel!, with panelIndex: Int) {
    }
}

【読書メモ】Hooked ハマるしかけ

こちらの本を読んでみました。
Hookedというモデルを通して、インスタグラムなどの有名アプリのヒットの仕組みについて書かれています。

メモ

  • フックモデルは人間を習慣づけさせる為のフレームワークで、4ステップで構成されている
  • ステップは「トリガー」「アクション」「リワード」「インベストメント」の4つ
  • トリガーはアクションを起こすためのきっかけ、外的トリガーと内的トリガーの2種類がある
  • 外的トリガーはアプリインストールの為の広告や口コミなど
  • 内的トリガーは良い景色を見た時に投稿したくなるなど
  • 内的トリガーを増やすためには、ユーザーのニーズを把握する事が重要
  • アクションはトリガーの次のステップで、実際に行動する部分
  • 行動するために必要なのは「モチベーション」「行動するための能力」「トリガー」の3つが必要
  • 行動するための能力はできるだけ低くする方が良い(プロダクトを簡単に使えるようにする)
  • 希少効果でモチベーションを高めることができる(例: Amazonの「残り○点」という表示で購買意欲を高める)
  • エンダウド・プログレス効果という、「ゴールに近い状態だとモチベーションが上がりやすい」という法則がある
  • エンダウド・プログレス効果を使った例として、WEBサービスのプロフィール完成度の表示などがある
  • リワードは予測不能な事が重要、予想可能だと喜びが減る
  • 報酬は「トライブ」「ハント」「セルフ」の3つがある
  • 「トライブ」は周囲に認められることで、Facebookのいいねなどがある
  • 「ハント」は何かを探し求めること、スロットマシンで当たりを出したりTwitterで良い情報を見つけることなどがある
  • 「セルフ」は何かの達成するなどの報酬、ゲームでのレベルアップ時の満足感などがある
  • 人は自主性を損なうと抵抗を感じる
  • 「インベストメント」はユーザーに求める行動
  • 人は行動すればするほど価値を感じる(例: 長い時間を使ったゲームに価値を感じる)

Embedded Frameworkを作ってみる

iOS8から導入されたEmbedded Frameworkを試してみました。
Embedded Frameworkは動的なライブラリで、プロジェクト分割によってコンパイル速度が早くなる・Extensionとの共通処理を書きやすいと言った利点があるようです。

まずは新規プロジェクトの作成をします。

f:id:llcc:20171104134037p:plain

次に、Targetの追加を押します。

f:id:llcc:20171104133817p:plain

下の方にあるCocoa Touch Frameworkを選びます。

f:id:llcc:20171104133830p:plain

これでEmbedded Frameworkを作る事ができました。
作ると下のようにターゲットが追加されます。

f:id:llcc:20171104134141p:plain

同時に、下のようにフォルダが作られます。

f:id:llcc:20171104134156p:plain

続けてEmbedded Frameworkのコードを読み取ってみようと思います。
Embedded Frameworkにファイルを追加します。

f:id:llcc:20171104134229p:plain

外部からクラスを参照する場合はpublicを付ける必要があります。

import UIKit

public class MyClass: NSObject {
}

作ったクラスをプロジェクトから呼び出すには、下のようにimportします。

import UIKit
import MyLibrary

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        _ = MyClass()
    }
}

PalauでUserDefaultsの管理を簡単に

Palauというライブラリを試してみました。

github.com

インストールはcocoapodsで行いました。

target 'MyApp' do
  use_frameworks!

  pod 'Palau'
end

使い方は下の通りです。
下のようにまずは変数を定義します。

import UIKit
import Palau

extension PalauDefaults {
    static var name: PalauDefaultsEntry<String> {
        get { return value("myName") }
        set { }
    }
}

定義した変数は下のように使えます。

print(PalauDefaults.name.value) // → nil
PalauDefaults.name.value = "MyString"
print(PalauDefaults.name.value) // → MyString

String以外にも対応しています。

extension PalauDefaults {
    static var count: PalauDefaultsEntry<Int> {
        get { return value("myCount") }
        set { }
    }
}

デフォルト値は下のようにwhenNilで定義します。

extension PalauDefaults {
    static var name: PalauDefaultsEntry<String> {
        get { return value("myName").whenNil(use: "myDefaultString") }
        set { }
    }
}

didSetを使ってセット時のイベントを取る事ができます。
ブロックの第一引数が新しい値、第二引数が古い値です。

extension PalauDefaults {
    static var name: PalauDefaultsEntry<String> {
        get { return value("myName").didSet { print($0, $1) } }
        set { }
    }
}

下のように条件付き値を扱う事もできます。
ここでは10以下場合は10がセットされるようにしています。

extension PalauDefaults {
    static var count: PalauDefaultsEntry<Int> {
        get { return value("myCount").ensure(when: { ($0 ?? 0) < 10 }, use: 10) }
        set { }
    }
}

PalauDefaults.count.value = 5
print(PalauDefaults.count.value) // → 10
PalauDefaults.count.value = 11
print(PalauDefaults.count.value) // → 11

【iOS】Interpolateでオシャレウォークスルー

Interpolateというライブラリを試してみました。

f:id:llcc:20171102141005g:plain

github.com

まずはCocoaPodsでインストールします。

target 'MyApp' do
  use_frameworks!

  pod 'Interpolate'
end

次に実際に実装してみます。
今回は画面をスワイプすると色が黒から白に変わるというものを作ってみようと思います。

まずは下のようにInterpolateをwhiteとblackを渡して初期化します。

import UIKit
import Interpolate

class ViewController: UIViewController {
    var interpolate: Interpolate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        interpolate = Interpolate(from: UIColor.white, to: UIColor.black, apply: { [weak self] color in
            self?.view.backgroundColor = color
        })
    }
}

Interpolateは、下のようにprogressをセットして使います。
下のように0.5を入れれば、applyに灰色(初期化時に渡したfromとtoの中間色)を引数に呼び出されます。
progressに1.0を入れればtoの黒色が引数に渡され、0.0の場合はfromの白色が渡されます。

interpolate = Interpolate(from: UIColor.white, to: UIColor.black, apply: { [weak self] color in
    self?.view.backgroundColor = color
})
interpolate?.progress = 0.5

次はスワイプに応じてprogressを渡す処理を実装します。
下のようにUIPanGestureRecognizerをセットします。

class ViewController: UIViewController {
    var interpolate: Interpolate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        interpolate = Interpolate(from: UIColor.white, to: UIColor.black, apply: { [weak self] color in
            self?.view.backgroundColor = color
        })
        
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.swipeView(sender:))))
    }
    
    @objc func swipeView(sender: UIPanGestureRecognizer) {
        let translation = sender.translation(in: view)
        let translatedCenterX = view.center.x + translation.x
        let progress = translatedCenterX / view.bounds.size.width
        interpolate?.progress = progress
    }
}

これでスワイプに応じて白から黒に変わる処理が実装できました。

f:id:llcc:20171102142114g:plain

Interpolateですが、色だけでなくCGPointやCGFloatなども渡す事ができます。

Interpolate(from: CGPoint(x: 0, y: 0), to: CGPoint(x: 100, y: 100), apply: { [weak self] point in
})

【iOS】静的ライブラリ(.aファイル)を作ってみる

iPhoneアプリ開発をしているとよく出てくる静的ライブラリですが、自分が作ったことはなかったので試しに作ってみました。

静的ライブラリの作成

まずはXcodeの新規プロジェクトで、Static Libraryを選択します。

f:id:llcc:20171102203739p:plain

プロジェクトを作成すると下のようなフォルダ構成になっています。

f:id:llcc:20171102203858p:plain

まずはログを出力するだけのメソッドを実装します。

@interface MyLibrary : NSObject

- (void)outputLog;

@end
#import "MyLibrary.h"

@implementation MyLibrary

- (void)outputLog {
    NSLog(@"MyLibrary!");
}

@end

ビルドすると下のフォルダに.aファイルが生成されます。

f:id:llcc:20171102204026p:plain

ライブラリを使う時は、使いたいプロジェクトに.aファイルとヘッダーファイルを移動します。

f:id:llcc:20171102213853p:plain

あとはBridgingHeaderでimportをする事でライブラリを使えます。

#import "MyLibrary.h"
import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        MyLibrary().outputLog()
    }
}

参考URL

iOSにおける静的ライブラリ作成技法 - 渋谷ラーメン男道

HEARTフレームワークでアプリの指標を考える

Googleが使っているHEARTフレームワークというものを使ってアプリの指標を考えてみました。
指標を考えたのは、運営中の体重管理アプリです。

体重管理ダイエットのFittを App Store で

f:id:llcc:20171031141121p:plain

HEARTフレームワークは下記事を参考にしました。

growthhackjournal.com

HEARTフレームワークとは

HEARTフレームワークとは指標を「ハピネス(Happiness)」「エンゲージメント(Engagement)」「アダプション(Adoption)」「リテンション(Retention)」「タスクの成功(Task success)」の5種類に分類する事で、利用する指標を選べるようにする事です。
それぞれは下のような意味になります。

・ハピネス(Happiness) 顧客調査を通じて得られるユーザーの態度に関する指標を指します。例えばユーザーの満足度、UIの使いやすさ、NPS(カスタマー・ロイヤルティを計測する指標)などが挙げられます。

・エンゲージメント(Engagement) ユーザーの関与レベルに関する指標を指します。ユーザーが一週間にサービスを利用した回数の平均、一日にアップロードした写真数の平均、シェア数など、一定期間内におけるユーザーインタラクションの深さや強さ、頻度を測ることによって得られます。

・アダプション(Adoption) プロダクトの全体や一部の機能を初めて使うユーザーに関する指標を指します。例えば、過去7日間で作られたアカウント数やラベル機能を使ったGmailユーザーの割合などです。

・リテンション(Retention) 既存ユーザーが戻ってくる割合を指します。例えば、ある期間内のアクティブユーザーがある一定期間後にどれだけ残っているか?または「チャーン」という言葉で知られているように継続をやめてしまった人の割合などが挙げられます。

・タスクの成功(Task success) これは作業効率(タスク完了までの時間など)、有効性(タスク完了率など)、エラー率などといった、昔から使われている指標を含みます。これは検索やアップロードのフローなど作業にフォーカスされたプロダクトにもっとも適用されるカテゴリーです。

HEARTフレームワークの使い方

HEARTフレームワークはGoals-Signals-Metricsというステップの中で利用するようです。
ゴールはアプリや機能の目標、シグナルはユーザーの具体的なアクション、メトリクスは具体的な数字です。

HEARTのそれぞれのGoals-Signals-Metrics事でより指標を分かりやすくするもののようです。

f:id:llcc:20171031144554j:plain

Google’s HEART User Experience Metrics and the Goals-Signals-Metrics Process: An Overview | UserVoice Blogより

体重管理アプリに置き換えて考える

体重管理アプリではアクティブユーザー数が重要なので、「リテンション(Retention)」について考えてみました。

体重管理アプリのゴールとしてはユーザーが毎日利用してくれる事です。
1人が起動する回数は増やしにくいので、離脱する人を減らす事が重要になります。

シグナルとしては日々の体重の入力が考えられます。
カレンダー表示もグラフ表示も、体重を入力しないと意味がないので体重入力が一番大切なアクションです。

メトリクスはインストールした人の何割が7日後も入力しているかというものが良さそうだと思いました。
Firebaseで見る事ができるので、それを使って指標を追いかけてみようと思いました。

f:id:llcc:20171031145107p:plain

参考URL

Google’s HEART User Experience Metrics and the Goals-Signals-Metrics Process: An Overview | UserVoice Blog