WWDC Quick Look 💓 By SwiftGGTeam
Discoverable design

Discoverable design

元の動画を見る

ハイライト

Apple は、Toasty の例を使用して、機能の優先順位付け、視覚的な合図の提供、ジェスチャーのプロンプト、ユーザーの行動によるコンテンツの整理、パーソナライズされた推奨事項のユーザー制御の提供という、見つけやすいデザインのための 5 つの方法を概説しています。

主要内容

多くのアプリが同じ問題を抱えています。機能は完成しているのに、ユーザーはその存在を知りません。

最も一般的な解決策はオンボーディングです。アプリを開き、ユーザーに手順のいくつかの画面を表示します。 Toast アプリ Toasty でもこの問題が発生しました。トーストのレシピを参照したり、友人が作ったトーストを表示したり、写真を撮ってレシピを生成したりできます。

これらの機能を紹介ページに 1 つずつ詰め込んでしまうと、ユーザーは直接スキップしてしまう可能性が高くなります。ユーザーが読み終わったとしても、数分後には思い出せなくなる可能性があります。

Apple がこのセッションで示した方向性は、「インターフェイス自体がすべてを語るべきだ」というものでした。ユーザーは画面を見たときに、行動を起こす前に何ができるのか、どのように実行すればよいのかを理解できる必要があります。

関数リストからユーザーターゲットに戻る

Toastyには多くの機能があります。レシピの閲覧、マイレシピの表示、レシピ生成のための写真の撮影、検索、設定、Aboutページはすべて重要であると言えます。

これらをすべてホームページに配置すると、インターフェースが混雑してしまいます。全てハンバーガーメニューに含まれていると、入り口が見えなくなります。

Apple のアプローチは、まずユーザーの目的によって分類することです。レシピを参照し、最もよく使用されるレシピを下部のタブ バーに表示します。レシピを生成するために写真を撮ることは重要ですが、それは「マイレシピ」内のアクションであるため、このページの上部に配置されています。設定や個人の好みはあまり変更されないため、プロフィール アイコンの後ろに配置できます。

ここでの判断基準は非常に具体的で、その機能がアプリの中核に属するか、ユーザーが頻繁に使用するか、入り口の場所が指で届くかどうかなどです。

ブート ページをインターフェイス ヒントに置き換えます。

見つけやすいデザインでは、すべてのキャプションを削除する必要はありません。

ユーザーが必要とする場所に指示を表示する必要があります。アイコンが不明瞭な場合は、テキスト ラベルを追加します。検索ボックスでは何を入力すればよいのかわかりません。「食材、場所、友達で検索してください」というプロンプトが表示されるだけです。カメラ機能では、ユーザーがトーストを正しい位置に置き、カメラ画面に輪郭を表示し、シャッター ボタンを無効にし、適切な角度になったときにアニメーションと触覚フィードバックを与える必要があります。

これは、紹介ページで事前に伝えるよりも簡単です。同じ情報は、ユーザーが操作している場合にのみ役立ちます。

パーソナライズされた推奨事項も制御可能でなければなりません

Toasty には機械学習に関する推奨事項もあります。ユーザーの好みのレシピに基づいて Tasty Picks (パーソナライズされた推奨事項) を生成します。

レコメンダー システムの問題は、ソースが透明ではないことです。ユーザーは一連のトーストを見ても、それが編集者の選択なのか、機械学習の結果なのか、あるいは修正方法がわかりません。

Appleのアプローチは、「アボカドトーストを追加したから」など、理由を書き出すことです。ユーザーは、そのレコメンデーションが自分が追加したアボカド トーストから来ていることを知っています。次に、[提案の編集] ボタンを提供して、ユーザーが [アボカド トーストの提案を減らす] または [アボカド トーストの提案を停止] を選択できるようにします。

推奨事項は透明性が必要です。ユーザーがソースを理解し、結果を変更できる場合にのみ、そのソースを信頼し続けることができます。

詳細

このセッションにはコード スニペットは提供されません。デザイン手法の話です。次に、実行可能な SwiftUI プロトタイプを使用して、主要なメソッドをインターフェイス構造にトランスクリプトで実装します。この例では、システム コントロールとコピーのみを使用しており、説明に存在しないカスタム API は紹介しません。

1. 機能を重要度ごとに並べる

(03:18) Apple の第一原則は、重要な機能を優先することです。コア機能はすぐに表示され、非コア機能はもう一度ナビゲートできるようになります。

Toasty はすべての機能を 1 つの画面に詰め込んでいるわけではなく、ハンバーガー メニューにも収まりません。 「おすすめ」と「マイレシピ」をタブバーに、「新しいレシピ」をマイレシピページの上部に、そして個人の好みをプロフィールアイコンに配置します。

import SwiftUI

struct ToastyAppView: View {
    var body: some View {
        TabView {
            ForYouView()
                .tabItem {
                    Label("For You", systemImage: "sparkles")
                }

            RecipesView()
                .tabItem {
                    Label("Recipes", systemImage: "book")
                }
        }
    }
}

struct ForYouView: View {
    var body: some View {
        NavigationView {
            List {
                Section("Tasty Picks") {
                    Text("Restaurant toast near you")
                    Text("Toast shared by friends")
                }
            }
            .navigationTitle("For You")
            .toolbar {
                Button {
                    showProfile()
                } label: {
                    Image(systemName: "person.crop.circle")
                }
            }
        }
    }
}

struct RecipesView: View {
    var body: some View {
        NavigationView {
            List {
                Button {
                    captureToast()
                } label: {
                    Label("New", systemImage: "camera")
                }

                Section("My Recipes") {
                    Text("Avocado toast")
                    Text("Blueberry toast")
                }
            }
            .navigationTitle("Recipes")
            .searchable(text: .constant(""), prompt: "Search ingredients, places, or friends")
        }
    }
}

func showProfile() {}
func captureToast() {}

キーポイント:

  • TabView最も重要で最も頻繁に使用される 2 つのページを下部のタブ バーに配置し、ユーザーがアプリを開いたときにそれらのページが表示されるようにします。
  • Label("For You", systemImage: "sparkles")アイコンの意味が不明瞭になるのを避けるために、テキストとアイコンの両方を提供します。
  • toolbarプロフィール ボタンには個人的な設定が含まれており、頻繁に変更されないコンテンツに適しています。
  • ButtonつけるRecipesViewリストの一番上にあるをクリックすると、「レシピを生成する写真」が関連ページ内で目立つようになります。
  • .searchableprompt検索ボックスが空白で何を検索すればよいかわからないという問題を解決するための入力例を示します。

2. テキスト、アイコン、コンテキストを使用して視覚的な手がかりを提供する

(08:12) 2 番目の原則は視覚的な合図です。視覚的なキューの役割は、要素が何であるか、要素で何ができるのか、いつ実行する必要があるのか​​をユーザーに伝えることです。

Apple は Toasty で 3 つの例について言及しています。下部のタブ バーのアイコンにはテキスト ラベルが必要です。カメラとは、写真を撮ったり、文書をスキャンしたり、QR コードをスキャンしたりすることを意味する場合があるため、カメラ アイコンだけではカメラ ボタンとしては十分ではありません。検索ボックスでは、食材、場所、友人で検索するようユーザーに促す必要があります。

import SwiftUI

struct DiscoverableSearchView: View {
    @State private var query = ""

    var body: some View {
        NavigationView {
            List {
                Section("Try searching") {
                    Text("Ingredients")
                    Text("Places")
                    Text("Friends")
                }

                Section("Actions") {
                    Button(action: captureToast) {
                        Label("New", systemImage: "camera")
                    }
                }
            }
            .navigationTitle("Toasty")
            .searchable(
                text: $query,
                prompt: "Search ingredients, places, or friends"
            )
        }
    }
}

func captureToast() {}

キーポイント:

  • @State private var query検索入力を保存すると、サンプルを SwiftUI で直接実行できます。
  • Section("Try searching")ユーザーが入力を開始しやすいように、インターフェイスに検索可能なコンテンツ タイプを提供します。
  • Label("New", systemImage: "camera")「新規」を使用してカメラ ボタンを記述すると、新しいレシピが作成されます。
  • .searchablepromptトランスクリプト内の「材料、場所、または友人」のプロンプトをシステムの検索ボックスに入力します。
  • NavigationViewそしてList一般的な iOS 構造を使用して、ユーザーの学習コストを削減します。

3. ジェスチャーをショートカットとして使用し、アニメーション プロンプトを使用する

(12:59) 3 番目の原則は、ジェスチャーでのヒントです。ジェスチャを使用するとナビゲーションがスムーズになりますが、ジェスチャ自体は目に見えません。

Apple のアドバイスは単純明快です。プラットフォームの標準ジェスチャの使用を優先します。カスタム ジェスチャは現実世界に近いものである必要があります。ジェスチャはショートカットとしてのみ使用する必要があり、表示されるボタンを置き換えるべきではありません。

Toasty のレシピ詳細ページでは、クリアな戻るボタンを維持しながら、下にスライドしてリストに戻ることができます。 「戻る」ボタンをクリックすると、アニメーションの方向も下向きになり、ユーザーが下にスライドできることがわかります。

import SwiftUI

struct RecipeDetailView: View {
    @Environment(\.dismiss) private var dismiss
    @State private var offsetY: CGFloat = 0

    var body: some View {
        VStack(spacing: 24) {
            Button("Back to recipes") {
                withAnimation(.easeInOut) {
                    offsetY = 700
                }
                dismiss()
            }

            Text("Avocado toast")
                .font(.largeTitle)

            Text("Swipe down as a shortcut to go back.")
                .foregroundStyle(.secondary)
        }
        .offset(y: offsetY)
        .gesture(
            DragGesture()
                .onEnded { value in
                    if value.translation.height > 120 {
                        dismiss()
                    }
                }
        )
    }
}

キーポイント:

  • @Environment(\.dismiss)システムが提供するシャットダウン機能を使用して、明確なリターン パスを保持します。
  • Button("Back to recipes")これは主要な操作の入り口であり、ユーザーは最初にジェスチャを見つける必要はありません。
  • withAnimation(.easeInOut)ボタンをクリックした後の移動方向とスライドジェスチャを一致させます。
  • .offset(y: offsetY)「下にスワイプして戻る」方向に合わせて、ビューを下に移動します。
  • DragGestureユーザーがしきい値を超えて滑り落ちた場合にのみトリガーされますdismiss(), ジェスチャーはショートカットです。

4. ユーザーの行動に基づいて大量のコンテンツを整理する

(17:37) 4 番目の原則は、行動によって組織化することです。コンテンツが大量にある場合、分類はデータ フィールドだけを調べることはできず、ユーザーが実際にコンテンツをどのように発見するかにも依存します。

トースティはもともと、アボカドやブルーベリーなどの材料によって分類されていました。しかし、成分の組み合わせが多すぎるため、ユーザーは分類に圧倒されてしまうでしょう。その後、レストランのおすすめ、友人の共有、おいしいおすすめに変更されました。最初の 2 つのカテゴリは、新しいレストランを試す、友人のおすすめを聞くなど、実際の行動から来ています。 3 番目のカテゴリは、パーソナライズされた推奨事項から来ています。

import SwiftUI

struct ToastCategory: Identifiable {
    let id = UUID()
    let title: String
    let items: [String]
}

struct BehaviorBasedContentView: View {
    let categories = [
        ToastCategory(
            title: "From restaurants",
            items: ["Cafe avocado toast", "Market tomato toast"]
        ),
        ToastCategory(
            title: "Shared by friends",
            items: ["Mylène's blueberry toast", "Jiabao's banana toast"]
        ),
        ToastCategory(
            title: "Tasty Picks",
            items: ["Suggested sesame toast", "Suggested honey toast"]
        )
    ]

    var body: some View {
        List(categories) { category in
            Section(category.title) {
                ForEach(category.items, id: \.self) { item in
                    Text(item)
                }
            }
        }
        .navigationTitle("For You")
    }
}

キーポイント:

  • ToastCategory表示されるカテゴリを表します。カテゴリ名はユーザーの行動シナリオから取得されます。
  • From restaurants対応するトランスクリプトでは、ユーザーはレストランを通じて新しいトーストを発見します。
  • Shared by friends友人が勧めた発見パスに対応します。
  • Tasty Picks機械学習の推奨事項によって生成されたパーソナライズされたコンテンツに対応します。
  • Section(category.title)見出しを使用してコンテンツをグループ化すると、ユーザーはカテゴリの境界を一目で確認できます。

5. ユーザーがレコメンデーション システムを理解して制御できるようにする

(22:35) 5 番目の原則は、コントロールしているという感覚を伝えることです。ユーザーは、推奨事項がどこから来たのかを知り、不要な推奨事項を変更できる必要があります。

Apple は明示的なフィードバックと暗黙的なフィードバックを区別しています。明示的なフィードバックとは、ユーザーが多かれ少なかれ見たいものをシステムに積極的に伝えることです。暗黙的なフィードバックは、レシピの表示、トーストの共有、レシピの追加などのユーザーのアクションから得られます。

Toasty は最終的に、「このようなトーストを提案してください」「アボカド トーストを追加したためです」「提案を編集してください」という、より明確なコピーで結果を説明します。

import SwiftUI

struct RecommendationControlView: View {
    @State private var showingEditOptions = false

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Tasty Picks")
                .font(.title)

            HStack {
                Text("Because you added avocado toast")
                    .foregroundStyle(.secondary)

                Button("Edit suggestion") {
                    showingEditOptions = true
                }
            }

            Text("Banana avocado toast")
                .font(.headline)

            HStack {
                Button("Suggest toast like this") {
                    suggestMore()
                }

                Button("Less") {
                    suggestLess()
                }
            }
        }
        .padding()
        .confirmationDialog("Edit suggestion", isPresented: $showingEditOptions) {
            Button("Suggest Less Avocado Toast") {
                suggestLessAvocadoToast()
            }

            Button("Stop Suggesting Avocado Toast", role: .destructive) {
                stopSuggestingAvocadoToast()
            }
        }
    }
}

func suggestMore() {}
func suggestLess() {}
func suggestLessAvocadoToast() {}
func stopSuggestingAvocadoToast() {}

キーポイント:

  • Text("Because you added avocado toast")推奨事項の入力元を明らかにし、その推奨事項が表示される理由を説明します。
  • Button("Edit suggestion")アイコンのみの詳細メニューに推奨事項を隠すのではなく、ユーザーが編集できる推奨事項を直接記述します。
  • Button("Suggest toast like this")動詞を使用して、推奨事項に影響を与えるクリックの結果を説明します。
  • Button("Less")類似コンテンツを減らす明示的なフィードバックに対応します。
  • confirmationDialog2 つの具体的なオプションを表示すると、ユーザーはアボカド トーストの推奨を減らすか、推奨をやめるかを選択できます。

重要ポイント

  1. やるべきこと: 「最近の行動に基づいた推奨テンプレート」ホームページ セクションを Notes アプリに追加します。 実行する価値がある理由: セッションは、パーソナライズされたコンテンツは多くのコンテンツ シナリオに適しているが、ソースは開示する必要があると述べました。 開始方法: 最近作成したメモの種類を使用して推奨事項を生成し、ブロック タイトルの下に「最近会議メモを作成したため」と書き込み、その横にある [提案の編集] ボタンを押します。

  2. 対処方法: 画像編集アプリのジェスチャー操作に、表示される代替入口を追加します。 実行する価値がある理由: Apple は、ジェスチャを主要なアクションの代替としてではなく、ショートカットとして推奨しています。 開始方法: ツールバーに「ズーム」、「前へ」、「次へ」ボタンを設けながら、2 本指でのズームとフィルターのスライド切り替えを維持し、アニメーションの方向をジェスチャーと一致させます。

  3. やるべきこと: 入力可能なコンテンツの例を検索ページに追加します。 実行する価値がある理由: 検索ボックスは空白ページになりがちで、ユーザーは何を検索すればよいのかわかりません。 開始方法:.searchableプロンプトに、「アイテム、メンバー、またはタグの検索」などの検索可能なディメンションを記述し、空の状態で 3 つのクエリ例を表示します。

  4. 対処方法: データベース フィールドごとにグループ化せずに、コンテンツ ベースのアプリの分類を再設計します。 実行する価値がある理由: セッションで、Toasty は分類を食材からレストラン、友達、おすすめに変更しました。分類は発見行動に近くなりました。 開始方法: ユーザーがどのようにコンテンツを見つけたかをインタビューし、「ソース」、「シナリオ」、「関係」を第一レベルのグループとして使用し、次にSectionまたは、境界線を強化するためのカードのタイトル。

  5. やるべきこと: 「見た理由」と「このコンテンツを減らす」を推奨フローに追加します。 実行する価値がある理由: ユーザーは暗黙的なフィードバックのソースを理解し、推奨結果を修正できます。 開始方法: 推薦カードの下に「X を集めたから」などの理由を表示し、「類似コンテンツを減らす」と「X の推薦をやめる」の 2 つの操作を提供します。

関連セッション

コメント

GitHub Issues · utterances