2013-09-28 5 views
24

У меня есть контроллер табличного представления, завернутый в контроллер навигации. Контроллер навигации, похоже, автоматически применяет правильную вставку содержимого к контроллеру табличного представления, когда он представлен через presentViewController:animated:completion:. (Может кто-нибудь объяснить мне, как это работает?)iOS 7: Пользовательский контроллер представления контейнера и вставка содержимого

Однако, как только я завершу комбинацию в пользовательский контроллер представления контейнера и представляю, что вместо этого верхняя часть содержимого представления таблицы скрыта за панелью навигации , Есть ли что-то, что я могу сделать, чтобы сохранить поведение автоматической вставки содержимого в этой конфигурации? Должен ли я «пропустить» что-то в контроллере контейнера, чтобы это работало правильно?

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

ответ

4

Благодаря подсказке Йоханнеса Фаренкрюга, я понял следующее: automaticallyAdjustsScrollViewInsets действительно работает, как рекламируется, когда корневой вид контроллера детского просмотра является UIScrollView. Для меня это означает следующее расположение работа:

Content-контроллер внутри навигация контроллер внутри пользовательский контейнер вид контроллер.

Хотя это не делает:

Content-контроллер внутри пользовательского контейнера вид контроллер внутри навигации контроллера.

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

12

У меня была аналогичная проблема. Итак, на iOS 7 есть новое свойство на UIViewController под названием automaticallyAdjustsScrollViewInsets. По умолчанию установлено значение YES. Когда ваша иерархия представлений каким-либо образом более сложна, чем просмотр прокрутки/таблицы внутри контроллера навигации или панели вкладок, это свойство, похоже, не работает для меня.

Что я сделал, так это: я создал класс контроллера базового представления, который наследует все мои другие контроллеры представлений. Этот вид контроллер затем берет на себя явно устанавливая врезки:

Заголовок:

#import <UIKit/UIKit.h> 

@interface SPWKBaseCollectionViewController : UICollectionViewController 

@end 

Реализация:

#import "SPWKBaseCollectionViewController.h" 

@implementation SPWKBaseCollectionViewController 


- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    [self updateContentInsetsForInterfaceOrientation:self.interfaceOrientation]; 
} 

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    [self updateContentInsetsForInterfaceOrientation:toInterfaceOrientation]; 

    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; 
} 

- (void)updateContentInsetsForInterfaceOrientation:(UIInterfaceOrientation)orientation 
{ 
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) { 
     UIEdgeInsets insets; 

     if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 
      insets = UIEdgeInsetsMake(64, 0, 56, 0); 
     } else if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 
      if (UIInterfaceOrientationIsPortrait(orientation)) { 
       insets = UIEdgeInsetsMake(64, 0, 49, 0); 
      } else { 
       insets = UIEdgeInsetsMake(52, 0, 49, 0); 
      } 
     } 

     self.collectionView.contentInset = insets; 
     self.collectionView.scrollIndicatorInsets = insets; 
    } 
} 

@end 

Это также работает для веб-просмотров:

self.webView.scrollView.contentInset = insets; 
self.webView.scrollView.scrollIndicatorInsets = insets; 

Если есть более элегантный и надежный способ сделать это, пожалуйста, дайте мне знать! Значения жестко закодированных вставок плохо пахнут, но я не вижу другого способа, когда вы хотите сохранить совместимость с iOS 5.

+0

Я делаю что-то подобное в подобной ситуации. К сожалению, это не работает, если у вас есть UIRefreshControl для просмотра таблицы и поворот устройства во время обновления. Кажется, это обновляет вставки самостоятельно - в этом случае ошибочно. – Stefan

+0

Вы правы, мне тоже не нравятся жестко закодированные значения вставки. Может ли это быть сделано с помощью Auto Layout, так как это необходимо только для iOS 7? Как бы выглядело это ограничение и какой метод он мог бы использовать в классе контроллера? – tajmahal

+0

@tajmahal Я абсолютно согласен: мне тоже не нравятся жестко установленные значения. Как я уже сказал, мне не удалось найти другой способ, чтобы поддерживать совместимость с iOS 5. Если вы найдете более чистое решение, обязательно передайте его. Autolayout не будет работать для вставки, потому что вставки не могут быть настроены с автозапуском. –

3

UINavigationController вызывает недокументированный метод _updateScrollViewFromViewController: toViewController при переходе между контроллерами для обновления вложений содержимого. Вот мое решение:

UINavigationController + ContentInset.h

#import <UIKit/UIKit.h> 
@interface UINavigationController (ContentInset) 
- (void) updateScrollViewFromViewController:(UIViewController*) from toViewController:(UIViewController*) to; 
@end 

UINavigationController + ContentInset.m

#import "UINavigationController+ContentInset.h" 
@interface UINavigationController() 
- (void) _updateScrollViewFromViewController:(UIViewController*) from toViewController:(UIViewController*) to; 
@end 

@implementation UINavigationController (ContentInset) 
- (void) updateScrollViewFromViewController:(UIViewController*) from toViewController:(UIViewController*) to { 
    if ([UINavigationController instancesRespondToSelector:@selector(_updateScrollViewFromViewController:toViewController:)]) 
     [self _updateScrollViewFromViewController:from toViewController:to]; 
} 
@end 

Вызова updateScrollViewFromViewController: toViewController где-то в пользовательском контейнере контроллера представления

[self addChildViewController:newContentViewController]; 
[self transitionFromViewController:previewsContentViewController 
        toViewController:newContentViewController 
          duration:0.5f 
          options:0 
         animations:^{ 
          [self.navigationController updateScrollViewFromViewController:self toViewController:newContentViewController]; 

        } 
        completion:^(BOOL finished) { 
         [newContentViewController didMoveToParentViewController:self]; 
        }]; 
+0

Это все еще проблема с IOS9beta. Это решение отлично работало для меня. Для всех это тоже проблема. Пожалуйста, подайте радар для этого яблока, что делает этот метод общедоступным. – berbie

+0

Это работает для меня до iOS 8.4. В настоящее время на iOS 9B5 это перестало работать. Какие-нибудь догадки о том, почему? Этот метод существует, как указано здесь: https://github.com/JaviSoto/iOS9-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UINavigationController.h#L408 – dezinezync

+0

с использованием '- (void) _computeAndSprollScrollContentInsetDeltaForViewController: (id) arg1; 'вместо этого работает как для iOS 8, так и для меня. – dezinezync

5

FYI в случае, если у кого-либо возникает аналогичная проблема: похоже, что automaticallyAdjustsScrollViewInsets применяется, только если ваш scrollview (или tableview/collectionview/webview) является первым представлением в иерархии диспетчера своего представления.

Я часто добавляю UIImageView сначала в свою иерархию, чтобы иметь фоновое изображение. Если вы сделаете это, вы должны вручную установить края врезки на Scrollview в viewDidLayoutSubviews:

- (void) viewDidLayoutSubviews { 
    CGFloat top = self.topLayoutGuide.length; 
    CGFloat bottom = self.bottomLayoutGuide.length; 
    UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0); 
    self.collectionView.contentInset = newInsets; 

} 
2

Swift Решение

Это решение предназначается для IOS 8 и выше Swift.

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

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

Чтобы исправить это, я вызываю adjustChild:tableView:insetTop (показано ниже) после того, как создан контроллер представления дочернего табличного устройства и в методе viewDidLayoutSubviews контроллера родительского представления.

вид Столик зрения контроллера дочернего и контроллер представления родителя topLayoutGuide.length передаются adjustChild:tableView:insetTop способом, как это ...

// called right after childViewController is created 
adjustChild(childViewController.tableView, insetTop: topLayoutGuide.length) 

Метод adjustChild ...

private func adjustChild(tableView: UITableView, insetTop: CGFloat) { 
    tableView.contentInset.top = insetTop 
    tableView.scrollIndicatorInsets.top = insetTop 

    // make sure the tableview is scrolled at least as far as insetTop 
    if (tableView.contentOffset.y > -insetTop) { 
     tableView.contentOffset.y = -insetTop 
    } 
} 

Заявление tableView.scrollIndicatorInsets.top = insetTop настраивает индикатор прокрутки в правой части таблицы, чтобы он начинался чуть ниже навигационной панели. Это тонко и легко упускается из виду, пока вы не узнаете об этом.

следующее: viewDidLayoutSubviews ...

override func viewDidLayoutSubviews() { 
    if let childViewController = childViewController { 
     adjustChild(childViewController.tableView, insetTop: topLayoutGuide.length) 
    } 
} 

Обратите внимание, что весь приведенный выше код появляется в родительском контроллере представления.

Я понял это с помощью Christopher Pickslay's answer на вопрос «iOS 7 Table view не удается настроить настройку содержимого».

+0

У вас есть ссылка на «пост Кристофера Пикслая»? – Koen

+0

Привет @Koen. Я добавил ссылку на ответ Кристофера Пикслея в нижней части моего ответа. –

3

Вам не нужно вызывать любые недокументированные методы. Все, что вам нужно сделать, это позвонить setNeedsLayout на ваш UINavigationController. См. Другой ответ: https://stackoverflow.com/a/33344516/5488931

Смежные вопросы