Connect with us

Разработка

Используем Core Motion в SwiftUI-приложении

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

Опубликовано

/

     
     

Чтобы получить доступ к акселерометру, гироскопам и, при наличии, шагомеру, магнитометру и барометру устройства, будь то iOS, iPadOS, watchOS или visionOS, используйте фреймворк Core Motion. Этот фреймворк сообщает данные о движении и окружающей среде, полученные от встроенных аппаратных датчиков. Использовать его в приложении, созданном с помощью SwiftUI, для создания визуального взаимодействия на основе собранных данных довольно просто.

Помните, что для тестирования функций приложения, использующего фреймворк Core Motion, необходимо запустить его на устройстве. В следующем примере мы имитируем динамическую глубину, используя данные гироскопа для поворота элементов пользовательского интерфейса и перемещения их тени.

Шаг 1 — Управление движением

Первым шагом будет импорт фреймворка Core Motion.

import SwiftUI
import CoreMotion

Затем создайте класс, отвечающий за предоставление данных от датчиков устройства. Класс MotionDataProvider, соответствующий протоколу ObservableObject, будет хранить данные о движении с датчиков устройства и публиковать любые обновления, основанные на движении устройства.

class MotionDataProvider: ObservableObject {
    // 1.
    private let motionProvider = CMMotionManager()
    // 2.
    @Published var x = 0.0
    @Published var y = 0.0

    init() {
        // 3.
        motionProvider.deviceMotionUpdateInterval = 1 / 20

        motionProvider.startDeviceMotionUpdates(to: .main) { [weak self] data, error in
            // 4.
            guard let motion = data?.attitude else { return }
            self?.x = motion.roll
            self?.y = motion.pitch
        }
    }  
}
  1. Константа motionProvider — это экземпляр CMMotionManager, объекта, отвечающего за запуск и управление сервисами движения.
  2. Свойства x и y будут обновляться объектом менеджера движения, они помечены оберткой свойства @Published.
  3. При инициализации объекта MotionDataProvider настройте объект менеджера движения:
    • .deviceMotionUpdateInterval: свойство экземпляра, задающее получение данных о движении устройства с регулярным интервалом в секундах.
    • .startDeviceMotionUpdates: метод экземпляра для получения последних данных о движении устройства без обработчика.
    • Для обновления пользовательского интерфейса параметр .main указывает, что данные будут обрабатываться в основной очереди, а [weak self] гарантирует, что если они не нужны, текущий объект не будет храниться в памяти, что позволяет избежать циклов удержания.
    • Значения data и error содержат информацию об устройстве. Данные и возможные найденные ошибки соответственно.
  4. Проверьте, есть ли данные для чтения, и получите доступ к значению attitude, которое содержит ориентацию устройства относительно системы отсчета в определенный момент времени, типа CMAttitude. Значение крена (roll) присваивается свойству x, представляя собой вращение вокруг продольной оси. Значение угла наклона (pitch) присваивается свойству y, представляющему вращение вокруг поперечной оси.

Шаг 2 — Создание движения в представлении

В представлении SwiftUI воспользуемся MotionDataProvider, чтобы получить информацию от датчиков устройства и использовать ее для изменения пользовательского интерфейса.

struct ContentView: View {
    // 1.
    @StateObject private var motionManager = MotionDataProvider()
    
    var body: some View {
        VStack {
            Text("Create with Swift")
                .font(.system(size: 40).bold())
            
            ZStack{
                Circle()
                        .frame(width: 200)
                Image(systemName: "swift")
                    .font(.system(size: 100).bold())
            }
        }
        // 2.
        .foregroundStyle(
            .white.gradient.shadow(
                .inner(color: .black, radius: 6, x: motionManager.x * -20, y: motionManager.y * -20)
            )
        )
        // 4.
        .rotation3DEffect(.degrees(motionManager.x * 20), axis: (x: 0, y: 1, z: 0))
        .rotation3DEffect(.degrees(motionManager.y * 20), axis: (x: -1, y: 0, z: 0))
        
    }
}
  1. Свойство motionManager является экземпляром MotionDataProvider и постоянно публикует значения, считанные CMMotionManager.
  2. Эффект глубины внутри компонентов вида будет достигнут с помощью модификатора тени shadow. Свойства координат будут получать значения от менеджера движения для расчета значений тени.
  3. Примените эффект вращения по осям x и y вида с помощью модификатора rotation3DEffect. При расчете значения поворота используются данные motionManager, чтобы определить количество градусов для поворота представления.

Финальный результат

После выполнения всех шагов можно запустить тесты на устройстве, например на iPhone. Ожидаемым результатом будет то, что при перемещении устройства тени объектов в представлении будут перемещаться, создавая ощущение глубины, как показано в примере:

Вот полный код:

import SwiftUI
import CoreMotion

class MotionDataProvider: ObservableObject {
    
    private let motionProvider = CMMotionManager()
    
    @Published var x = 0.0
    @Published var y = 0.0
    
    init() {
        motionProvider.deviceMotionUpdateInterval = 1 / 20
        motionProvider.startDeviceMotionUpdates(to: .main) { [weak self] data, error in
            guard let motion = data?.attitude else { return }
            
            self?.x = motion.roll
            self?.y = motion.pitch
        }
    }
    
}

struct ContentView: View {
    // 1.
    @StateObject private var motionManager = MotionDataProvider()
    
    var body: some View {
        // 2.
        VStack {
            Text("Create with Swift")
                .font(.system(size: 40).bold())
            
            ZStack{
                Circle().frame(width: 200) //.shadow(radius: 8)
                
                Image(systemName: "swift")
                    .font(.system(size: 100).bold())
            }
        }
        // 3.
        .foregroundStyle(
            .white.gradient.shadow(
                .inner(color: .black, radius: 6, x: motionManager.x * -20, y: motionManager.y * -20)
            )
        )
        // 4.
        .rotation3DEffect(.degrees(motionManager.x * 20), axis: (x: 0, y: 1, z: 0))
        .rotation3DEffect(.degrees(motionManager.y * 20), axis: (x: -1, y: 0, z: 0))
        
    }
}

Еще про Core Motion:

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: