Фрейм элемента Swift -Tabbar возвращает сомнительное значение при преобразовании фрейма в окно

#ios #swift #uitabbarcontroller #uitabbaritem #cgrect

#iOS #swift #uitabbarcontroller #uitabbaritem #cgrect

Вопрос:

У меня есть панель вкладок с 5 элементами. Чтобы получить фрейм первого элемента панели вкладок и установить что-то на основе этого фрейма, я использую это, которое работает отлично:

 guard let firstTab = tabBarController?.tabBar.items?[0].value(forKey: "view") as? UIView else { return }
        
guard let window = UIApplication.shared.windows.filter({$0.isKeyWindow}).first else { return }

let windowRect = lastTab.convert(firstTab.frame, to: window)

print(firstTab) // (2.0, 1.0, 79.00000000298023, 48.0)
print(windowRect) // (4.0, 689.0, 79.00000000298023, 48.0)
 

Но когда я пытаюсь использовать приведенный выше код, чтобы получить фрейм 5-й вкладки, значения неверны. При настройке tabBar.items?[4] x координата кадра находится за пределами экрана на 665 в windowRect:

 guard let lastTab = tabBarControlle?.tabBar.items?[4].value(forKey: "view") as? UIView else { return }

guard let window = UIApplication.shared.windows.filter({$0.isKeyWindow}).first else { return }

let windowRect = lastTab.convert(lastTab.frame, to: window)

print(lastTab) // (332.99999999701976, 1.0, 79.00000000298023, 48.0)
print(windowRect) // (665.9999999940395, 689.0, 79.0000000029803, 48.0)
 

Но при настройке tabBar.items?[2] я получаю правильную координату x в 336 в windowRect:

 // setting the 2nd item gives me the correct frame for the 4th item
guard let lastTab = tabBarControlle?.tabBar.items?[2].value(forKey: "view") as? UIView else { return }

guard let window = UIApplication.shared.windows.filter({$0.isKeyWindow}).first else { return }

let windowRect = lastTab.convert(lastTab.frame, to: window)

print(lastTab) // (168.00000000596046, 1.0, 77.99999998807907, 48.0)
print(windowRect) // (336.0000000119209, 689.0, 77.99999998807908, 48.0)
 

Почему tabBar.items?[2] возвращается значение for tabBar.items?[4] в фрейме окна?

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

1. не связано с вашим вопросом, но почему бы и нет просто windows.first(where: .isKeyWindow) ?

2. Когда в XCode 12/13 начало появляться предупреждение, я начал использовать .filter({..}) , потому что это был первый ответ, который, как я обнаружил, сработал, и я просто никогда не переключался. Я видел . другой ответ, но к тому времени весь мой код использовался .filter .

3. filter будет излишне перебирать всю коллекцию. В этом случае это не имеет значения, потому что окон всего несколько. Убедитесь, что всегда используйте first(where:) , чтобы он обеспечивал ранний выход при выполнении условия.

4. ohhhhhhh, я никогда не знал, узнать что-то новое каждый день. Спасибо за совет. Теперь я собираюсь переключить их все 😊. Если я собираюсь добавить предложение the, я мог бы также использовать более короткий синтаксис

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

Ответ №1:

Вы пропустили .superview .

 private func convertTabFrame(for index: Int) -> CGRect? {
    guard let window = UIApplication.shared.windows.first(where: {$0.isKeyWindow}) else { return nil }
    guard let tabView = self.tabBarController?.tabBar.items?[index].value(forKey: "view") as? UIView else { return nil }
    return tabView.superview?.convert(tabView.frame, to: window)
}