iOS 7.1 UITableView layoutSubviews 问题

Posted

技术标签:

【中文标题】iOS 7.1 UITableView layoutSubviews 问题【英文标题】:iOS 7.1 UITableView layoutSubviews issue 【发布时间】:2015-01-07 15:10:25 【问题描述】:

我正在开发一个必须同时支持 ios 8 和 iOS 7.1 的项目。现在我遇到了一个只出现在 iOS 7.1 上但在 iOS 8 上正常工作的问题。我有一个 ViewController,它包含一个 tableview 和一个 tableHeaderView 中的自定义视图。我将发布代码如下。所有约束都是以编程方式添加的。

//视图控制器。

-(void)viewDidLoad

  [super viewDidLoad];

  self.commentsArray = [NSMutableArray new];

  [self.commentsArray addObject:@"TEST"];
  [self.commentsArray addObject:@"TEST"];
  [self.commentsArray addObject:@"TEST"];
  [self.commentsArray addObject:@"TEST"];
  [self.commentsArray addObject:@"TEST"];
  [self.commentsArray addObject:@"TEST"];

  [self.view addSubview:self.masterTableView];

  self.masterTableView.tableHeaderView = self.detailsView;

  [self.view setNeedsUpdateConstraints];




- (void)viewWillAppear:(BOOL)animated

  [super viewWillAppear:animated];
  [self.view layoutIfNeeded];



//Table view getter
- (UITableView *)masterTableView

  if(!_masterTableView)
  
    _masterTableView = [UITableView new];
    _masterTableView.translatesAutoresizingMaskIntoConstraints = NO;

    _masterTableView.backgroundColor                = [UIColor greyColor];

    _masterTableView.delegate                       = self;
    _masterTableView.dataSource                     = self;

    _masterTableView.separatorStyle                 = UITableViewCellSeparatorStyleNone;
    _masterTableView.showsVerticalScrollIndicator   = NO;
    _masterTableView.separatorInset                 = UIEdgeInsetsZero;

  

  return _masterTableView;


-(void)updateViewConstraints

 NSDictionary *views = @
      @"table"        : self.masterTableView,
      @"details"      : self.detailsView,
 ;


  NSDictionary *metrics = @
                            @"width"  : @([UIScreen mainScreen].applicationFrame.size.width)
                            ;
    //Table view constraints
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[table]-0-|" options:0 metrics:0 views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[table]-0-|" options:0 metrics:0 views:views]];

  //Details View
  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[details(width)]-0-|" options:0 metrics:metrics views:views]];
  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[details]-0-|" options:0 metrics:metrics views:views]];




//Details View Getter
- (DetailsView *)detailsView

  if(!_detailsView)
  

   _detailsView = [[DetailsView alloc]initWithFrame:CGRectMake(0, 0, 0, 100)];
    _detailsView.backgroundColor = [UIColor orangeColor];

  return _detailsView;

现在细节视图包含一些基本的子视图,它们都派生自 UIView,细节视图本身派生自更通用的超类。我将发布代码如下。

//Parent View 
@interface ParentView (): UIView

- (instancetype)init

  self = [super init];

  if (self)
  
    [self setupViews];
  

  return self;



- (void)setupViews

  [self addSubview:self.publishedTimeView];


- (void)updateConstraints

  NSDictionary *views = @
                          @"time"         : self.publishedTimeView,
                          ;


  // Header with published video time
  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[time]-10-|" options:0 metrics:0 views:views]];
  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[time(11)]" options:0 metrics:0 views:views]];

  [super updateConstraints];


//Getter for the timePublished view added to the detail view. Will not post all its related code for //the sake of brevity.
- (TimePublishedDetailView *)publishedTimeView

  if(!_publishedTimeView)
  
    _publishedTimeView = [TimePublishedDetailView new];
    _publishedTimeView.translatesAutoresizingMaskIntoConstraints = NO;
  

  return _publishedTimeView;


//Child View (or the detailsView) of the view controller.

@interface DetailsView : ParentView


@implementation RecordingDetailsView

- (void)updateConstraints

  NSDictionary *views = @
                          @"time"         : self.publishedTimeView,
                          ;

   //Vertical alignment of all views

  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[time]" options:0 metrics:nil views:views]];

  [super updateConstraints];




- (void)setModel:(DetailViewModel *)model

  self.publishedTimeView.date = model.dateTime;

  [self setNeedsUpdateConstraints];
  [self layoutSubviews];

现在在 iOS 8 上看起来像这样:

但是在 iOS 7.1 上,这将崩溃并显示以下错误消息:

“异常:执行-layoutSubviews后仍然需要自动布局。UITableView的-layoutSubviews实现需要调用super”

我已经用谷歌搜索了这个并在我的布局调用中使用了代码,看看我是否可以解决这个问题,但到目前为止还没有成功。如果有人可以就如何解决此问题发布一些提示或建议,我将不胜感激。

【问题讨论】:

我在做什么有什么理由吗?能具体点吗? 抱歉,我的编辑没有更新!您是否尝试过在不同的视图生命周期方法中做事?您可能会对正在发生的事情有更多的了解 是的,我已经对此进行了相当多的测试和实验。甚至还注释掉了 timePublishedView,这似乎仍然只发生在 iOS 7 上。 【参考方案1】:

我知道这个问题很老,但我最近遇到了类似的问题,经过大量谷歌搜索、尝试和失败后,我在 this answer 的帮助和一些更改下使它工作。

只需将此类别添加到您的项目中并仅调用一次[UITableView fixLayoutSubviewsMethod];(我建议在AppDelegate 内)。

#import <objc/runtime.h>
#import <objc/message.h>

@implementation UITableView (FixUITableViewAutolayoutIHope)

+ (void)fixLayoutSubviewsMethod

    Method existing = class_getInstanceMethod(self, @selector(layoutSubviews));
    Method new = class_getInstanceMethod(self, @selector(_autolayout_replacementLayoutSubviews));

    method_exchangeImplementations(existing, new);


- (void)_autolayout_replacementLayoutSubviews

    [super layoutSubviews];
    [self _autolayout_replacementLayoutSubviews]; // not recursive due to method swizzling
    [super layoutSubviews];


@end

【讨论】:

以上是关于iOS 7.1 UITableView layoutSubviews 问题的主要内容,如果未能解决你的问题,请参考以下文章

iOS 7.1 中未显示 UITableView 选定的单元格分隔符

在自定义单元格中调整 iOS 7.1 中的 UILabel 大小

UISearchBar 在 iOS 7.1 上添加到 UITableViewCell 时会更改其超级视图

如何使用 Xcode 7.1 和 iOS 部署目标 iOS 7.1 启动应用程序?

iOS 7.1 模拟器不适用于 Xcode 7.1

iOS 版本更新摘要iOS 7.1