yandex / mapkit-ios-demo

MapKit iOS demo
Other
84 stars 26 forks source link

Get tapped object details and change the icon #46

Closed EmmaVvv closed 5 years ago

EmmaVvv commented 5 years ago

I need to display nearby objects with their custom icons on the map, and on tap event open the information window down below. Besides, I need to change the object icon on tap. How can I implement this? I can hardly find any tutorial or course regarding YandexMapKit. Any help would be appreciated!

eberkovich commented 5 years ago

I need to display nearby objects with their custom icons on the map https://github.com/yandex/mapkit-ios-demo/blob/master/MapKitDemo/MapObjectsViewController.swift

I need to change the object icon on tap

YMKMapObjectCollection* mapObjects = self.mapView.mapWindow.map.mapObjects;
YMKPlacemarkMapObject *placemark = [mapObjects addPlacemarkWithPoint: ...];

[mapObjects addTapListenerWithTapListener:self];
//or [placemark addTapListenerWithTapListener:self];

- (BOOL)onMapObjectTapWithMapObject:(YMKMapObject *)mapObject point:(YMKPoint *)point
{
    if ([mapObject isKindOfClass:[YMKPlacemarkMapObject class]]) {
        YMKPlacemarkMapObject *placemark = (YMKPlacemarkMapObject *)mapObject;
        [placemark setIconWithImage:self.tappedImage];
    } 
    return YES;
}

open the information window down below... You can use MapObject.userData property.

Please keep in mind, mapkit stores weak reference to listeners, so it is needed to store listener by application.

EmmaVvv commented 5 years ago

Here's how I do it:

` class MyViewController: UIViewController, YMKMapObjectTapListener {

func onMapObjectTap(with mapObject: YMKMapObject, point: YMKPoint) -> Bool {

    guard let placemark = mapObject as? YMKPlacemarkMapObject else { return false }

    print(point.latitude, point.longitude)

    return true
}`

override func viewDidLoad() {
    super.viewDidLoad()
    mapView.mapWindow.map.addTapListener(with: self)

} }`

As it was stated by one of your admins. But I get the following error:

Argument type 'AddressesViewController' does not conform to expected type 'YMKLayersGeoObjectTapListener'

When I add this listener, I'm forced to use this method:

func onObjectTap(with event: YMKGeoObjectTapEvent) -> Bool { return true }

But in this case the func onMapObjectTap(with mapObject: YMKMapObject, point: YMKPoint) -> Bool { isn't called at all.

What should I do, @eberkovich ?

eberkovich commented 5 years ago

You need to use YMKMapObjectTapListener not YMKLayersGeoObjectTapListener. YMKMapObjectTapListener - handles tap on user map objects. YMKLayersGeoObjectTapListener - handles tap on objects within map layer.

EmmaVvv commented 5 years ago

@eberkovich , yes, I added only YMKMapObjectTapListener to my map objects, and now this delegate method is called, but once in a lifetime :)

Here is the piece of code:

`class AddressesViewController: UIViewController, YMKMapObjectTapListener {

override func viewDidLoad() { super.viewDidLoad() let mapObjects = mapView.mapWindow.map.mapObjects mapObjects.addTapListener(with: self) } `

And the delegate method onMapObjectTap(with mapObject: YMKMapObject, point: YMKPoint) is called randomly, when I tap on object, meanwile I get the following messages in log console:

class AddressesViewController: UIViewController, YMKMapObjectTapListener {

But I don't have any other listeners added. Why is this like that?

And my number 2 question is related to object data.

The

mapObject.userData

is always nil How can I get the object details(name, description, rating, working hours, etc.) in a proper way?

eberkovich commented 5 years ago

method is called, but once in a lifetime called randomly

I do not quite understand, so it is not called once? And what does it mean randomly?

mapObject.userData is always nil

Could you please explain? You fill userData then read it and it is nil?

EmmaVvv commented 5 years ago

Yes, in viewDidLoad() I add placemarks with their lat/long-s to mapObjects and when I want to read the data onMapObjectTap(with mapObject: YMKMapObject, point: YMKPoint) the mapObject.userData is nil

eberkovich commented 5 years ago

Could you show your source code?

EmmaVvv commented 5 years ago

can you give me your email address?

eberkovich commented 5 years ago

Could you please put minimum example here?

EmmaVvv commented 5 years ago

This is the whole class

`class AddressesViewController: UIViewController, YMKMapObjectTapListener, YMKLayersGeoObjectTapListener {

func onObjectTap(with event: YMKGeoObjectTapEvent) -> Bool {

    return true
}

func onMapObjectTap(with mapObject: YMKMapObject, point: YMKPoint) -> Bool {
    guard let placemark = mapObject as? YMKPlacemarkMapObject else { return false }
    print(placemark)
    print("Something tapped")
    print(point.latitude, point.longitude)
    return true
}

@IBOutlet weak var mapView: YMKMapView!
let locationManager = CLLocationManager()
var currentLocation: CLLocation!
var lat: CLLocationDegrees?
var long: CLLocationDegrees?
var text: String!

override func viewDidLoad() {
    super.viewDidLoad()
    if (CLLocationManager.authorizationStatus() == .authorizedAlways) || (CLLocationManager.authorizationStatus() == .authorizedWhenInUse) {
        currentLocation = locationManager.location
        lat = currentLocation.coordinate.latitude
        long = currentLocation.coordinate.longitude
    } else {
        lat = 55.7558
        long = 37.6173
    }
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let mapObjects = mapView.mapWindow.map.mapObjects
    let placemark = mapObjects.addPlacemarks(with: [YMKPoint(latitude: lat!, longitude: long!), YMKPoint(latitude: 40.220395, longitude: 44.492963)], image: #imageLiteral(resourceName: "halp-full cap"), style: YMKIconStyle(anchor: CGPoint(x: 0, y: 0) as NSValue, rotationType: YMKRotationType.rotate.rawValue as NSNumber, zIndex: 0, flat: true, visible: true, scale: 1.5, tappableArea: nil))
    placemark[0].setIconWith(#imageLiteral(resourceName: "locationPointer"))
    mapObjects.addTapListener(with: self)
    mapView.mapWindow.map.addTapListener(with: self)
    mapView.mapWindow.map.move(
        with: YMKCameraPosition.init(target: YMKPoint(latitude: lat!, longitude: long!), zoom: 15, azimuth: 0, tilt: 0),
        animationType: YMKAnimation(type: YMKAnimationType.smooth, duration: 5),
        cameraCallback: nil)
}

}`

eberkovich commented 5 years ago

It does not use userData property?

EmmaVvv commented 5 years ago

When in onMapObjectTap(with mapObject: YMKMapObject, point: YMKPoint) -> Bool I put a breakpoint and in logs console pring mapObject.userData, it's nil

eberkovich commented 5 years ago

You need to put data to userData in advance.

EmmaVvv commented 5 years ago

Which method should I use for this? I can't uderstand this part.

eberkovich commented 5 years ago

userData

leningradspb commented 1 year ago

extension MyViewController: YMKMapObjectTapListener {

// MARK: - YMKMapObjectTapListener
func onMapObjectTap(with mapObject: YMKMapObject?, point: YMKPoint) -> Bool {
    guard let placemark = mapObject as? YMKPlacemarkMapObject { return false }

    // here you can do what you want to do with tapped placemark

    return true
}

}

https://github.com/yandex/mapkit-ios-demo/issues/6

latynskii commented 8 months ago

Author wrote about YMKMapObject and property from userData. He asked HOW he could configure "userData" this property for use the information when delegate onMapObjectTap work. By the way im intersted in this too.