FRMSKI開発ブログ

AWS、iOS、AR/VRなど開発メモ

【Xcode 10.2 betaのSwift 5リリースノート】Swift言語のアップデート一覧

Swift Language

  • @dynamicCallable属性を使用すると、単純な構文を使用して関数を呼び出すのと同じ名前の型を呼び出すことができる。
@dynamicCallable struct ToyCallable {
    func dynamicallyCall(withArguments: [Int]) {}
    func dynamicallyCall(withKeywordArguments: KeyValuePairs<String, Int>) {}
}

let x = ToyCallable()

x(1, 2, 3)
// Desugars to `x.dynamicallyCall(withArguments: [1, 2, 3])`

x(label: 1, 2)
// Desugars to `x.dynamicallyCall(withKeywordArguments: ["label": 1, "": 2])`
  • キーパスが入力値全体を参照するWritableKeyPathをサポート。
let id = \Int.self
var x = 2
print(x[keyPath: id]) // Prints "2"
x[keyPath: id] = 3
print(x[keyPath: id]) // Prints "3"
  • Swift 5より前のバージョンでは、さまざまな引数を取る列挙型のケースを書くことができたが、代わりに、列挙型の場合を変更して配列を取得し、明示的に配列を渡す。
enum X {
    case foo(bar: [Int]) 
} 

func baz() -> X {
    return .foo(bar: [0, 1, 2, 3]) 
} 
  • Optional型の式を使用すると、ネストされたオプションを返すのではなく、結果のオプションがフラットになります。

  • UInt64(0xffff_ffff_ffff_ffff)のような式は、以前はデフォルトの整数リテラル型のIntをオーバーフローしていましたが、現在は有効です。

  • 文字列補間により、パフォーマンス、明瞭さ、および効率が向上しました。

  • Swift 4.2とSwift 5の間で#ifを使用してコードを条件付きにすることができます。次に例を示します。

#if compiler(<5)
extension MyType: _ExpressibleByStringInterpolation { /*...*/ }
#else
extension MyType: ExpressibleByStringInterpolation { /*...*/ }
#endif 

【SceneKit】SCNノードをカメラの方へ向かせる

SCNノードのベクトルを常時カメラの方へ向かせるにはSCNBillboardConstraintを使います。
下記のソースでノードのconstraintsに指定してあげます。

let billboard = SCNBillboardConstraint()
billboard.freeAxes = SCNBillboardAxis.Y //Y座標のみ追従させる
node.constraints = [billboard]

freeAxesは固定したい軸を指定する時に追記します。

【iOSデザインガイドライン和訳】起動画面(ローンチスクリーン)の常識

起動画面

 アプリが起動するとすぐに起動画面が表示されます。起動画面はすぐにアプリの最初の画面に置き換えられ、アプリが速く応答性の高い印象を与えます。起動画面は芸術表現の機会ではありません。これは、すぐに起動し、すぐに使用できるように、アプリの認識を向上させることのみを目的としています。すべてのアプリは起動画面を提供する必要があります。

 デバイスの画面サイズが異なるため、起動画面のサイズも異なります。これに対応するには、起動画面をXcodeのストーリーボードとして、またはアプリがサポートしているデバイス用の静止画像のセットとして提供できます。ストーリーボードは柔軟で適応性があるため、Xcodeストーリーボードを使用することをお勧めします。 1つのストーリーボードを使用して、すべての起動画面を管理できます。適応インターフェースの実装については、「自動レイアウトガイド」を参照してください。

  • アプリの最初の画面とほぼ同じ起動画面をデザインします
     アプリの起動が完了したときに異なるように見える要素を含めると、起動画面とアプリの最初の画面の間で不快なフラッシュが発生する可能性があります。

  • 起動画面にテキストを含めないでください
     起動画面は静的なため、表示されているテキストはローカライズされません。

  • ダウンプレイを開始
     人々はアプリを頻繁に切り替える可能性が高いので、アプリの起動に注意を払わない起動画面を設計します。

  • 宣伝しないでください
     起動画面はブランディングの機会ではありません。スプラッシュスクリーンや「バージョン情報」ウィンドウのようなエントリーエクスペリエンスをデザインしないでください。ロゴやその他のブランディング要素は、アプリの最初の画面の静的な部分以外は含めないでください。

  • 静的起動画面
     起動画面にはXcodeのストーリーボードを使用することをお勧めしますが、必要に応じて一連の静止画像を提供できます。デバイスごとに異なるサイズの静止画を作成し、ステータスバー領域を必ず含めてください。

f:id:frmski:20181213113758p:plain:w500

【iOSデザインガイドライン和訳】覚えておくと助かるシステムアイコン一覧

システムアイコン

 iOSシステムには、さまざまなユースケースで共通のタスクやコンテンツの種類を表すビルトインのアイコンが用意されています。

 これらのビルトインアイコンは、人に親しまれているので、できるだけ多く使用することをお勧めします。

  • 意図したとおりにシステムアイコンを使用してください
     すべてのシステム提供のイメージには、特定のよく知られている意味があります。ユーザーの混乱を避けるために、それぞれのイメージをその意味と推奨される使用法に従って使用することが不可欠です。

  • アイコンの代替テキストラベルを提供する
     代わりのテキストラベルは画面上には表示されませんが、VoiceOverは画面上に表示されているものを音声で表現できるため、視覚障害のある方にとってナビゲーションが容易になります。

  • あなたのニーズに合ったシステムアイコンが見つからない場合は、カスタムアイコンを設計してください  システム提供のイメージを誤用するよりも自分自身を設計する方が良いです。カスタムアイコンを参照してください。

ナビゲーションバーとツールバーのアイコン

 ナビゲーションバーとツールバーには、次のアイコンを使用します。開発者ガイダンスについては、UIBarButtonSystemItemを参照してください。

TIP
 アイコンの代わりにテキストを使用して、ナビゲーションバーまたはツールバー内の項目を表すことができます。たとえば、カレンダーはツールバーの「今日」、「カレンダー」、および「受信トレイ」を使用します。固定スペース要素を使用して、ナビゲーションとツールバーアイコンの間にパディングを提供することもできます。

f:id:frmski:20181213114744p:plain:w500 f:id:frmski:20181213114759p:plain:w500

タブバーのアイコン

 タブバーには次のアイコンを使用します。開発者向けのガイダンスについては、UITabBarSystemItemを参照してください。

f:id:frmski:20181213115121p:plain:w500

ホーム画面クイックアクションアイコン

 ホーム画面のクイックアクションメニューでは、次のアイコンを使用します。開発者ガイダンスについては、UIApplicationShortcutIconTypeを参照してください。

f:id:frmski:20181213115308p:plain:w500 f:id:frmski:20181213115248p:plain:w500 f:id:frmski:20181213115323p:plain:w500

【iOSデザインガイドライン和訳】意外と知らないカスタムアイコンのマナー

意外と知らないカスタムアイコンについてのガイドラインです。

カスタムアイコン

 アプリにシステムアイコンで表現できないタスクやモードが含まれている場合や、システムアイコンがアプリのスタイルと一致しない場合は、独自のアイコンを作成できます。

  • 認識しやすく、高度に単純化されたデザインを作成してください
     詳細が多すぎると、アイコンが混乱したり読めなくなったりすることがあります。ほとんどの人がすぐに認識し、不快にならないシンプルでユニバーサルなデザインを目指してください。より良いアイコンは、開始するアクションまたはそれが明らかにするコンテンツに直接関係する親しみやすい視覚的メタファを使用します。

f:id:frmski:20181213110332p:plain:w300

  • グリフとしてのアイコンのデザイン
     グリフは、テンプレート画像とも呼ばれ、透過性、アンチエイリアス、マスクを使用して形状を定義するドロップシャドウなしの単色画像です。グリフは、文脈やユーザーとのやりとりに基づいて、適切な外観(着色、ハイライト、活気など)を自動的に受け取ります。ナビゲーションバー、タブバー、ツールバー、ホーム画面のクイックアクションなど、さまざまな標準インターフェイス要素がグリフをサポートしています。

  • グリフを@ 2xの倍率で準備し、PDFとして保存
     PDFは高解像度のスケーリングを可能にするベクトル形式なので、通常はアプリで@ 2xの単一のバージョンを用意し、他の解像度のために拡大縮小することができます。

  • アイコンの一貫性を保つ
     カスタムアイコンのみを使用する場合でも、カスタムアイコンとシステムアイコンを組み合わせる場合でも、アプリ内のすべてのアイコンは、詳細レベル、光学重量、ストロークウェイト、位置、およびパースペクティブの点で同じである必要があります。

f:id:frmski:20181213110633p:plain:w300

  • アイコンが見やすいことを確認してください
     一般に、ソリッドアイコンはアウトラインアイコンよりも明確になる傾向があります。アイコンに線が含まれている必要がある場合は、他のアイコンとアプリのタイポグラフィとの重さを調整します。

f:id:frmski:20181213110752p:plain:w300

  • 選択した状態と選択解除した状態を連携するには、色を使用します
     ソリッドバージョンとアウトラインバージョンのような、2つの異なるアイコンデザインの切り替えは避けてください。

  • アイコンにテキストを含めないでください
     テキストが必要な場合は、アイコンの下にラベルを表示し、それに応じて配置を調整します。

  • Appleハードウェア製品の複製は使用しないでください
     アップル製品は著作権で保護されており、アイコンや画像で再現することはできません。一般的には、ハードウェアのデザインが頻繁に変更される傾向があり、アイコンが日付表示になる可能性があるため、デバイスの複製を表示しないでください

  • アイコンの代替テキストラベルを提供する
     代わりのテキストラベルは画面上には表示されませんが、VoiceOverは画面上に表示されているものを音声で表現できるため、視覚障害のある方にとってナビゲーションが容易になります。

カスタムアイコンのサイズ

 とりわけ、あなたのアプリのアイコンファミリは視覚的に一貫している必要があります。個々のアイコンのデザインの重さが異なる場合、この効果を達成するために、一部のアイコンを他のアイコンのデザインよりもわずかに大きくする必要があります。

f:id:frmski:20181213111247p:plain:w300

ナビゲーションバーとツールバーのアイコンサイズ

 カスタムナビゲーションバーとツールバーのアイコンを準備する際には、以下のサイズを参考にしてください。必要に応じてバランスを調整してください。

Target sizes Maximum sizes
72px × 72px (24pt × 24pt @3x) 84px × 84px (28pt × 28pt @3x)
48px × 48px (24pt × 24pt @2x) 56px × 56px (28pt × 28pt @2x)

タブバーのアイコンサイズ

 縦向きでは、タブタイトルの上にタブバーアイコンが表示されます。横向きの向きでは、アイコンとタイトルが並べて表示されます。デバイスと向きに応じて、通常のタブバーまたはコンパクトタブバーが表示されます。あなたのアプリには、両方のサイズのカスタムタブバーアイコンが含まれている必要があります。

f:id:frmski:20181213111614p:plain:w300

【ARKit】3D空間座標をスクリーン座標に変換する

ARの空間座標をスクリーン座標に変換する関数を紹介します。
ARSCNViewのprojectPointで取得できます。
下記ソースです。

func getScreenPointfromARPos(sceneView:ARSCNView , pos:SCNVector3) -> CGPoint
{
    let screenPos = sceneView.projectPoint(pos)
    let point = CGPoint(x: CGFloat(screenPos.x), y: CGFloat(screenPos.y))
    return point
}