iOS - Swift - кликабельные области на UIImage

Я работаю над проектом, в котором мне нужно нанести точки в определенных областях на изображение, представляющее человеческое тело. В Интерфейсном Разработчике я установил контейнер UIView, который занимает большую часть вертикального центра основного вида. В этом представлении контейнера я поместил UIImageView и установил изображение в IB. Графика намного больше, чем UIImageView и контейнер UIView, точнее, она выше. ContentMode UIImageView установлен в AspectFit, потому что я хочу, чтобы изображение не показывалось как больше, чем контейнер.

Код создает несколько экземпляров CGRect, которые являются областями, где касания пользователя что-то значат. Когда пользователь нажимает на представление контейнера, код используется для определения, находится ли точка в одной из областей, и если это так, в центре этой области рисуется точка.

Проблема в том, что когда я запускаю приложение на определенных симуляторах, прямоугольники региона находятся не в нужном месте на изображении. Например, когда я запускаю приложение на iPhone X, прямоугольная область, которая находится на месте для головы, выглядит нормально. Когда я запускаю приложение на iPhone XR, область прямоугольника отключается слева от головы.

Я использую координаты, чтобы определить прямоугольники региона, основанные на том, где, например, человеческая голова находится на изображении. Я чувствую, что это не правильный способ сделать это, поскольку AspectFit для ContentMode изображения, скорее всего, вызывает масштабирование изображения для сохранения аспекта.

Суть в том, что я хочу, чтобы прямоугольник был в нужном месте и размере независимо от масштаба изображения. Не уверен, имеет ли смысл то, как я это делаю, поэтому надеюсь, что появятся некоторые предложения, которые предложат лучший способ сделать это.

Обновление 1: UIImageView прикреплен к окружающему UIView, поэтому его ширина и высота такие же большие, как у контейнера. Поскольку изображение более тонкое, чем UIImageView, изображение отображается по центру. На прикрепленных изображениях фиолетовый фон - это UIImageView, показывающий самый верхний цвет фона UIView.

Обновление 2: я проверил шкалу ширины и высоты и обнаружил, что они разные. Коэффициент масштабирования по ширине равен 1,356565656565, а коэффициент масштабирования по высоте равен 2,104. Я попробовал формулы, приведенные с обоими масштабными коэффициентами, заданными Sweeper, и не повезло.

3 ответа

Вам просто нужно сделать некоторые математики.

На исходном изображении укажите регион, который пользователь может нажать. Запишите его x, y, w, h относительно изображения.

Выясните, насколько уменьшилось изображение при просмотре изображения. Поскольку вы сказали, что изображение выше, чем изображение, изображение подверглось масштабному коэффициенту imageViewHeight / imageHeight, Теперь мы будем ссылаться на это как scaleFactor,

Координата Y региона также должна была уменьшиться на scaleFactorтак что вы умножаете regionY от scaleFactor получить newY,

Ширина и высота региона будут делать то же самое, поэтому умножьте их на scaleFactor и получить newWidth а также newHeight,

Координата X области относительно вида изображения немного хитрая. Вам необходимо учитывать количество пустого пространства, созданного представлением изображения, путем его уменьшения. это emptySpace рассчитывается по (imageViewWidth - newWidth) / 2, Затем, чтобы вычислить координату X новой области относительно вида изображения, вы делаете emptySpace + X * scaleFactor,

Теперь прямоугольник (newX, newY, newWidth, newHeight) это область относительно изображения, которую пользователь может нажать!

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

@IBOutlet weak var tabMenu:          NSLayoutConstraint!
@IBOutlet weak var topConstraint:    NSLayoutConstraint!
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!

@IBOutlet weak var backgroundImg: UIImageView!
@IBOutlet weak var rectangleImg:  UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Check if it's a iPhone X
    if #available(iOS 11, *) {
        let safeArea = UIApplication.shared.delegate?.window??.safeAreaInsets

        // If its a x phone i use safe instead of superView
        guard let safe = safeArea else { return }
        if safe.bottom > 0 {
            topConstraint.constant = safe.top
            bottomConstraint.constant = safe.bottom + tabMenu.constant
        }
    }
}

override func viewDidAppear(_ animated: Bool) {

    // Here I set the rectangle to 36% of the width and height (change to what you want)
    rectangleImg.frame = CGRect(x: 0, y: 0, width: backgroundImg.frame.width * 0.36,
    height: backgroundImg.frame.height * 0.36)

    // Last I put the rectangle in the center of background image
    rectangleImg.center.x = backgroundImg.center.x
    rectangleImg.center.y  = backgroundImg.center.y

}

Надеюсь, этот код может помочь!

Корень моей проблемы заключается в том, что у меня было четыре стороны UIImageView, прикрепленные к его виду контейнера. Когда ширина устройства изменилась, оно корректно масштабировало изображение, но это вызвало "растяжение" графики. Это вызвало, например, увеличение ширины головы. На данный момент я решил эту проблему, зафиксировав ширину изображения, чтобы координаты, которые я придумала из исходного изображения, остались без изменений, независимо от устройства.

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

Я также использовал ответ на этот вопрос, чтобы переделать код: создать интерактивную диаграмму тела

Другие вопросы по тегам