Nano Hash - криптовалюты, майнинг, программирование

Нарисуйте MKPointAnnotation с заголовком в изображении MKSnapshot

Я пытаюсь нарисовать аннотацию точно так же, как в «живом» MapView, но затем в MKSnapshot. Почему MKSnapshot > потому что я хочу иметь неинтерактивные MapViews в UITableView и использовать изображения более эффективно.

Я могу получить булавку для рисования (хотя и не точку, как в iOS 11, булавка выглядит старой) с помощью MKPinAnnotationView, но и тогда на изображении нет заголовка аннотации. Используя почти такой же код: Снимок MKMapView в iOS7.


Ответы:


1

Вы можете использовать следующие шаги:

  • с MKMapSnapshotter вы получите изображение карты без аннотаций

  • вы можете получить аннотации из вашего MKMapView

  • для каждой аннотации определить ее положение в координатном пространстве изображения

  • нарисуйте там собственный пин (может выглядеть как булавки Apple)

  • определите текст и размер заголовка аннотации и нарисуйте его по центру ниже положения булавки

Результат может выглядеть очень похоже на то, что отображает MKMapView. На прикрепленном снимке экрана в верхней части находится MKMapView, а в нижней — UIImageView с результирующим изображением. Выглядит похоже, не так ли?

введите описание изображения здесь

Вот код Swift 4 для скриншота выше:

    @IBOutlet weak var imageView: UIImageView!

    @IBAction func onSnap(_ sender: Any) {
        let options: MKMapSnapshotOptions = MKMapSnapshotOptions()
        options.region = self.mapView.region
        options.size = self.mapView.frame.size
        options.scale = UIScreen.main.scale

        let customPin = UIImage(named: "customPin.pdf")

        let snapshotter = MKMapSnapshotter(options: options)
        snapshotter.start { [weak self] (snapshot: MKMapSnapshot?, error: Error?) -> Void in
            guard error == nil, let snapshot = snapshot else { return }

            UIGraphicsBeginImageContextWithOptions(snapshot.image.size, true, snapshot.image.scale)
            snapshot.image.draw(at: CGPoint.zero)

            let titleAttributes = self?.titleAttributes()
            for annotation in (self?.mapView.annotations)! {
                let point: CGPoint = snapshot.point(for: annotation.coordinate)
                if let customPin = customPin {
                    self?.drawPin(point: point, customPin: customPin)
                }
                if let title = annotation.title as? String {
                    self?.drawTitle(title: title,
                                    at: point,
                                    attributes: titleAttributes!)
                }
            }
            let compositeImage = UIGraphicsGetImageFromCurrentImageContext()
            self?.imageView.image = compositeImage
        }
    }

    private func drawTitle(title: String,
                           at point: CGPoint,
                           attributes: [NSAttributedStringKey: NSObject]) {
        let titleSize = title.size(withAttributes: attributes)
        title.draw(with: CGRect(
            x: point.x - titleSize.width / 2.0,
            y: point.y + 1,
            width: titleSize.width,
            height: titleSize.height),
                   options: .usesLineFragmentOrigin,
                   attributes: attributes,
                   context: nil)
    }

    private func titleAttributes() -> [NSAttributedStringKey: NSObject] {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        let titleFont = UIFont.systemFont(ofSize: 10, weight: UIFont.Weight.semibold)
        let attrs = [NSAttributedStringKey.font: titleFont,
                     NSAttributedStringKey.paragraphStyle: paragraphStyle]
        return attrs
    }

    private func drawPin(point: CGPoint, customPin: UIImage) {
        let pinPoint = CGPoint(
            x: point.x - customPin.size.width / 2.0,
            y: point.y - customPin.size.height)
        customPin.draw(at: pinPoint)
    }
}

Альтернативный

Если вы предпочитаете рисовать MKMarkerAnnotationView (например, чтобы получить красивую тень бесплатно), вы можете изменить drawPin на это:

private func drawPin(point: CGPoint, annotation: MKAnnotation) {
    let annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "test")
    annotationView.contentMode = .scaleAspectFit
    annotationView.bounds = CGRect(x: 0, y: 0, width: 40, height: 40)
    annotationView.drawHierarchy(in: CGRect(
        x: point.x - annotationView.bounds.size.width / 2.0,
        y: point.y - annotationView.bounds.size.height,
        width: annotationView.bounds.width,
        height: annotationView.bounds.height),
                                 afterScreenUpdates: true)
}

Не забудьте изменить вызов на

self?.drawPin(point: point, annotation: annotation)

Тогда результат выглядит так:

введите описание изображения здесь

08.03.2018
  • Это почти то, что я хочу, спасибо! Теперь я пытаюсь объединить ваш код с моим, поскольку я рисую аннотацию, используя MKMarkerAnnotationView вместо пользовательского UIImage. Это дает тень, как на первом изображении вашего ответа :-) Однако метка затем отключается и находится в верхнем левом углу маркера. Любая подсказка? Спасибо! 09.03.2018
  • @JoostvandenAkker Я добавил альтернативу, используя MKMarkerAnnotationView, в конце моего ответа выше. 10.03.2018
  • Рад, что это помогло! Пожалуйста, примите мои ответы (зеленая галочка) на два вопроса. 10.03.2018
  • Это одно из лучших решений для этой задачи. Большое спасибо! Однако у меня есть один вопрос. Я не смог найти в коде, какой параметр изменить, чтобы я мог настроить расстояние заголовка аннотации от пользовательского вывода? Я попытался изменить y: point.y + 1 в методе drawTitle. 31.07.2020
  • Если вы используете что-то вроде 'y: point.y + 16' в методе drawTitle, заголовок отображается на снимке ниже булавки. 12.08.2020
  • @StephanSchlecht я люблю тебя 29.06.2021
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

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

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..