iPhoneの片手用操作メニュー(QuadCurveMenu編)

iPhoneを片手で扱える操作用メニューを作りたいと思ったのでちょっと調べたことをメモ。

CSS で作るスマートフォン向け片手操作メニュー

これCSSとjQueryなのか、スゲー。
でも、Viewコンテナーとして作りたいんだよなー、と思ったらインスパイア元があるらしい。

ちなみに今回のやつ、デザインは Dribbble に投稿された下記がイケてたのでインスパイアされてみた。

iPhone Search Type Nav (Path Inspired) by Eric Hoffman : Dribbble


エントリーのタイトルにあるように「Path」にインスパイアされてるらしい。
「Path」ってなんぞ?
とググってみたら、ちょっと変わったSNSらしく、その「Path」のiPhoneアプリのUIにインスパイアされてるらしい。

Mobile UI Patterns – CustomNavigation

おぉ、まさにこういうメニューが作りたかったんだよ。

サンプルになりそうなソースが公開されてないか探してみた。
QuadCurveMenu for iOS : Cocoa Controls
levey / QuadCurveMenu : github
ライセンスもMIT Licenseなのでクレジット表記で改変自由。

ARC対応してないソースだったのでARC対応を再度探してみたらあった。
flubbermedia / QuadCurveMenu : github
levey氏のソースからforkしたものだ。

画面左上の配置しか無かったので、6パターンの配置になるようにソースを修正。


左上、左中、左下、右上、右中、右下の順に1~6までの数字ボタンを割り当て、タップすると配置が変更するようにしてみた。
実機で使い心地を試してみたが、親指で操作する場合は中段の配置が一番便利かな。
メニューの展開が180度開く必要があるかは微妙だけど。
邪魔にならない前提を考えると実用的なのはやっぱり下段。
あとはボタンの透明度を上げるとかすれば邪魔な感じが減るかもしれない。

ソースはfork元同様、githubで。
nalabjp / QuadCurveMenu : github

起動中プロセスの状態

Androidにおける起動中のプロセスの状態を知りたい時はRunningAppProcessInfoから知ることができる。
バックグラウンドプロセスをkillする場合等で状態チェックが必要な時に使える。
以下、ソースコード。

package com.nalabjp.example.rapi;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.os.Bundle;
import android.widget.ScrollView;
import android.widget.TextView;

public class RunningAppProcessInfoExampleActivity extends Activity {
    
    private ActivityManager manager;
    private ScrollView sc;
    private TextView tv;
    private static Map<Integer, String> importance = new HashMap<Integer, String>();
    private static Map<Integer, String> reason = new HashMap<Integer, String>();
    
    static {
    	importance.put(RunningAppProcessInfo.IMPORTANCE_FOREGROUND, "IMPORTANCE_FOREGROUND");
    	importance.put(RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE, "IMPORTANCE_PERCEPTIBLE");
    	importance.put(RunningAppProcessInfo.IMPORTANCE_VISIBLE, "IMPORTANCE_VISIBLE");
    	importance.put(RunningAppProcessInfo.IMPORTANCE_SERVICE, "IMPORTANCE_SERVICE");
    	importance.put(RunningAppProcessInfo.IMPORTANCE_BACKGROUND, "IMPORTANCE_BACKGROUND");
    	importance.put(RunningAppProcessInfo.IMPORTANCE_EMPTY, "IMPORTANCE_EMPTY");
    	reason.put(RunningAppProcessInfo.REASON_PROVIDER_IN_USE, "REASON_PROVIDER_IN_USE");
    	reason.put(RunningAppProcessInfo.REASON_SERVICE_IN_USE, "REASON_SERVICE_IN_USE");
    	reason.put(RunningAppProcessInfo.REASON_UNKNOWN, "UNKNOWN");
    }
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
        sc = new ScrollView(this);
        tv  = new TextView(this);
    	sc.addView(tv);
    	setContentView(sc);
    }
    
    @Override
    public void onResume() {
    	super.onResume();
    	searchRunningAppProcesses();
    }
    
    private void searchRunningAppProcesses() {
    	final List<RunningAppProcessInfo> apps = manager.getRunningAppProcesses();
    	StringBuilder sb = new StringBuilder();
    	for (RunningAppProcessInfo rapi : apps) {
    		StringBuilder tmp = new StringBuilder();
    		tmp.append("processName : ").append(rapi.processName).append("\n");
    		tmp.append("importance : ").append(importance.get(rapi.importance)).append("\n");
    		tmp.append("importanceResonCode : ").append(reason.get(rapi.importanceReasonCode)).append("\n");
    		tmp.append("------\n");
    		sb.append(tmp);
    	}
    	tv.setText(sb.toString());
    }
}

結果はこんな感じ。

UITextFieldDelegate

UITextFieldDelegateの動作と戻り値について調べたのでメモ。

(BOOL)textFieldShouldBeginEditing:

  • FirstResponderになる際、一番目に呼ばれるコールバック。
  • YES→FirstResponderになる。
  • NO →FirstResponderにならない。

(void)textFieldDidBeginEditing:

  • FirstResponderになる際、二番目に呼ばれるコールバック。
  • textFieldShouldBeginEditing:でNOが返却された場合は呼ばれない。

(BOOL)textFieldShoultEndEditing:

  • FirstResponderでなくなる際、一番目に呼ばれるコールバック。
  • YES→FirstResponderでなくなる。
  • NO →FirstResponderのまま。

(void)textFieldDidEndEditing:

  • FirstResponderでなくなる際、二番目に呼ばれるコールバック。
  • textFieldShoultEndEditing:でNOが返却された場合は呼ばれない。

(BOOL)textField:shouldChangeCharactersInRange:replacementString:

  • UITextFieldに変更があった際に呼ばれるコールバック。
  • YES→変更が有効になりUITextFieldに反映される。
  • NO →変更は無効になりUITextFieldには反映されない。

(BOOL)textFieldShouldClear:

  • クリアボタンがタップされたときに呼ばれるコールバック。
  • YES→UITextFieldがクリアされる。
  • NO →UITextFieldはクリアされない。

(BOOL)textFieldShouldReturn:

  • リターンキーがタップされた時に呼ばれるコールバック。
  • YES→UITextFieldの「Did End On Exit」イベントが発生する。
  • NO →UITextFieldの「Did End On Exit」イベントは発生しない。

Ricty

Rictyというフォントを使うとコードが見やすくなるというのがTLに流れてきたので入れてみることに。
軽くググってみるとMacPortsかHomebrewを使ってfontforgeを入れるのだとか。
インストール済みだったMacPortsでやってみる。

プログラミング用の見やすいフォント「Ricty」をMacとUbuntuで生成
こちらを参考にインストールしてみると、fontforgeのインストール時にXcodeのCommand Line Toolsが無いと怒られた。
Xcodeが4.3だからなのか、別途インストールしないとダメらしい。
ということで、「Xcode」->「 Open Developer Tool」 ->「 More Developer Tools」からCommand Line Toolsをインストール。
その後にfontforgeのインストールなんだけど、なんかエラー出てるし。
「fatal error: ‘/Developer/Headers/FlatCarbon/Files.h’ file not found」
/Developerなんてないよねってことでココからパッチを取得して、
/opt/local/var/macports/sources/rsync.macports.org/release/tarballs/ports/graphics/fontforge/Portfileに当てる。
これでfontforgeはインストールできた。
あとは特に問題なくRictyを生成しておしまい。

android.intent.action.BOOT_COMPLETED

android.intent.action.BOOT_COMPLETEDをintent-filterに設定していても、BOOT_COMPLETEDを検知できないことがある。
ググってみたらこんな記事が。
http://commonsware.com/blog/2011/07/13/boot-completed-regression-confirmed.html
どうやらAndroid3.1かららしい。
インストール後に一度もユーザが起動させていない場合はBOOT_COMPLETEDを拾えないようだ。
インストール直後はstoppedというstateになっているらしく、一度でもユーザが起動しているとstoppedのstateではなくなるみたい。
http://developer.android.com/intl/ja/sdk/android-3.1.html#launchcontrols
セキュリティ上の問題なのかな?

因みにandroid.intent.action.BOOT_COMPLETEDに必須のパーミッションであるandroid.permission.RECEIVE_BOOT_COMPLETEDにバグがある模様。
パーミッションがなくてもandroid.intent.action.BOOT_COMPLETEDはintent-filterに引っかかるとかで、検証したら確かにパーミッション不要でした。
http://code.google.com/p/android/issues/detail?id=14044
ICSでfixされる模様だけどどうなったんだろ?

QuasiDisk

設定を忘れた時のためのメモ。

Mac側でアドホックを作成する。
AdHoc

アドホックに接続する。
AdHocCon

iPhone側でWiFi設定からAdHocに接続する。
iPhoneAdHocCon

QuasiDiskを起動する。
電波マークをタップして設定画面を開く。
Portを「5100」に設定して「FTP Server」を有効にする。
QuasiDisk

Mac側で「ネットワーク環境設定」から「プロキシ」を設定する。
「Webプロキシ(HTTP)」と「保護されたWEBプロキシ(HTTPS)」のプロキシサーバを「[iPhoneの名前].local」、ポートを「6666」に設定する。
「SOCKSプロキシ」を「[iPhoneの名前].local」、ポートを「5050」に設定する。
proxy

以上でテザリングできるはず。

Apple Developer Program

新規にApple Developer Programを追加購入する必要があったので購入手続きを。
昔とは違いAppleIDが日本語登録でも問題なく購入できるようになってた。
AppleIDが日本語だと本国での登録時に日本語が「?」に文字化けしていたり、日本のApple Storeでの支払いは日本語で入力された情報が必要だったりと、日米でのサイトの行き来でエラーが発生してサポートに修正依頼を出したりというのが必要だったみたいだが、現在は特に気にしなくても良さそう。
今回の登録時はAppleIDは日本語で登録していて米国サイト側では文字化けしてたが、無視して手続きを進めたら問題なく購入できアクティベーションコードも普通にメールで送られてきた。
面倒な手続きが必要だったのが改善されていて良かった。
さて、プロビジョニングやり直さないとなー。

%d人のブロガーが「いいね」をつけました。