TipKit для Swift: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

TipKit для Swift: Полное руководство по созданию подсказок пользователю

TipKit — это мощная и современная библиотека от Apple, представленная на WWDC 2023, предназначенная для создания контекстных подсказок и обучения пользователей в приложениях на SwiftUI и UIKit. Она позволяет разработчикам легко внедрять интерактивные подсказки, которые помогают пользователям быстрее освоить интерфейс, узнать о новых функциях и повысить общую вовлеченность в приложение.

Основная цель TipKit — заменить устаревшие и громоздкие решения для онбординга (например, кастомные вьюхи или сторонние библиотеки) на стандартизированный, гибкий и производительный инструмент. TipKit автоматически управляет отображением подсказок: показывает их в нужный момент, скрывает после взаимодействия, учитывает частоту показов и позволяет настраивать логику появления на основе действий пользователя или состояния приложения.

Библиотека идеально подходит для iOS 17+, macOS 14+, tvOS 17+ и watchOS 10+. Она тесно интегрируется с фреймворками Apple, поддерживает анимации, адаптивность под разные размеры экранов и работает как с SwiftUI, так и с UIKit (через UIViewRepresentable). В этой статье мы подробно разберем все возможности TipKit, от установки до сложных сценариев использования.

Установка

TipKit является частью экосистемы Apple и не требует установки через сторонние менеджеры пакетов. Для использования библиотеки достаточно добавить ее в ваш Xcode проект через стандартный Swift Package Manager (SPM) или вручную.

Через Xcode (рекомендуемый способ)

  1. Откройте ваш проект в Xcode.
  2. Выберите File → Add Package Dependencies....
  3. В поисковой строке введите: https://github.com/apple/sample-tipkit.git (официальный репозиторий Apple с примерами) или используйте встроенный пакет, если он доступен в вашей версии Xcode.
  4. Убедитесь, что выбрана ветка main или последняя стабильная версия.
  5. Нажмите Add Package и выберите ваш таргет.

Важно: Начиная с Xcode 15, TipKit встроен в SDK, поэтому в большинстве случаев достаточно просто импортировать модуль в коде. Если вы используете более старую версию Xcode, добавьте пакет вручную.

Через Package.swift (для SPM проектов)

// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "YourProject",
    dependencies: [
        .package(url: "https://github.com/apple/sample-tipkit.git", from: "1.0.0")
    ],
    targets: [
        .target(
            name: "YourTarget",
            dependencies: ["TipKit"]
        )
    ]
)

После добавления пакета импортируйте библиотеку в нужном файле:

import TipKit

Быстрый старт: минимальный рабочий пример

Давайте создадим простую подсказку, которая появится при первом запуске приложения и объяснит пользователю, как использовать кнопку.

import SwiftUI
import TipKit

// 1. Определяем структуру подсказки
struct WelcomeTip: Tip {
    var title: Text {
        Text("Добро пожаловать!")
    }
    
    var message: Text? {
        Text("Нажмите эту кнопку, чтобы начать работу с приложением.")
    }
    
    var image: Image? {
        Image(systemName: "hand.wave")
    }
}

// 2. Используем подсказку в представлении
struct ContentView: View {
    // 3. Создаем экземпляр подсказки
    private let welcomeTip = WelcomeTip()
    
    var body: some View {
        VStack {
            Button("Начать") {
                // Действие кнопки
                print("Кнопка нажата!")
            }
            .popoverTip(welcomeTip) // 4. Привязываем подсказку к кнопке
            .padding()
        }
        .padding()
        .task {
            // 5. Конфигурируем TipKit при запуске
            try? await Tips.configure()
        }
    }
}

// 6. Точка входа в приложение
@main
struct TipKitExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Объяснение:

  • Шаг 1: Мы создали структуру WelcomeTip, которая соответствует протоколу Tip. В ней мы определили заголовок, сообщение и иконку.
  • Шаг 2-3: В представлении ContentView мы создаем экземпляр нашей подсказки.
  • Шаг 4: Модификатор .popoverTip(welcomeTip) привязывает подсказку к кнопке. TipKit автоматически покажет ее при первом появлении кнопки на экране.
  • Шаг 5: Метод Tips.configure() инициализирует систему подсказок. Его нужно вызвать один раз при запуске приложения (например, в .task или в AppDelegate).

После запуска приложения вы увидите всплывающую подсказку с заголовком, текстом и иконкой. После нажатия на кнопку или вне области подсказки она исчезнет и больше не появится (если не сбросить настройки).

Основные методы, функции и классы

Рассмотрим ключевые компоненты TipKit. Для каждого элемента приведена сигнатура, описание и пример использования.

1. Протокол Tip

Сигнатура:

protocol Tip {
    associatedtype Title: View
    associatedtype Message: View = EmptyView
    associatedtype Image: View = EmptyView
    associatedtype Actions: View = EmptyView
    
    @ViewBuilder var title: Title { get }
    @ViewBuilder var message: Message? { get }
    @ViewBuilder var image: Image? { get }
    @ViewBuilder var actions: Actions { get }
    var rules: [Rule] { get }
    var options: [Option] { get }
}

Что делает: Определяет структуру подсказки. Вы обязаны реализовать свойство title, остальные свойства опциональны. Позволяет настраивать внешний вид, логику появления и действия.

Пример:

struct CustomTip: Tip {
    var title: Text {
        Text("Совет")
    }
    
    var message: Text? {
        Text("Попробуйте провести пальцем влево, чтобы удалить элемент.")
    }
    
    var image: Image? {
        Image(systemName: "hand.draw")
    }
    
    var actions: some View {
        Button("Понятно") {
            // Действие при нажатии на кнопку в подсказке
            print("Пользователь подтвердил")
        }
    }
}

2. Модификатор .popoverTip(_:arrowEdge:)

Сигнатура:

func popoverTip<T: Tip>(
    _ tip: T,
    arrowEdge: Edge = .top
) -> some View

Что делает: Привязывает подсказку к любому View. Подсказка отображается в виде всплывающего окна (popover) с указанной стрелкой. Это основной способ отображения подсказок в SwiftUI.

Пример:

struct ButtonView: View {
    let tip = MyTip()
    
    var body: some View {
        Button("Нажми меня") {
            // ...
        }
        .popoverTip(tip, arrowEdge: .bottom)
    }
}

3. Модификатор .tip(_:) для UIKit

Сигнатура (в UIKit):

// В UIKit используется через UIViewRepresentable или напрямую:
func tip(_ tip: Tip) -> UIPopoverTipView

Что делает: Позволяет отображать подсказки в UIKit приложениях. Создает UIPopoverTipView, который можно добавить к любому UIView.

Пример (через UIViewRepresentable):

struct UIKitTipView: UIViewRepresentable {
    let tip: MyTip
    
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        let tipView = UIPopoverTipView(tip: tip)
        tipView.sourceView = view
        tipView.sourceRect = view.bounds
        tipView.present(animated: true)
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {}
}

4. Метод Tips.configure()

Сигнатура:

static func configure(options: [TipOption] = []) async throws

Что делает: Инициализирует систему TipKit. Должен быть вызван один раз перед использованием любых подсказок. Настраивает хранилище, частоту показов и другие глобальные параметры.

Пример:

// В AppDelegate или в .task
Task {
    try? await Tips.configure()
    // Теперь подсказки будут работать
}

5. Свойство rules в протоколе Tip

Сигнатура:

var rules: [Rule] { get }

Что делает: Позволяет задать условия, при которых подсказка будет показана. Например, показать подсказку только после того, как пользователь выполнил определенное действие.

Пример:

struct ConditionalTip: Tip {
    @Parameter
    static var hasTappedButton: Bool = false
    
    var title: Text {
        Text("Отличная работа!")
    }
    
    var rules: [Rule] {
        #Rule(Self.$hasTappedButton) { $0 == true }
    }
}

6. Макрос #Rule

Сигнатура:

#Rule<Value>(
    _ parameter: Parameter<Value>,
    _ condition: (Value) -> Bool
) -> Rule

Что делает: Создает правило на основе значения параметра. Позволяет динамически управлять отображением подсказки.

Пример:

#Rule(Self.$userScore) { $0 > 100 }

7. Свойство options в протоколе Tip

Сигнатура:

var options: [Option] { get }

Что делает: Позволяет настроить поведение подсказки: максимальное количество показов, интервал между показами, игнорирование и т.д.

Пример:

var options: [Option] {
    // Показать максимум 3 раза, с интервалом 1 день
    Tips.MaxDisplayCount(3)
    Tips.DisplayFrequency(.daily)
}

8. Структура Tips.Parameter

Сигнатура:

@propertyWrapper struct Parameter<Value> where Value: Codable

Что делает: Обертка свойства, которая сохраняет состояние между запусками приложения. Используется для хранения флагов, счетчиков и других данных, влияющих на правила показа.

Пример:

struct MyTip: Tip {
    @Parameter
    static var appLaunchCount: Int = 0
    
    var rules: [Rule] {
        #Rule(Self.$appLaunchCount) { $0 >= 3 }
    }
}

9. Метод Tips.show(_:for:) (ручной показ)

Сигнатура:

static func show(_ tip: Tip, for sourceView: UIView) throws

Что делает: Позволяет принудительно показать подсказку для указанного UIView. Используется в UIKit или когда нужно показать подсказку вне зависимости от правил.

Пример:

try? Tips.show(MyTip(), for: myButton)

10. Метод Tips.hide(_:)

Сигнатура:

static func hide(_ tip: Tip) throws

Что делает: Принудительно скрывает подсказку. Полезно, если нужно убрать подсказку при определенных условиях (например, при переходе на другой экран).

Пример:

try? Tips.hide(MyTip())

11. Структура Tips.DisplayFrequency

Сигнатура:

struct DisplayFrequency: TipOption {
    enum Frequency {
        case immediate
        case daily
        case weekly
        case monthly
        case custom(TimeInterval)
    }
}

Что делает: Определяет, как часто подсказка может показываться одному и тому же пользователю. Позволяет избежать назойливости.

Пример:

var options: [Option] {
    Tips.DisplayFrequency(.weekly)
}

12. Структура Tips.MaxDisplayCount

Сигнатура:

struct MaxDisplayCount: TipOption {
    let count: Int
}

Что делает: Ограничивает

Рекомендаций