Как правильно перевести view.преобразовать фрейм UIBarButtonItem в навигационной панели в координаты главного окна

#ios #swift #uibarbuttonitem

#iOS #swift #uibarbuttonitem

Вопрос:

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

На скриншоте я пытаюсь нарисовать красный круг вокруг второй кнопки (на которую указывает всплывающее окно), но когда я перевожу координаты, он фактически рисуется вокруг 3-й кнопки. Когда я запускаю тот же код на первой кнопке (поисковое увеличительное стекло), он работает просто отлично, и красный круг нарисован правильно.

Изображение навигационной панели с четырьмя кнопками, третья с красным кружком вокруг нее и всплывающей стрелкой, указывающей на вторую кнопку

В моем коде я просто беру barButtonItem из всплывающего окна, и я проверил, что он указывает на правильную кнопку.

 if let buttonItem = self.popoverPresentationController?.barButtonItem {
        
    if let view = buttonItem.value(forKey: "view") as? UIView,
        let mainView = containingViewController?.navigationController?.view {

        let viewFrame = view.frame
        print("viewFrame: (viewFrame)")
            
        // This should be translating coords to the main window.
        let windowRect = view.convert(viewFrame, to: nil)
 
        print("Window RECT (windowRect)")

        let circlePath = UIBezierPath(ovalIn: windowRect)
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = circlePath.cgPath
                
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.lineWidth = 3.0
        mainView.layer.addSublayer(shapeLayer)
     }
  }
  

Я распечатываю view фрейм, и эти цифры кажутся правильными, но переведенный windowRect отключен, когда это не самая левая кнопка на навигационной панели.

Для кнопки поиска (самая левая на скриншоте):

 viewFrame: (0.0, 0.0, 46.0, 44.0)
Window RECT (617.0, 27.0, 46.0, 44.0)
  

Для второй кнопки (на которую указывает всплывающее окно на скриншоте) прямоугольник окна смещен на 108 вместо 54, как ожидалось:

 viewFrame: (54.0, 0.0, 46.0, 44.0)
Window RECT: (725.0, 27.0, 46.0, 44.0)
  

Каждый UIBarButtonItem имеет ширину 46, и я предполагаю, что интервал между ними равен 8. Это дает начальный x 54.0 во втором наборе чисел. Но при переводе в координаты окна каким-то образом это становится разницей в 108; так что это компенсируется целой кнопкой. Я пытался настроить таргетинг на 3-ю и 4-ю кнопки, и он всегда отключен на одну полную ширину кнопки. Как вы можете видеть, красный круг сосредоточен на 3-й кнопке, но это не та, которую я пытаюсь выделить.

Я пытался перевести в mainView вместо to: nil при выполнении view.convert , но это не имеет никакого значения. Цифры возвращаются точно такими же. Есть мысли о том, что я делаю неправильно, или это «но» (известное или иное), и мне придется делать сумасшедшие вещи в моем коде, чтобы заставить его работать правильно?

Обновлено, чтобы добавить: Если я удалю перевод и просто помещу слой в супервизию того вида, который я нашел:

 let circlePath = UIBezierPath(ovalIn: viewFrame)
 // code to create shapelayer
view.superview?.layer.addSublayer(highlightItemLayer!)
  

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

Комментарии:

1. Вы уверены, что это не сетчатка?

2. Я тестирую в симуляторе на ipad pro 11 «, используя iOS 13.3. Как бы я определил, была ли это сетчатка? Другое поле, которое я пытаюсь обвести, также выходит немного сдвинутым вниз и вправо на том же симуляторе. Это заставляет меня думать, что перевод не учитывает маржу или что-то в этом роде. Я делал другие подобные переводы, когда пользователь нажимал на экран, и они были прекрасными.

3. Когда я удаляю перевод во 2-м поле (не в UIBarButtonItem), он работает отлично. что-то определенно не так в том, как я делаю перевод, или как происходит перевод.

Ответ №1:

Я думаю, что я решил это. Я изменил строку преобразования с let windowRect = view.convert(viewFrame, to: nil) , чтобы использовать супервизор вместо просто представления:

 let windowRect = view.superview?.convert(viewFrame, to: nil)
  

и теперь красный круг отображается в соответствующем месте (обратите внимание, что я также увеличил его размер, используя translatedFrame.insetBy(dx: -10, dy: -10) в windowRect перед созданием пути.

красный кружок на правильном значке