yandex / mapkit-ios-demo

MapKit iOS demo
Other
84 stars 26 forks source link

Поддержка SwiftUI? #129

Closed windrunner21 closed 1 year ago

windrunner21 commented 3 years ago

Документация для SwiftUI была бы полезна.

windrunner21 commented 3 years ago

Для тех кто ищет как показать карту используя SwiftUI

import SwiftUI
import YandexMapsMobile

struct YandexMapsView: UIViewRepresentable {

    func makeUIView(context: Context) -> YMKMapView {
        let mapView = YMKMapView(frame: CGRect.zero)

        return mapView
    }

    func updateUIView(_ uiView: YMKMapView, context: Context) {

    }
}

и потом в вашем нужном View

import SwiftUI

struct HomeView: View {

    var body: some View {
        YandexMapsView().edgesIgnoringSafeArea(.all)
    }
}

struct HomeView_Previews: PreviewProvider {
    static var previews: some View {
        HomeView()
    }
}
Dominnik commented 3 years ago

Для тех кто ищет как показать карту используя SwiftUI

import SwiftUI
import YandexMapsMobile

struct YandexMapsView: UIViewRepresentable {

    func makeUIView(context: Context) -> YMKMapView {
        let mapView = YMKMapView(frame: CGRect.zero)

        return mapView
    }

    func updateUIView(_ uiView: YMKMapView, context: Context) {

    }
}

и потом в вашем нужном View

import SwiftUI

struct HomeView: View {

    var body: some View {
        YandexMapsView().edgesIgnoringSafeArea(.all)
    }
}

struct HomeView_Previews: PreviewProvider {
    static var previews: some View {
        HomeView()
    }
}

Не пытался реализовывать функционал отображения местоположения пользователя в SwiftUI?

windrunner21 commented 3 years ago

Для тех кто ищет как показать карту используя SwiftUI

import SwiftUI
import YandexMapsMobile

struct YandexMapsView: UIViewRepresentable {

    func makeUIView(context: Context) -> YMKMapView {
        let mapView = YMKMapView(frame: CGRect.zero)

        return mapView
    }

    func updateUIView(_ uiView: YMKMapView, context: Context) {

    }
}

и потом в вашем нужном View

import SwiftUI

struct HomeView: View {

    var body: some View {
        YandexMapsView().edgesIgnoringSafeArea(.all)
    }
}

struct HomeView_Previews: PreviewProvider {
    static var previews: some View {
        HomeView()
    }
}

Не пытался реализовывать функционал отображения местоположения пользователя в SwiftUI?

Да, пытался. Коротко скажу так: использовать местоположение надо через сами функции Swift-a. Потом кидать это в Yandex View.

Подробнее:

Создаем класс, чтобы получать местоположение на изменения в геолокации. (Используем методы встроннные Swift-a)

class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {

    // Publish the user's location so subscribers can react to updates
    @Published var lastKnownLocation: CLLocation? = nil
    private let manager = CLLocationManager()

    override init() {
        super.init()
        self.manager.delegate = self
        self.manager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            self.manager.startUpdatingLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // Notify listeners that the user has a new location
        self.lastKnownLocation = locations.last
    }
}

Потом создаем Observable который будет реагировать на изменения Location Manager-a. И добавляем его в updateUIView, где уже используем API от Yandex:

struct YandexMapsView: UIViewRepresentable {

    // Listen to changes on the locationManager
    @ObservedObject var locationManager = LocationManager()

    func makeUIView(context: Context) -> YMKMapView {
        let mapView = YMKMapView(frame: CGRect.zero)
        mapView.mapWindow.map.move(
            with: YMKCameraPosition(target: YMKPoint(latitude: 40.40_92_64, longitude: 49.86_70_92), zoom: 10, azimuth: 0, tilt: 0)
        )
        let userLocationViewController = UserLocationViewController()

        let mapKit = YMKMapKit.sharedInstance()
        let userLocationLayer = mapKit.createUserLocationLayer(with: mapView.mapWindow)
        userLocationLayer.setVisibleWithOn(true)
        userLocationLayer.isHeadingEnabled = true
        userLocationLayer.setObjectListenerWith(userLocationViewController)

        return mapView
    }

    func updateUIView(_ mapView: YMKMapView, context: Context) {
        // When the locationManager publishes updates, respond to them
        if let myLocation = locationManager.lastKnownLocation {
            centerMapLocation(target: YMKPoint(latitude: myLocation.coordinate.latitude, longitude: myLocation.coordinate.longitude), map: mapView )
            print("User's location: \(myLocation)")
        }
    }

    // custom functions
    func centerMapLocation(target location: YMKPoint?, map: YMKMapView) {
        guard let location = location else { print("Failed to get user location"); return }

        map.mapWindow.map.move(
            with: YMKCameraPosition(target: location, zoom: 18, azimuth: 0, tilt: 0),
            animationType: YMKAnimation(type: YMKAnimationType.smooth, duration: 5)
        )
    }
}

P.S. Чтобы использовать userLocationLayer.setObjectListenerWith(userLocationViewController) создай класс под протокол YMKUserLocationObjectListener

Надеюсь смог помочь.

Dominnik commented 3 years ago

Для тех кто ищет как показать карту используя SwiftUI

import SwiftUI
import YandexMapsMobile

struct YandexMapsView: UIViewRepresentable {

    func makeUIView(context: Context) -> YMKMapView {
        let mapView = YMKMapView(frame: CGRect.zero)

        return mapView
    }

    func updateUIView(_ uiView: YMKMapView, context: Context) {

    }
}

и потом в вашем нужном View

import SwiftUI

struct HomeView: View {

    var body: some View {
        YandexMapsView().edgesIgnoringSafeArea(.all)
    }
}

struct HomeView_Previews: PreviewProvider {
    static var previews: some View {
        HomeView()
    }
}

Не пытался реализовывать функционал отображения местоположения пользователя в SwiftUI?

Да, пытался. Коротко скажу так: использовать местоположение надо через сами функции Swift-a. Потом кидать это в Yandex View.

Подробнее:

Создаем класс, чтобы получать местоположение на изменения в геолокации. (Используем методы встроннные Swift-a)

class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {

    // Publish the user's location so subscribers can react to updates
    @Published var lastKnownLocation: CLLocation? = nil
    private let manager = CLLocationManager()

    override init() {
        super.init()
        self.manager.delegate = self
        self.manager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            self.manager.startUpdatingLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // Notify listeners that the user has a new location
        self.lastKnownLocation = locations.last
    }
}

Потом создаем Observable который будет реагировать на изменения Location Manager-a. И добавляем его в updateUIView, где уже используем API от Yandex:

struct YandexMapsView: UIViewRepresentable {

    // Listen to changes on the locationManager
    @ObservedObject var locationManager = LocationManager()

    func makeUIView(context: Context) -> YMKMapView {
        let mapView = YMKMapView(frame: CGRect.zero)
        mapView.mapWindow.map.move(
            with: YMKCameraPosition(target: YMKPoint(latitude: 40.40_92_64, longitude: 49.86_70_92), zoom: 10, azimuth: 0, tilt: 0)
        )
        let userLocationViewController = UserLocationViewController()

        let mapKit = YMKMapKit.sharedInstance()
        let userLocationLayer = mapKit.createUserLocationLayer(with: mapView.mapWindow)
        userLocationLayer.setVisibleWithOn(true)
        userLocationLayer.isHeadingEnabled = true
        userLocationLayer.setObjectListenerWith(userLocationViewController)

        return mapView
    }

    func updateUIView(_ mapView: YMKMapView, context: Context) {
        // When the locationManager publishes updates, respond to them
        if let myLocation = locationManager.lastKnownLocation {
            centerMapLocation(target: YMKPoint(latitude: myLocation.coordinate.latitude, longitude: myLocation.coordinate.longitude), map: mapView )
            print("User's location: \(myLocation)")
        }
    }

    // custom functions
    func centerMapLocation(target location: YMKPoint?, map: YMKMapView) {
        guard let location = location else { print("Failed to get user location"); return }

        map.mapWindow.map.move(
            with: YMKCameraPosition(target: location, zoom: 18, azimuth: 0, tilt: 0),
            animationType: YMKAnimation(type: YMKAnimationType.smooth, duration: 5)
        )
    }
}

P.S. Чтобы использовать userLocationLayer.setObjectListenerWith(userLocationViewController) создай класс под протокол YMKUserLocationObjectListener

Надеюсь смог помочь.

Конечно помог :) Спасибо. Единственное, в классе UserLocationViewController не отрабатывают методы протокола (onObjectAdded, onObjectRemoved), что не даёт выставить кастомную иконку для местоположения пользователя.

windrunner21 commented 3 years ago

Для тех кто ищет как показать карту используя SwiftUI


import SwiftUI

import YandexMapsMobile

struct YandexMapsView: UIViewRepresentable {

    func makeUIView(context: Context) -> YMKMapView {

        let mapView = YMKMapView(frame: CGRect.zero)

        return mapView

    }

    func updateUIView(_ uiView: YMKMapView, context: Context) {

    }

}

и потом в вашем нужном View


import SwiftUI

struct HomeView: View {

    var body: some View {

        YandexMapsView().edgesIgnoringSafeArea(.all)

    }

}

struct HomeView_Previews: PreviewProvider {

    static var previews: some View {

        HomeView()

    }

}

Не пытался реализовывать функционал отображения местоположения пользователя в SwiftUI?

Да, пытался. Коротко скажу так: использовать местоположение надо через сами функции Swift-a. Потом кидать это в Yandex View.

Подробнее:

Создаем класс, чтобы получать местоположение на изменения в геолокации. (Используем методы встроннные Swift-a)


class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {

    // Publish the user's location so subscribers can react to updates

    @Published var lastKnownLocation: CLLocation? = nil

    private let manager = CLLocationManager()

    override init() {

        super.init()

        self.manager.delegate = self

        self.manager.startUpdatingLocation()

    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

        if status == .authorizedWhenInUse {

            self.manager.startUpdatingLocation()

        }

    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        // Notify listeners that the user has a new location

        self.lastKnownLocation = locations.last

    }

}

Потом создаем Observable который будет реагировать на изменения Location Manager-a. И добавляем его в updateUIView, где уже используем API от Yandex:


struct YandexMapsView: UIViewRepresentable {

    // Listen to changes on the locationManager

    @ObservedObject var locationManager = LocationManager()

    func makeUIView(context: Context) -> YMKMapView {

        let mapView = YMKMapView(frame: CGRect.zero)

        mapView.mapWindow.map.move(

            with: YMKCameraPosition(target: YMKPoint(latitude: 40.40_92_64, longitude: 49.86_70_92), zoom: 10, azimuth: 0, tilt: 0)

        )

        let userLocationViewController = UserLocationViewController()

        let mapKit = YMKMapKit.sharedInstance()

        let userLocationLayer = mapKit.createUserLocationLayer(with: mapView.mapWindow)

        userLocationLayer.setVisibleWithOn(true)

        userLocationLayer.isHeadingEnabled = true

        userLocationLayer.setObjectListenerWith(userLocationViewController)

        return mapView

    }

    func updateUIView(_ mapView: YMKMapView, context: Context) {

        // When the locationManager publishes updates, respond to them

        if let myLocation = locationManager.lastKnownLocation {

            centerMapLocation(target: YMKPoint(latitude: myLocation.coordinate.latitude, longitude: myLocation.coordinate.longitude), map: mapView )

            print("User's location: \(myLocation)")

        }

    }

    // custom functions

    func centerMapLocation(target location: YMKPoint?, map: YMKMapView) {

        guard let location = location else { print("Failed to get user location"); return }

        map.mapWindow.map.move(

            with: YMKCameraPosition(target: location, zoom: 18, azimuth: 0, tilt: 0),

            animationType: YMKAnimation(type: YMKAnimationType.smooth, duration: 5)

        )

    }

}

P.S. Чтобы использовать userLocationLayer.setObjectListenerWith(userLocationViewController) создай класс под протокол YMKUserLocationObjectListener

Надеюсь смог помочь.

Конечно помог :) Спасибо. Единственное, в классе UserLocationViewController не отрабатывают методы протокола (onObjectAdded, onObjectRemoved), что не даёт выставить кастомную иконку для местоположения пользователя.

Рад что смог помочь. Насчёт иконок пользователя, я скоро перейду на имплементацию этой части. Как найду что и как делать дам знать!

windrunner21 commented 3 years ago

Для имплементации иконок и тд через UserLocationView Controller в классе YandexMapView просто надо поменять let userLocationViewController = UserLocationViewController() на @ObservedObject var userLocationViewController = UserLocationViewController()

@Dominnik

Dominnik commented 3 years ago

Спасибо большое. Как раз начала тоже заниматься этим. @windrunner21

IHIierO commented 2 years ago

Для тех кто ищет как показать карту используя SwiftUI

import SwiftUI
import YandexMapsMobile

struct YandexMapsView: UIViewRepresentable {

    func makeUIView(context: Context) -> YMKMapView {
        let mapView = YMKMapView(frame: CGRect.zero)

        return mapView
    }

    func updateUIView(_ uiView: YMKMapView, context: Context) {

    }
}

и потом в вашем нужном View

import SwiftUI

struct HomeView: View {

    var body: some View {
        YandexMapsView().edgesIgnoringSafeArea(.all)
    }
}

struct HomeView_Previews: PreviewProvider {
    static var previews: some View {
        HomeView()
    }
}

Не пытался реализовывать функционал отображения местоположения пользователя в SwiftUI?

Да, пытался. Коротко скажу так: использовать местоположение надо через сами функции Swift-a. Потом кидать это в Yandex View.

Подробнее:

Создаем класс, чтобы получать местоположение на изменения в геолокации. (Используем методы встроннные Swift-a)

class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {

    // Publish the user's location so subscribers can react to updates
    @Published var lastKnownLocation: CLLocation? = nil
    private let manager = CLLocationManager()

    override init() {
        super.init()
        self.manager.delegate = self
        self.manager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            self.manager.startUpdatingLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // Notify listeners that the user has a new location
        self.lastKnownLocation = locations.last
    }
}

Потом создаем Observable который будет реагировать на изменения Location Manager-a. И добавляем его в updateUIView, где уже используем API от Yandex:

struct YandexMapsView: UIViewRepresentable {

    // Listen to changes on the locationManager
    @ObservedObject var locationManager = LocationManager()

    func makeUIView(context: Context) -> YMKMapView {
        let mapView = YMKMapView(frame: CGRect.zero)
        mapView.mapWindow.map.move(
            with: YMKCameraPosition(target: YMKPoint(latitude: 40.40_92_64, longitude: 49.86_70_92), zoom: 10, azimuth: 0, tilt: 0)
        )
        let userLocationViewController = UserLocationViewController()

        let mapKit = YMKMapKit.sharedInstance()
        let userLocationLayer = mapKit.createUserLocationLayer(with: mapView.mapWindow)
        userLocationLayer.setVisibleWithOn(true)
        userLocationLayer.isHeadingEnabled = true
        userLocationLayer.setObjectListenerWith(userLocationViewController)

        return mapView
    }

    func updateUIView(_ mapView: YMKMapView, context: Context) {
        // When the locationManager publishes updates, respond to them
        if let myLocation = locationManager.lastKnownLocation {
            centerMapLocation(target: YMKPoint(latitude: myLocation.coordinate.latitude, longitude: myLocation.coordinate.longitude), map: mapView )
            print("User's location: \(myLocation)")
        }
    }

    // custom functions
    func centerMapLocation(target location: YMKPoint?, map: YMKMapView) {
        guard let location = location else { print("Failed to get user location"); return }

        map.mapWindow.map.move(
            with: YMKCameraPosition(target: location, zoom: 18, azimuth: 0, tilt: 0),
            animationType: YMKAnimation(type: YMKAnimationType.smooth, duration: 5)
        )
    }
}

P.S. Чтобы использовать userLocationLayer.setObjectListenerWith(userLocationViewController) создай класс под протокол YMKUserLocationObjectListener

Надеюсь смог помочь.

Подскажите пожалуйста как должен выглядеть класс UserLocationViewController()?

aramayyes commented 1 year ago

Можно использовать эту библиотеку: https://github.com/aramayyes/YandexMapsSwiftUI