IOS7 - Установка selectedIndex UITabBarController разбивает события касания вдоль правого края экрана?
Я поразил странную проблему с UITabBarController
на iOS7 и не могу найти способ обхода, поэтому любая помощь будет приветствоваться!
Сценарий:
- Навигационное приложение, использующее ландшафтную ориентацию на iPad.
- Приложение состоит из основного вида и второго представления, которое является UITabBarController.
- TabBarController имеет две вкладки.
- В первом представлении есть две кнопки - каждая кнопка выполняет переход к контроллеру панели вкладок и устанавливает другую вкладку как выбранную. (т.е. кнопка1 выбирает первую вкладку, а кнопка2 выбирает вторую вкладку).
- Настройка вкладки выполняется в
prepareForSegue
, вызывая setSelectedIndex
в контроллере панели вкладок.
![Simple storyboard that demonstrates the issue]()
Результат:
В iOS 7 я обнаружил, что представление, показанное в контроллере панели вкладок, не регистрирует никаких событий касания вдоль правого края представления! Таким образом, в раскадровке, показанной выше, UISwitch в правой части экрана не может быть задействован.
Я даже прикреплял распознаватель жестов к представлениям и использовал его для регистрации области экрана, на которую можно было коснуться - он, похоже, регистрирует события касания примерно до x = 770 точек в поперечнике. Остальные 1/4 экрана "неприкасаемые"!
После сеанса, если вы вручную переключитесь на другую вкладку и снова вернетесь, события касания будут "фиксированными", а полный вид снова будет реагировать на касания.
Это не похоже на проблему на iOS 5/6.
Любая помощь, которую очень ценят:
- Что вызывает это в первую очередь (ошибка/изменение iOS7?)
- Как еще я могу обойти это? Я попытался позвонить
setSelectedViewController
, а также использовать setSelectedIndex
, и это похоже на то же самое.
Спасибо заранее.
Ответы
Ответ 1
В итоге я поднял это с помощью технической поддержки разработчиков, и это похоже на ошибку. Это ответ, который я получил от Apple:
Вид контейнера, который настраивается контроллером панели табуляции, чтобы содержать ваш контроллер просмотра, не изменяется, чтобы учесть, что интерфейс находится в альбомной ориентации. Его размеры в то время, когда отображается ваш контроллер вида, составляют 768 (ширина) x 1024 (высота).
Иерархия представлений выглядит так, когда отображается выбранное представление табуляции:
UIWindow
/* Navigation Controller */
UILayoutContainerView
UINavigationTransitionView
UIViewControllerWrapperView
/* Tab bar controller */
UILayoutContainerView
UITransitionView
UIViewControllerWrapperView <-- Incorrectly sized.
/* MyViewController */
MyViewController.view
Неверный размер UIViewControllerWrapperView не вызывает проблемы с отображением, потому что subviews все еще отображаются, даже если они находятся за пределами границ надзора. Однако маршрутизация событий намного более строгая. События в правой четверти экрана никогда не маршрутизируются в представлении диспетчера просмотров, потому что тест с ошибкой выходит из строя в UIViewControllerWrapperView с неправильным размером, где событие выходит за пределы UIViewControllerWrapperView.
В качестве обходного пути я подклассифицировал UITabBarController и добавил в viewWillAppear следующее:
@implementation FixedIOS7TabBarController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Fix the frame of the UIViewControllerWrapperView
self.selectedViewController.view.superview.frame = self.view.bounds;
}
@end
Надеюсь, что это поможет кому-то еще...
Ответ 2
Как объяснено в этом ответе,
Вид контейнера, который настраивает контроллер панели вкладок, чтобы содержать контроллер просмотра не изменяется для учета интерфейса находясь в ландшафтной ориентации. Его размеры во время вашего просмотра отображается контроллер 768 (ширина) x 1024 (высота).
Я столкнулся с этой проблемой, когда TabBarController изначально отображался в портретном режиме. Когда устройство было повернуто в ландшафтный режим, вид не реагировал с правой стороны.
Решение, предложенное в этом ответе, не работает для меня, потому что viewWillAppear:
вызывается только один раз. Тем не менее, viewDidLayoutSubvews
вызывается всякий раз, когда изменяется вид, включая поворот, поэтому мое решение заключалось в подклассе UITabBarController и выполнении обходного пути в viewDidLayoutSubvews
:
@implementation FixedIOS7TabBarController
- (void)viewDidLayoutSubviews
{
// fix for iOS7 bug in UITabBarController
self.selectedViewController.view.superview.frame = self.view.bounds;
}
@end
Ответ 3
В конце найдите обходное решение здесь:
self.view.autoresizesSubviews = YES;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Ответ 4
Правильный ответ не работает для меня, потому что пользователь может изменить ориентацию; И это еще не осязаемо в какой-то области, когда меняют ориентацию.
Итак, я создаю свое собственное решение, я не уверен, что это нормальное решение.
@implementation FixedIOS7TabBarController
- (UIView*)findInSubview:(UIView*)view className:(NSString*)className
{
for(UIView* v in view.subviews){
if([NSStringFromClass(v.class) isEqualToString:className])
return v;
UIView* finded = [self findInSubview:v className:className];
if(finded)
return finded;
}
return nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIView* wraperView = [self findInSubview:self.view className:@"UIViewControllerWrapperView"];
wraperView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
@end
Прекрасно работает для меня!
Ответ 5
В списке контроллеров представления в левой части экрана найдите обработчики вида/представления, перетащите представление под первым ответчиком, чтобы он не был связан с представлением контроллера вида.
Затем перейдите на вкладку макета с правой стороны, выберите все 4 анкера и оба набора стрелок изменения размера (горизонтально + вертикально).
Затем перетащите представление обратно туда, где оно было первоначально (чуть ниже контроллера вида).