iOS7用のホームアイコンの設定
もうすぐiOS7がリリースされるそうなので、 Webアプリでホーム用アイコンを設定しているプロジェクトは アイコンのデザイン調整の対応を検討しないとなーと思って調べたメモです。
iOS6/5用と iOS7用の切替方法
iOS6/5用のアイコンは 114px四方なのに対してiOS7用のアイコンは120px四方なので、 link要素(rel=apple-touch-icon)のsizes属性で各OS用に切り替えることができそうです。
参考)http://blog.fonland.net/2011/02/iphone-ipad-apple-touch-iconpng.html
調整が必要なデザインは?
iOS7のアイコンは角丸の具合をふくめたアウトラインと内部のグリッドが変わったので、 角丸に合わせたスタイリングがしてあるものとか四隅に要素が隣接しているものは調整したほうが良い気がしました。
いったんiOS7の端末にインストールしてみてから検討すればいいと思いますが、 個人的にはフラットかどうかよりも四隅の余白のバランスに違和感を感じるものが多かったです。
納品後のプロジェクトとかでも、こういうのは対応してあげたいんですけどねー。
iOSアプリのモックアップをWebView(ローカル)で作ってみた。
今回はネットワークに繋がない端末でモックアップをインストールしたかったので、UIWebViewからローカルにバンドルしたHTMLを呼び出すだけのiOSアプリを作成しました。 もとのHTMLはテストサイトとかで作っていた画面遷移を確認する程度のWebアプリです。
- Single View Applicationのテンプレートで新規プロジェクト作成する
- UIWebViewを配置しViewControllerをdelegateに設定する
- ViewControllerにwebviewプロパティを定義しOutletとして接続しておく
- ViewControllerにUIWebviewDelegateプロトコルを実装する
- ViewContorllerのviewDidAppearあたりでアプリのリソースバンドル内のHTMLファイルを指定する。
NSURLを生成するときにネットワーク上のアドレスではなく、ファイルパスを渡すためURLWithStringの代わりにfileURLWithPathを呼び出す。
あと、HTMLと画像やJSなどのリソースがすべてバンドル内のルート(?)に展開されるそうなので、 ブラウザ用に作っていたものを転用する場合、HTMLやCSSのパスをバンドルされた状態にあわせて調整する必要がある。(./js/index.js -> ./index.js) (名前がかぶった時とかどうなるんだろう…検証してませんが。)
参考)http://waka.hatenablog.com/entry/2012/11/21/091037
また、JSがコンパイルするリソースとして設定されてしまうので、適宜、コピーするリソースのほうに移動してあげる必要があるそうです。コンパイルされるほうはリソースはあるけどバンドルリソースとしてアクセスできないので。
参考)http://d.hatena.ne.jp/KishikawaKatsumi/20091229/1262052856
見せられませんが、JSでサクッとつくったものがわりと綺麗にアプリっぽくなったので全部出来る人がつくるぶんにはいい方法だな、と思いました。
iOS SafariでドラッグするとrequestAnimationFrameが止まる件
JSでrequestAnimationFrameを使ってアニメーションさせるとき、 ネイティブのスクロールが発生するとスクロール中はrequestAnimationFrameが一時的に止まるらしい。厳密にはする時としないときがあった。
スワイプジェスチャーを実装してドラッグに応じてアニメーションさせようとしていたのですが、 要はブラウザがスクロールするとザ・ワールド!してしまうという感じらしい。 困った。
今回はフルスクリーン想定なのでtouchmoveでe.preventDefault()すればよかったが、 ネイティブのスクロールと併用すると困るパターンが出てきそう。
@doke touchstartでpreventDefaultして、ネイティブのスクロール殺せばいけませんでしたっけ
— げこたん (@GeckoTang) 2013, 9月 12
@GekoTangの言うとおりtouchstartでpreventDefaultでも良いのだけど、それだと子要素のclickイベントも死んでしまうため、touchmoveでスクロール抑止しました。
CGRectをオフセットする方法
描画用のCGRectを用意する際に、イラレ的な感覚で矩形をオフセット(ピクセル単位でパスを拡張)したかったのですが、
CGRectOffsetかと思いきや、CGRectInsetを使うと簡単にできました。
GCRect CGRectInset(CGRect rect, CGFloat dx, CGFloat dy)
もとのCGRectと、内側に拡張したい数値を入れると新しいCGRectが生成されます。
dx, dyをマイナスにすると外側に広がった矩形が生成できます。
CGRect rect = CGRectMake(0, 0, 100, 100); CGRect insetRect = CGRectInset(rect, 10, 10); NSLog(@"CGRectInset %@",NSStringFromCGRect(insetRect)); //CGRectInset {{10, 10}, {80, 80}}
drawRectメソッドの中などで枠線の幅を考慮した計算が必要になることがありますが
そういう描画用の矩形を生成するときに便利です。
CGRectOffsetはIFが似てますが、始点(rect.origin)を動かしたCGRectを作る関数みたいです。
GCRect CGRectInset(CGRect rect, CGFloat dx, CGFloat dy)
CGRect rect = CGRectMake(0, 0, 100, 100); CGRect offsetRect = CGRectOffset(rect, 10, 10); NSLog(@"CGRectOffset %@",NSStringFromCGRect(insetRect)); //CGRectOffset {{10, 10}, {100, 100}}
Indexを管理するモデル@AS3版
Flashでモックつくっていてカルーセルとかスライドショー的なものを汎用化していったらIndex.asっていうのを作る感じになったので公開してみるです。
Index.as
package { import flash.events.EventDispatcher; import flash.events.Event; public class Index extends EventDispatcher { private var _index:int = 0; private var _min:int = 0; private var _max:int = 0; private var _length:int = 0; private var _loop:Boolean = false; public function Index(min:int = 0, max:int = 0, loop:Boolean = false) { updateRange(min, max); _loop = loop; } public function set index(newIndex:int):void { newIndex = validate(newIndex); if (_index != newIndex) { _index = newIndex; dispatchEvent(new Event(Event.CHANGE)); } } public function get index():int { return _index; } public function next():void { index++; } public function prev():void { index--; } public function range(min:int, max:int, uselessRefresh:Boolean = false):void { updateRange(min, max); if (!uselessRefresh) { index = index; } } public function set loop(value):void { _loop = value; } public function get loop():Boolean { return _loop; } public function get isMin():Boolean { return index === _min; } public function get isMax():Boolean { return index === _max; } private function updateRange(min:int, max:int):void { _min = min; _max = max; _length = _max - _min + 1; } private function validate(value:int):int { if (isNaN(value)) return _index; if (_loop) { value -= _min; value %= _length; if (value < 0) value += _length; return value + _min; } else { return Math.min(Math.max(value, _min), _max); } } } }
使い方
下の例では、ViewがIndexインスタンスのCHANGEイベントを受け取って更新されるようにしてます。
package { import flash.events.Event; import flash.display.Sprite; public class SlideBase extends Sprite { private var _model:Index; public function SlideBase(size:int = 3) { _model = new Index(0, size - 1, true); //loop == true _model.addEventListener(Event.CHANGE, onChangeIndex); // initialize onChangeIndex(null); } public function next(): void { _model.next(); } public function prev(): void { _model.prev(); } public function index(value:int): void { _model.index = value; } public function loop(value:Boolean): void { _model.loop = value; } private function onChangeIndex(event:Event):void { updateDisplay(_model.index); } protected function updateDisplay(index:int):void { // indexを使って見た目を更新する } } }
あとはボタンのCLICKイベント、キーボードイベント、タイマーイベントなど何かしらのタイミングでmodelを操作すればViewが切り替わるので、かなり柔軟でしかもスッキリ書けるようになります。
import flash.events.MouseEvent; var slide:SlideBase = new SlideBase(); addChild(slide); setInterval(function () { slide.next(); }, 10000); addEventListener(MouseEvent.CLICK, function (event:MouseEvent) { slide.next(); });
解説
機能要件
- index、min、maxあたりのプロパティを持ってる
- next(), prev(), index()的なI/Fを持っている
- loop処理、 範囲に応じたtrim処理あたりをよしなにやってくれる
- イベント発行する機能を持っている
あと最大値かどうか、最小値かどうかを返すメソッドを追加したあたりでまとめてみました。
実装
- 各プロパティはカプセル化する。indexはget/setアクセサを提供
- loopはフラグにして、値が変更された時にmin/maxでtrimするかループさせるかをうまいことやる
- AS3なのでEventDispatcherを継承するだけ。index値に変化があればEvent.CHANGEイベントを発行
という感じ。
工夫したところ
特に難しいことはないですが、ループする場合にすこし工夫が必要でした。
普通はindex値を範囲の長さで割った余りでシンプルに表現できるんだけど、
index値がマイナスになっちゃったりするとちょっとややこしいです。
ループさせたい範囲が min 0 ~ max 2 (長さ3)の場合で考えてみます。
値をnextしていくとき(index > 0になりうる場合)
var length = 3; var newIndex = index % length; // 0 % 3 => 0 // 1 % 3 => 1 // 2 % 3 => 2 // 3 % 3 => 0 // 4 % 3 => 1 // ...
値をprevしていくとき(index < 0になりうる場合)
var newIndex = index % length; // 0 % 3 => 0 // -1 % 3 => -1 // ループ的には2であってほしい // -2 % 3 => -2 // ループ的には1であってほしい // -3 % 3 => 0 // 3の倍数の時は問題なさげ // ...
というふうに、0 から prev()したときに、期待する挙動としては 2に戻ってほしいのに -1を3で剰余すると−1になってしまってうまくいかない。
でもよく見ると、結果値がマイナスのとき、結果値から期待値を引くと常に-3になる。
結果値 - 期待値 = -3
これを期待する値に合わせて整理すると
期待値 = 3 + 結果値
という事になるので、もし結果値がマイナスだったら、剰余する値を1度足せばうまくループしてくれるぽい。
var length = 3; var newIndex = index % length; if (newIndex < 0) newIndex += length;
検算
- 0 % 3 = 0
- -1 % 3 + 3 = -1 + 3 = 2
- -2 % 3 + 3 = -2 + 3 = 1
- -3 % 3 = 0 = 0
- -4 % 3 + 3 = -1 + 3 = 2
- -5 % 3 + 3 = -2 + 3 = 1
- ...
とりあえずいきなり大きいマイナス値を入れても何とかなりそうです。
FlashでもJSでも地味にややこしいところなので整理してみました。
前回Backbone.jsで似たようなものを書いていますが、次はもちょっとちゃんとした版としてJSに移植してみます。
Androidでoverflowした要素をスクロール可能にするjQueryプラグイン
Androidでoverflowするとスクロールできない問題を解決するためにつくりました。
使い方
#hoge { overflow:auto;//Androidは強制的にhidden的な挙動になる width:320px; height:400px; }
$("#hoge"). overflowScroll();
iOSでもoverflowを設定すると慣性スクロールが効かなくなるので有用かもしれませんが、
よほどでなければUAを判定してAndroidだけ適応するほうがいいと思います。
仕組み
touchStartで取得したポイントをと現在の指の位置の差分をscrollTopに設定しているだけです。
模式的に書くと次のようなかんじです。
タッチ開始
$target.on("touchStart", function(event) { event = event.originalEvent; var touch = event.touches[0]; touchStartX = touch.pageX; touchStartY = touch.pageY; });
タッチ中(ドラッグ中)
$target.on("touchMove", function(event) { event = event.originalEvent; var touch = event.touches[0]; touchX = touch.pageX; touchY = touch.pageY; $target.scrollLeft(touchStartX - touchX); $target.scrollTop(touchStartY - touchY); });
タッチ完了
$target.on("touchEnd", function(event) { event = event.originalEvent; var touch = event.touches[0]; touchStartX = touch.pageX; touchStartY = touch.pageY; //何かあれば });
実際にはtouchEndで直前の touchX/touchYとの差分をもとに話した時の指の速度を割り出し
それをもとに慣性スクロールっぽくするよう試みてます。
$target.on("touchEnd", function(event) { event = event.originalEvent; var touch = event.changedTouches[0]; touchSpeedX = (touchX - touch.pageX); touchSpeedY = (touchY - touch.pageY); intervalID = setInterval(afterMoving, INTERVAL_TO_MOVE); });
function afterMoving() { //速度があまりにも小さくなったら止まったことにする。 if ((Math.abs(touchSpeedX)<LIMIT_TO_STOP && Math.abs(touchSpeedY)<LIMIT_TO_STOP)) { clearInterval(intervalID); return; } var oldX = $target.scrollLeft(), oldY = $target.scrollTop(); //摩擦係数をかけて減速 touchSpeedX *= FRICTION; touchSpeedY *= FRICTION; $target.scrollLeft(oldX + Math.round(touchSpeedX)); $target.scrollTop(oldY + Math.round(touchSpeedY)); }
iOS開発の日本語ドキュメントを分類してみた
iOS開発の日本語のドキュメントの一覧が見づらかったので、自分的にわかりやすいまとまりにしてみた。
https://developer.apple.com/jp/devcenter/ios/library/japanese.html
全部読んでいないので、適宜直していこうと思います。
Objective-Cについて
Objective-Cプログラミングの概念
https://developer.apple.com/jp/devcenter/ios/library/documentation/CocoaEncyclopedia.pdf
Objective-Cによるプログラミング
https://developer.apple.com/jp/devcenter/ios/library/documentation/ProgrammingWithObjectiveC.pdf
Objective-C プログラミング言語
https://developer.apple.com/jp/devcenter/ios/library/documentation/ObjC.pdf
iOSに関するガイドライン系
Cocoa向け コーディングガイドライン
https://developer.apple.com/jp/devcenter/ios/library/documentation/CodingGuidelines.pdf
iOSアプリケーション プログラミングガイド
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html
iOS ヒューマンインターフェイス ガイドライン
https://developer.apple.com/jp/devcenter/ios/library/documentation/MobileHIG.pdf
iOS アクセシビリティ プログラミング ガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/iPhoneAccessibility.pdf
アプリケーションの配布に関するガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/AppDistributionGuide.pdf
App Store デベロッパ向け マーケティング/広告ガイドライン
https://developer.apple.com/appstore/marketing/AppStoreMarketingGuidelines-JP.pdf
iOSテクノロジーの構成要素の話
iOS テクノロジーの概要
https://developer.apple.com/jp/devcenter/ios/library/documentation/iPhoneOSTechOverview.pdf
SDK互換性ガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/cross_development.pdf
iOS 構成プロファイルリファレンス
https://developer.apple.com/jp/devcenter/ios/library/documentation/iPhoneConfigurationProfileRef.pdf
無線経由のプロファイル配信と構成
https://developer.apple.com/jp/devcenter/ios/library/documentation/iPhoneOTAConfiguration.pdf
iOSプログラミングの基本的な話
文字列操作プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/Strings.pdf
キー値コーディングプログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/KeyValueCoding.pdf
キー値監視プログラミングガイド
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html
Blocksプログラミングトピックス
https://developer.apple.com/jp/devcenter/ios/library/documentation/Blocks.pdf
高度なメモリ管理プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/MemoryMgmt.pdf
並列プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/ConcurrencyProgrammingGuide.pdf
スレッドプログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/Multithreading.pdf
ファイルシステム プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/FileSystemProgrammingGuide.pdf
ファイルメタデータ検索プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/SpotlightQuery.pdf
位置情報対応プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/LocationAwarenessPG.pdf
iOSイベント処理ガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/EventHandlingiPhoneOS.pdf
iOS View プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/ViewPG_iPhoneOS.pdf
iOS Scroll View プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/UIScrollView_pg.pdf
iOS View Controller プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/ViewControllerPGforiOS.pdf
iOS View Controllerカタログ
https://developer.apple.com/jp/devcenter/ios/library/documentation/ViewControllerCatalog.pdf
iOS Table View プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/TableView_iPhone.pdf
Collection View プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/CollectionViewPGforIOS.pdf
Cocoa Auto Layout ガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/AutolayoutPG.pdf
Core Dataプログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/CoreData.pdf
iOS ドキュメントベース アプリケーション プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/DocumentBasedAppPGiOS.pdf
iOS マルチディスプレィ プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/WindowAndScreenGuide.pdf
ネットワーキング コンセプト
https://developer.apple.com/jp/devcenter/ios/library/documentation/NetworkingConcepts.pdf
ネットワーキング オーバービュー
https://developer.apple.com/jp/devcenter/ios/library/documentation/NetworkingOverview.pdf
ネットワーキング プログラミング トピックス
https://developer.apple.com/jp/devcenter/ios/library/documentation/NetworkingTopics.pdf
描画まわりの話
iOS描画および印刷ガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/DrawingPrintingiOS.pdf
Quartz 2D プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/drawingwithquartz2d.pdf
iOS OpenGL ES プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/OpenGLES_ProgrammingGuide.pdf
Core Animationプログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/CoreAnimation_guide.pdf
アニメーションのタイプとタイミング
https://developer.apple.com/jp/devcenter/ios/library/documentation/Animation_Types_Timing.pdf
サウンド周りの話
Core Audio の概要
https://developer.apple.com/jp/devcenter/ios/library/documentation/CoreAudioOverview.pdf
AV Foundationプログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/AVFoundationPG.pdf
Audio Session プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/AudioSessionProgrammingGuide.pdf
各機能の実装の話
iPodライブラリアクセス プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/iPodLibraryAccess_Guide.pdf
iOSカメラプログラミングトピックス
https://developer.apple.com/jp/devcenter/ios/library/documentation/CameraAndPhotoLib_TopicsForIOS.pdf
Local および Push Notification プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/RemoteNotificationsPG.pdf
Passbookの概要
https://developer.apple.com/jp/devcenter/ios/library/documentation/Getting_Started_with_Passbook.pdf
Passbook プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/PassKit_PG.pdf
iAd プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/iAd_Guide.pdf
カレンダーとリマインダーのプログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/EventKitProgGuide.pdf
Game Center プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/GameKit_Guide.pdf
iOS Address Book プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/AddressBookProgrammingGuideforiPhone.pdf
iCloud設計ガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/iCloudDesignGuide.pdf
iTunes Connect デベロッパガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/iTunesConnect_Guide.pdf
In App Purchase プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/StoreKitGuide.pdf
チュートリアル
iOS Core Dataチュートリアル
https://developer.apple.com/jp/devcenter/ios/library/documentation/iPhoneCoreData01.pdf
初めての iOS アプリケーション
https://developer.apple.com/jp/devcenter/ios/library/documentation/iPhone101.pdf
2つ目のiOSアプリケーション:ストーリーボード
https://developer.apple.com/jp/devcenter/ios/library/documentation/SecondiOSAppTutorial.pdf
3つ目のiOSアプリケーション:iCloud
https://developer.apple.com/jp/devcenter/ios/library/documentation/iCloud101.pdf
App Storeへの登録に関するチュートリアル
https://developer.apple.com/jp/devcenter/ios/library/documentation/YourFirstAppStoreSubmission.pdf
ツールの話
Xcodeユーザーガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/Xcode_User_Guide.pdf
Xcode ユニットテスト ガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/UnitTesting.pdf
iOSシミュレータ ユーザーガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/iOSSimulatorUserGuide.pdf
Instrumentsユーザガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/InstrumentsUserGuide.pdf
Instruments新機能ユーザガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/WhatsNewInstruments.pdf