更新UILabel文本会重置故事板吗?

时间:2015-05-29 07:08:01

标签: ios objective-c iphone xcode uilabel

我遇到了一个奇怪的场景,我自己无法理解。

我开始了一个小测试场景,几乎是空的iOS单视图应用程序和故事板。故事板包含一个标签和单个UIView,10x10,仅用于呈现问题。当然,他们已经分配和连接了适当的IBOutlets:

@property (nonatomic, weak) IBOutlet UILabel *label;
@property (nonatomic, weak) IBOutlet UIView *dot;

在(void)viewDidLoad方法中,我启动一个计时器并将其添加到运行循环中:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSTimer * timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(doSomething) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

在(void)doSomething方法中,我执行以下操作:

-(void)doSomething {
    // Lets move the dot to the right a bit further
    _dot.center = CGPointMake(_dot.center.x+1, _dot.center.y);

    // About every ten steps, update the label with the current
    // X position, to better show the problem
    CGFloat moduloResult = (float)((int)_dot.center.x % (int)10.0);
    if(moduloResult <= 0)
        _label.text = [NSString stringWithFormat:@"%f", _dot.center.x+1];
}

所以基本上,我每次将小10x10点视图的中心改为1,每10次更新标签以显示当前的X位置。就此而言,我更新标签文本并不重要,重要的是它会发生变化。我每10次只更改一次文本,以便更好地显示问题。

如果我运行该代码,则点会按预期向右移动,但是当我更新标签文本时,点视图会重置并跳回其原始位置。因此,更新我的标签文本会重置我在故事板上的其他视图,这完全让我困惑。

有人可以复制甚至解释它吗?

提前感谢所有人:)

亚历

3 个答案:

答案 0 :(得分:6)

我能够重现所描述的行为,这就是它发生的原因:

  1. 默认情况下,元素的位置由自动生成的AutoLayout约束
  2. 确定
  3. 更改dot的位置时,您只更新当前帧,而不是更新基础约束
  4. 更改UILabel的文字可能会更改UILabel内容的大小,因此需要重新计算其框架。这里根据约束重新计算整个布局,因此也重置了dot
  5. 的框架

    对于解析,我建议正确指定AutoLayout约束并更新它们而不是直接更新位置。

答案 1 :(得分:2)

就是这样,AutoLayout约束推动视图总是回到它上面。原来的地方,我觉得哪种意义,这就是AutoLayout应该做的事情。

所以,因为我希望我的litte 10x10点视图在屏幕上移动(为了练习目的,我改变了我的代码。我试着解释它,目前缺乏声誉使我无法发布适当的图像。

我做了两个自定义AutoLayout约束,告诉它保持视图总是从superview左边120px和superview顶部100px。我还为每个10的固定宽度和高度指定了约束。因为对于有效约束,您需要x和y以及高度和宽度的组合(至少据我所知)。

                  -
                  |
                  | Constraint *n* from top
                  |

                  |------|
  Constraint      | view |
  *n* from left   | _dot |
|---------------  |------|

然后我为两个约束创建了两个IBOutlets:

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *c1X;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *c1Y;

我将我的(void)doSomething方法更改为:

-(void)doSomething {

    // Lets move the dot to the right a bit
    // further by changing its Constraint
    _c1X.constant++;

    // About every ten steps, update the labe with the current
    // X position, to better show the problem
    CGFloat moduloResult = (float)((int)_dot.center.x % 10);
    if(moduloResult <= 0)
        _label.text = [NSString stringWithFormat:@"%f - %f - %f", _c1X.constant, _dot.center.x, _dot.center.y];
}

它有效,更改约束而不是实际视图现在可以在屏幕上移动视图。如果这是最佳做法,我不知道。如果我没有尝试过它来进行练习,那么在老化的教程之后,我就不会想到这一点。

希望这可能有一天会有所帮助。欢迎提出任何意见或改进:)

亚历

答案 2 :(得分:0)

这似乎是一个老问题,但也困扰着我。 令我感到困惑的是,在可视层次结构的底部更改UILabel中的文本会使整个情节提要板重新布局。

更重要的是,由于具有一定的Android开发背景,所以我从未见过(类似)TextView在Android中的这种行为。您可以按自己的意愿更改其中的文本-永远不会更新更高级别的UI。

但是@Jakub Vano的回答使我意识到了一件事:

Android中的TextView始终具有固定的宽度和高度,并且无法通过更新视图内部的文本来更改其边框。 相反,iOS的UILabel可以根据其中的文本保留自格式化的宽度和高度。 不幸的是,即使在情节提要中固定宽度和高度也不能解决问题:更新文本仍会触发重新布局所有内容的请求。

我在使用CATextLayer时发现了解决方案-它不影响布局,您可以在其中放置所需的任何文本。但是这样做的代价是,您必须以编程的方式来处理所有事情,并记住要处理真实像素而不是点,例如:

            let mScale = UIScreen.main.scale

            indicatorLeft = CATextLayer ()
            indicatorLeft.fontSize = FONT_SIZE * mScale
            indicatorLeft.string = "text in CA layer"
            indicatorLeft.foregroundColor = UIColor.white.cgColor
            indicatorLeft.shadowColor = UIColor.gray.cgColor
            indicatorLeft.isHidden = false
            indicatorLeft.contentsScale = mScale

            indicatorLeft.frame = CGRect(x: 0, y:  0,
                                 width: VIEW_WIDTH * mScale, height: VIEW_HEIGHT * mScale )

            leftView.layer.addSublayer(indicatorLeft)