スマートフォンwebのタップイベントを高速化するライブラリ"fastclick.js"をさわってみた

先日参加したADC MEETUP ROUND 07での@akb7_jpさんのセッション「HTML アプリケーションのパフォーマンスを良くする 10 のポイント」にて、"fastclick.js"というタップイベントを高速化するツールの話があって試してみたのでここに書いておきます。

ftlabs/fastclick

今回のエントリは、そのセッションのレポートというよりかは、あくまで自分が認識した内容となっていますのでそこらへんはあしからず。

パフォーマンスを良くする10のポイントのうちの1つに「#6 クリックイベントは使わない」という項目がありました。これはどういうことかというと、スマートフォンwebにおけるタッチイベントは"onclick"ではなく"ontouchstart"を使ったほうがレスポンスが早く、ユーザビリティが向上するという話でありました。
それもそのはず、"onclick"ではダブルクリックかを判定するために300msほど待ってからイベントを発火するという処理を行っているようなので、理屈ではありますね。

確かに試してみたところ、明らかにontouchstartのほうがレスポンスが早くてユーザビリティが良いように思われます・・・が、大抵のスマートフォンwebサービス(ネイティブだろうがwebだろうが)ではイベントの発火タイミングにontouchstartにあたるものは採用されていないように思います。

というのも、「誤ってあるボタンにタップしてしまっても、そのボタンから指をずらして離すことで、イベント発生をキャンセルすることができる」というのがタッチデバイスでのユーザビリティの原則だから、というのが持論です。実際に自分はこのような方法でスマートフォンを操作しています。

ここで、"fastclick.js"です。イベントの発火タイミングについては"onclick"同様ですが、通常のよりも高速になります。
以下にサンプル置いておきました。スマートフォンで確認ください。

f:id:ushisantoasobu:20130629194803j:plain
fastclick.jsのサンプル

それぞれの画像をタップするとalertがあがります。
左から"onclick", "ontouchstart", fastclickをattachした"onclick"になります。

導入にあたっての注意点などはもう少し調べてみようと思います。

Sublime Text 2でまとめてインクリメントの処理を行う

少し前から業務でjavascriptを書いています。エディタはSublime Text 2を使っているのですが、あるとき以下のようなインクリメントなコードを書く必要があって(あくまで例です!業務で何書いたか忘れてしまいました・・・)、

<img src="/test_1.png">
<img src="/test_2.png">
<img src="/test_3.png">
<img src="/test_4.png">
<img src="/test_5.png">
<img src="/test_6.png">
<img src="/test_7.png">
<img src="/test_8.png">
<img src="/test_9.png">
<img src="/test_10.png">

これは絶対に楽にまとめて書きたいと思って便利なプラグインはないかと探してみたら、"Incrementor"というのがあったので書いておきます。

Incrementor

まずPackage ControlからIncrementorをインストールします。Package Controlをまだインストールしていない方はこちらから。

使い方は、一番はじめのコードを完成させる手順を追う形で紹介していこうと思います(ショートカットキーはMacのものです)。

まず下記の1行を書きます。インクリメントな数字に置換したいところをとりあえずここでは"aaa"としておきます。

<img src="/test_aaa.png">

【⌘+shift+D】で行のコピーを行います。

<img src="/test_aaa.png">
<img src="/test_aaa.png">
<img src="/test_aaa.png">
<img src="/test_aaa.png">
<img src="/test_aaa.png">
<img src="/test_aaa.png">
<img src="/test_aaa.png">
<img src="/test_aaa.png">
<img src="/test_aaa.png">
<img src="/test_aaa.png">

ここでIncrementorを使います。
【⌘ + G】, 【⌘ + R】と続けて入力すると以下のような画面になります。

f:id:ushisantoasobu:20130608163607j:plain

ここでまず置換したい文字列を入力します。ここでは"aaa"と入力します。

f:id:ushisantoasobu:20130608163645j:plain

Enterキーを押すと、次はどのように置換するのかの入力画面になるので以下のような入力します。

f:id:ushisantoasobu:20130608163655j:plain

すると

f:id:ushisantoasobu:20130608163710j:plain

と一番はじめのコードになりました。

先ほど"\i"と入力した箇所を"\i(100, 1)"と入力すると以下のようにできるなどオプションもあります。

<img src="/test_100.png">
<img src="/test_101.png">
<img src="/test_102.png">
<img src="/test_103.png">
<img src="/test_104.png">
<img src="/test_105.png">
<img src="/test_106.png">
<img src="/test_107.png">
<img src="/test_108.png">
<img src="/test_109.png">


まああまり使うことないかもしれないし、もっと楽な方法もあるかもしれないけれど一応。

【第6回】iOSアプリ ticket to UI/UX

今回はUIにおけるUXについて。UIとUXについての定義は人それぞれのところがあると思いますが、自分はそういった細かいことはあまり気にしません。「UIにおけるUX」と書きましたが、もう少し細かくいうと「同じUIを使用していながらも、実に様々な体験を我々は提供できるor享受してるのでは」というのが今回のエントリーの内容です。

タイムラインならぬディスタンスライン

"trover"という写真共有アプリが最近好きです。

f:id:ushisantoasobu:20130508011207j:plain

縦に写真が並べられていて下にスクロールしていくことで次から次へと写真を見ていく「よくある」ものなのですが、下にいけばいくほどその写真が撮影された場所が遠くなるという見せ方をしています。「タイムライン」ならぬ「ディスタンスライン」とでも呼べるのでしょうか。
はじめは東京の観光名所なんかの写真なんかが多くあって(あ、私は東京の大田区在住です)、どんどん距離が離れていくと国内の各地の名所が、そしてふと気がつけばいつの間にか海外へ、さらにいくとそこは完全に異国情緒な風景が・・・。


f:id:ushisantoasobu:20130508011655j:plain
スカイツリー、行こうと思えばすぐに行ける距離にある


f:id:ushisantoasobu:20130508011706j:plain
山形の山寺が見えますね


f:id:ushisantoasobu:20130508011944j:plain
くまもんがいるので熊本あたりなのでしょうw


f:id:ushisantoasobu:20130508011959j:plain
ハングルが見えるから韓国??いつのまにか海外へ


f:id:ushisantoasobu:20130508011800j:plain
完全に異国情緒溢れる風景が・・・

こういった一連の体験が個人的には大好きなのですが、UIという点で見ればよくあるタイムラインと同じものなので、同じUIでもサービスのコンセプトや見せ方次第で全く別の新しいUXを提供できると思います。

アラートビューの文言について

先日"ボケて"をみているときに思わず笑ってしまいました。もちろん投稿された作品がおもしろいサービスなのですが、そのときはアラートの文言で笑ってしまいました。

f:id:ushisantoasobu:20130508013030j:plain

せっかちな自分は「読み込みできない」などといわれると正直結構いらっときてしまう。にも関わらず「おっと」という一言で、思わず許してしまいました。「ボケて」というアプリのコンセプトと合致するような文言だったからかもしれません。Facebookのアプリで、「おっと、XXXXXXX」なんて言われたらムカっとするかもしれませんw(それはそれで斬新かも・・・)。


f:id:ushisantoasobu:20130508013109j:plain

"火をつけろ"でも「余計なお世話」という言葉にちょっと笑ってしまいました。

こういったフランクなアプリ限定の話なんじゃないのかと言われるとちょっと自信はありませんが、最近読んだサイバーエージェント藤田社長の本で、自身が社長という役職でありながらアメーバのプロデューサーとしてサービスに徹底的にこだわる件があるのですが、そこでも「文言」というのは1つの重要な要素としてしっかり入っていました。
同じアラートビューというUIでも、文言1つで笑いをとることもできるかもしれないし、ユーザに安心感を与えることもできるかもしれない、何か不備があったとしてもユーザの怒りを最小限に抑えることができるかもしれない、、、そんなふうに思えます。


起業家

起業家

ナビゲーションバーのボタンをカスタマイズしたけどなぜかイベントが発生しないとき

iOSアプリでのナビゲーションバーのボタンのデザインのカスタマイズについて、少しハマってしまったので備忘録として。

ナビゲーションバーの右にデザインをカスタマイズした「保存」ボタンを置きたいという状況が発生しました。
ナビゲーションバーのボタンのカスタマイズについては他のサイトにもたくさん情報があります。それらをもとに、以下のようなコードを書きました。

    //保存ボタンの追加
    UIBarButtonItem *btnSave = [[UIBarButtonItem alloc]
                                initWithBarButtonSystemItem:UIBarButtonSystemItemSave
                                target:self
                                action:@selector(respondToBtnSave:)];
    UIButton *btnSaveView = [HeaderBtnUtil createHeaderBtnView:@"save"];
    [btnSave setCustomView:btnSaveView];

    self.navigationItem.rightBarButtonItem = btnSave;

今回の例は、別で生成したUIButtonのデザイン("createHeaderBtnView"で設定しています)をナビゲーションバーのボタンのデザインに設定するというものです。
ポイントは"setCutomView"。たったこれだけ。これで大丈夫かな、、、と思ったのですが、デザインは反映されましたがボタンがなぜか効かない。正解は、

    //保存ボタンの追加
    UIBarButtonItem *btnSave = [[UIBarButtonItem alloc] init];
    UIButton *btnSaveView = [HeaderBtnUtil createHeaderBtnView:@"save"];
    [btnSaveView addTarget:self
                    action:@selector(respondToBtnSave:)
          forControlEvents:UIControlEventTouchUpInside];
    [btnSave setCustomView:btnSaveView];
    
    self.navigationItem.rightBarButtonItem = btnSave;

でした。
つまり"setCutomView"で設定したビューにイベントを設定してあげなくてはいけなかったようです。

flashをずっと開発してきた人間がiOS開発をやってみて

今月はじめに、業務で開発に携わっていた"デコラージュ"というアプリがリリースされました。

f:id:ushisantoasobu:20130330174735j:plain
Decollage~デコラージュ~ スタンプで出来るイラスト作成アプリ

これまで長くflash開発を続けてきましたが、上司へ意思表明して念願のiOS開発に携わらせていただきました。感謝。
社内で、flash開発してきた人間からみたiOS開発の醍醐味だったり所感だったり、をまとめた簡単な発表をしましたのでslideshareにアップしました。

似たような境遇を迎える人がいたら、目を通していただけると幸いです。

また口頭ベースでの資料となっていますので、スライドだけみてもわかりづらいところあると思いますのでここで補足しておこうと思います。

メモリ管理

ARCを使ってもメモリリークはガンガン起きるという話。
スライド25ページで例として紹介しているのは以前のエントリで詳細に書いたものです。

UITableViewCellの再利用でメモリリーク

他にもCGImageRefの解放漏れだとか、ファイルサイズが大きいものをより快適なUXを目論んで先読みするという仕様だったのをプロデューサーに直訴してそれを表示する直前で読み込むようにした、などがありました。

画像キャッシュ

大量の、しかも比較的ファイルサイズの大きい画像を扱うアプリであるため、かなり早い段階から画像キャッシュの機構についてはみんなで考えました。
簡単にいうと、頻繁にアクセスする画像については「メモリキャッシュ→ディスクキャッシュ→画像サーバ」の順番でみていくというもの。
下記の記事を参考にしました。こちらも感謝。

ダウンロードした画像をキャッシュするクラスの設計と実装について

マルチスレッド処理

スライドの58ページ目で具体的にあったこととして、並列処理のところに

  • 複数のパラメータを渡すと画像のパスを返してくれるシングルトンのクラスがあった
  • そのシングルトンは、はじめてアクセスがあったときにplistからデータを取得して、返すデータの準備をする

みたいな記述があったために、はじめて画像のパスを取得しようとしたときに、場合によってEXE_BAD_ACCESSが起きました。
なかなか原因見つけるのに時間がかかったため、複雑なものを書こうとするときは注意が必要ですね。

iOSのバージョン、デバイスの違い

Android開発をしている方からすれば「ナメてるのかー!!」言われるかもしれませんが、flash(PC)で開発をしてきた私にとっては結構めんどくさいものでした。
特にデバイス。"あるある"だとは思うのですが、スライド67ページでいっていることは、
「画面下のほうにテキストフィールドがあって、テキストフィールドをタップすると下からキーボードが表示される。iPhone5でみたときはとくに問題ないが、iPhone4Sなんかでみるとキーボードがそのテキストフィールドを隠してしまう。だからそのテキストフィールドを含むビューを画面上方にキーボード入力するときのみ移動してあげなくてはいけない」というもの。

なにはともあれ"デコラージュ"をみなさんDLしていただき、楽しんでいただければ幸いです!!

iOSアプリ"1,2,3,4"をリリースしました!

"1,2,3,4"という一風変わった名前ですが、iOSアプリを個人として初めてリリースしました!

https://itunes.apple.com/us/app/1-2-3-4/id623790896?l=ja&ls=1&mt=8

簡単にいうと「写真を4枚連写して、それを縦に4コマ漫画のように並べて1つの画像を生成する」というシンプルなカメラアプリ。どんなものができあがるかというと・・・

f:id:ushisantoasobu:20130328015406j:plain

同僚がすぐさまオフィスで作ってくれました。感謝!!


アプリの細かな紹介だったり使い方はすぐに別のエントリーで書くとして、制作に関する話をここではまとめておきたいと思います。

カメラ撮影のビューをカスタマイズする

f:id:ushisantoasobu:20130328020536j:plain

上画像のようにカメラ撮影のビュー(わかりづらいですが確かにカメラを撮影しようとしているところです)を独自にカスタマイズする方法については色々なサイトをみましたが、サンプルがappleのドキュメントに載っているのでそちらを参考にしました。

http://developer.apple.com/library/ios/#samplecode/PhotoPicker/Introduction/Intro.html

大きな画像を扱ううえでの注意

カメラで撮影した画像についてあまり自分は意識していなかったのですが「2448*3264ピクセル(iPhone 4Sで撮影)」とかなり大きめです。それを4枚も扱うアプリということもあって、あるときメモリリークが発生しました。
原因はCGImageRefの解放漏れ。ARCを有効にしていても、これは自分の手で解放してあげないといけないようですね(下コードは撮影した画像を正方形にトリミングしているところの処理)。

    CGImageRef imgRef = CGImageCreateWithImageInRect(image.CGImage,rect);
    UIImage *clipedImage = [UIImage imageWithCGImage:imgRef
                                               scale:1.0f
                                         orientation:UIImageOrientationRight];
    
    //ここの解放を忘れないこと!
    CGImageRelease(imgRef);

GPUImageによるフィルター

カメラアプリということもあって、はじめてフィルター機能も入れました。

f:id:ushisantoasobu:20130328021735j:plain

下の記事を参考に"GPUImage"というライブラリを利用しました。

GPUImageで高速フィルター!iOSカメラアプリの作り方(1) ~ fantagramができるまで ~


どんな調整ができるのかなどは直接githubにいって確認しました。

https://github.com/BradLarson/GPUImage



・・・と、制作に関しての大きなポイントは以上です。
他には、偉そうにUIとかの記事も書いたりしてきたくせにいざ自分が制作してみると改めて難しいなと思ったり、申請の手順をはじめて経験できて(業務時は別の同僚が対応したため)良かったなど、色々とありますが、とりあえずリリースできて良かったです。

よければDLしていただけると嬉しいです。

iOSネイティブでのラジオボタンの是非

現在携わっているiOSネイティブ開発でデザイナーさんからあがってきたデザインに下画像のような「ラジオボタン」がありました。(まだリリースしていないため画面はTwitterのweb版のもの)


f:id:ushisantoasobu:20130301011957j:plain


ただしラジオボタンはiOSの標準コンポーネントには含まれていません。基本的にはUISegmentedControlで代用すると思います(下画像は"Kickstarter"のもの)。


f:id:ushisantoasobu:20130301012510j:plain


ラジオボタンのデザインがあがってきたときには、こちらエンジニア側のメンバーもあまり知識・経験がなかったためとくに考慮せずOKを出したのですが、このような「標準コンポーネントでできるものを別のコンポーネントに置き換えるってどうなんだろ」、というのが今回のエントリのテーマです。


今回のラジオボタンを用意するとなると、

  • オープンソースからもってくる
  • 自前で用意する(今回はこちらで対応しました)

とあると思いますが、

オープンソースのものだと
「選定の手間」「導入の手間」「ライセンス規約を考慮すること、必要であればその記載の手間」

自前で用意だと
「作成する手間」

そして両方にいえることですが
「今後もそれらを流用していくうえでの管理の手間」

という手間が発生すると思います。

主要機能などでどうしても実現したい、オリジナリティを出したい!・・・とかであれば対応する価値は十分あると思います。ただし主要機能以外のところであれば、標準コンポーネントを使用するのが上記の手間を考えるとやはり望ましいのかなと思います。

自前で実装するのはエンジニアにとって、余裕があるときであれば楽しいものであるかもしれません。ただそれでも、UXという視点からみたとき標準コンポーネントのもののほうがユーザにとっては馴染みのあるものだと思いますので、やはりできるだけ標準コンポーネントのものを使用するのがいいのではと個人的には思っています。

なのでまずはデザイナーさんに(というかチーム全体で)、何が標準コンポーネントとして用意されているのかを知ってもらう/意識してもらう必要があると思います。下画像が一覧です。


f:id:ushisantoasobu:20130301014436j:plain


f:id:ushisantoasobu:20130301014446j:plain


f:id:ushisantoasobu:20130301014457j:plain


またこれら標準コンポーネントの呼び方もチーム内で統一がとれるようにするといいと思います。
うちのチームでは開発中は"ピッカー"と"ドラムロール"がごちゃまぜで使われていたため。。。