弹出时,多行UILabel自动布局会折叠为1个线条

时间:2014-04-30 20:30:41

标签: ios uilabel autolayout

Here is the sample project demonstrating the problem

这是什么?
UIViewControllers下的堆栈中有两个UINavigationController。除了从一个到另一个呈现之外,每个都与彼此无关。在两个控制器中,都有一个UILabel。每个都使用Autolayout。每个标签都包含任意数量的行label.numberOfLines = 0

什么有效?
从viewController A(root)转换到viewController BB被分配并启动。 B看起来很好。

出了什么问题?
B过渡到A。在ViewDidDisappearB中的标签决定它将不再显示超过1行,即使其numberOfLines设置为0.当B被推入堆栈时,标签只显示1个衬垫而不是多个。

是什么造成的?
不知道。但是查看A标签numberOfLines设置为0.如果要删除该行,则B中的标签不会折叠。

问题:但是为什么?我喜欢A有多行标签,我该怎样克服这个?


一个

@implementation FirstViewController
{
    BugController *_bugController;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Bar Button
    UIBarButtonItem *helpBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"BUG" style:UIBarButtonItemStylePlain target:self action:@selector(bugTapped)];
    [self.navigationItem setLeftBarButtonItem:helpBarButtonItem];

    // A sample label
    UILabel *someLabel = [[UILabel alloc] init];
    [someLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
    [someLabel setText:@"Tap BUG to see a bunch of text in many lines... tap back... then tap BUG again to see that the text has gone to 1 liner.... WTF?"];
    [self.view addSubview:someLabel];

    // Comment it out to see that problem is fixed
#warning This one liner is a culprit, removing it will make everything normal but WHY?
    [someLabel setNumberOfLines:0];
#warning end of warning


    //Constraints
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[someLabel]-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(someLabel)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[someLabel]-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(someLabel)]];
}

- (void)bugTapped
{
    // Reuse controller
    if (!_bugController) {
        _bugController = [[BugController alloc] init];
    }
    [self.navigationController pushViewController:_bugController animated:YES];
}

B

@implementation BugController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Setting up stuff
    UILabel *header = [[UILabel alloc] init];
    [header setTranslatesAutoresizingMaskIntoConstraints:NO];
    [header setText:@"This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. "];
    [header setNumberOfLines:0];
    [self.view addSubview:header];

    // Constraints
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[header]-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(header)]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:header attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
}

请在上面的示例代码链接中查看!


使用变通方法更新1!使用code provided by Misha Vyrko后,我意识到将preferredMaxLayoutWidth设置为非零可以克服UILabel中的错误。

Non broken sample project

添加到BugViewController

// Constraints
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[header]-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(header)]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:header attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
    [header setPreferredMaxLayoutWidth:1]; // NEWLY ADDED

我仍然在寻找解释为什么会发生这种情况的解释,以及更好的解决方法。


更新2更正通过将PreferredMaxLayoutWidth设置为1,label.frame.size.height实际上会扩展到预期的高度,如果宽度实际为1.这意味着如果您有任何约束依赖标签的高度,无效。您需要将其明确设置为估计宽度。如果没有帮助,将无法处理轮换,请注意这一点!

4 个答案:

答案 0 :(得分:4)

在bugController中,如果你设置了所有约束,你就没有足够的布局标签约束

@interface BugController ()

@property (nonatomic, strong) UILabel *header;

@end

@implementation BugController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Setting up stuff
    self.header = [[UILabel alloc] init];
    [self.header  setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.header  setText:@"This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing! "];
    [self.header  setBackgroundColor:[UIColor redColor]];
    [self.header  setNumberOfLines:0];
    [self.view addSubview:self.header ];


    // Constraints
    //    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[header]-|"
    //                                                                      options:0
    //                                                                      metrics:0
    //                                                                        views:NSDictionaryOfVariableBindings(header)]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.header
                                                      attribute:NSLayoutAttributeCenterY
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self.view
                                                      attribute:NSLayoutAttributeCenterY
                                                     multiplier:1
                                                       constant:0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.header
                                                      attribute:NSLayoutAttributeCenterX
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self.view
                                                      attribute:NSLayoutAttributeCenterX
                                                     multiplier:1
                                                       constant:0]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.header
                                                      attribute:NSLayoutAttributeHeight
                                                      relatedBy:NSLayoutRelationLessThanOrEqual
                                                         toItem:self.view
                                                      attribute:NSLayoutAttributeHeight
                                                     multiplier:1
                                                       constant:0]];
    self.header.preferredMaxLayoutWidth = self.view.frame.size.width;


    [self.view needsUpdateConstraints];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    self.header.preferredMaxLayoutWidth = self.view.frame.size.width;
    [self.view needsUpdateConstraints];
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}

@end

答案 1 :(得分:1)

Here is the link for the working project.

问题的根源尚不清楚,但遵循“如果你不知道该做什么,做点什么”的原则,我通过将两个标签存储为属性来实现它(这可能是不必要的,可能是实例变量没关系)并在两个视图控制器中实现以下回调(记住,你说,删除一行[someLabel setNumberOfLines:0];在第一个控制器中修复第二个,所以这里我们去):

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    self.yourLabel.numberOfLines = 1; 
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.yourLabel.numberOfLines = 0; 
}

它闻起来像UILabel类中的一个错误,但我确定并不是那么酷。祝你好运!

答案 2 :(得分:0)

让我回答你的问题。

为什么?

我没弄清楚但是通过我的代码可能会回答你。我的猜测是,它每次都会在 viewDidLoad 中创建一个新的UILabel,而不会清除之前的那些。

我怎样才能克服这个?

我试了几件事。以下事情对我有用

  1. 我试图提供_bugController而不是在导航控制器中推送它。

    [self presentViewController:_bugController animated:YES completion:nil]
    
  2. 不重用bugController对象。每次想要推送它时都会创建一个新对象。

  3. 将您的代码移至viewWillAppear并在消失时使所有UILabel为零。这是我的代码:

  4. FirstViewController

      #import "FirstViewController.h"
      #import "BugController.h"
      @interface FirstViewController ()
    
      @end
    
      @implementation FirstViewController
      {
          BugController *_bugController;
      }
    
      - (void)viewDidLoad
      {
          [super viewDidLoad];
        // Bar Button
        UIBarButtonItem *helpBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"BUG" style:UIBarButtonItemStylePlain target:self action:@selector(bugTapped)];
        [self.navigationItem setLeftBarButtonItem:helpBarButtonItem];
    
      }
    
      - (void)viewWillAppear:(BOOL)animated {
        // A sample label
        UILabel *someLabel = [[UILabel alloc] init];
        [someLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
        [someLabel setText:@"Tap BUG to see a bunch of text in many lines... tap back... then tap BUG again to see that the text has gone to 1 liner.... WTF?"];
    
        [self.view addSubview:someLabel];
    
        // Comment it out to see that problem is fixed
      #warning This one liner is a culprit, removing it will make everything normal but WHY?
        [someLabel setNumberOfLines:0];
      #warning end of warning
    
    
        //Constraints
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[someLabel]-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(someLabel)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[someLabel]-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(someLabel)]];
      }
    
    
      - (void)viewWillDisappear:(BOOL)animated {
    
        for (UIView *subView in self.view.subviews) {
          if ([subView isKindOfClass:[UILabel class]]) {
            UILabel *label = (UILabel *)subView;
            label.text = @"";
            label = nil;
          }
        }
        [super viewWillDisappear:animated];
      }
    
      - (void)bugTapped
      {
          // Reuse controller
          if (!_bugController) {
              _bugController = [[BugController alloc] init];
          }
          [self.navigationController pushViewController:_bugController animated:YES];
      }
    
      @end
    

    BugController

    //

      #import "BugController.h"
    
      @interface BugController ()
    
      @end
    
      @implementation BugController
    
      - (void)viewDidLoad
      {
          [super viewDidLoad];
      }
    
      - (void)viewWillAppear:(BOOL)animated {
    
        UILabel *header = [[UILabel alloc] init];
        [header setTranslatesAutoresizingMaskIntoConstraints:NO];
        [header setText:@"This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. This is a multiple line thing. "];
        [header setNumberOfLines:0];
        header.tag = 111;
        [self.view addSubview:header];
    
        // Constraints
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[header]-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(header)]];
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:header attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
      }
    
      - (void)viewWillDisappear:(BOOL)animated {
        for (UIView *subView in self.view.subviews) {
          if ([subView isKindOfClass:[UILabel class]]) {
            UILabel *label = (UILabel *)subView;
            label.text = @"";
            label = nil;
          }
        }
        [super viewWillDisappear:animated];
      }
    
    
      - (void)dismiss {
        [self dismissViewControllerAnimated:YES completion:nil];
      }
    
    
      @end
    

    我希望这可以帮到你!

答案 3 :(得分:0)

您遇到的行为非常奇怪。这是一种解决方法:

我建议您停止重复使用BugController。这是一个干净的解决方案,您不必显式缓存ViewControllers。 (操作系统可以自行处理效率,如果您遵守MVC标准,您应该可以根据基础模型数据随时重建视图控制器)

要执行此操作,请删除BugController iVar,并将bugTapped更改为:

- (void)bugTapped
{
    BugController *bugVC = [[BugController alloc] init];
    [self.navigationController pushViewController:bugVC animated:YES];
}