更新 UILabel Text 会重置情节提要?

Posted

技术标签:

【中文标题】更新 UILabel Text 会重置情节提要?【英文标题】:Updating UILabel Text resets storyboard? 【发布时间】:2015-05-29 07:08:00 【问题描述】:

我遇到了一个奇怪的场景,我自己无法弄清楚。

我开始了一个小测试场景,其中包含一个几乎空的 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 次更改一次文本以更好地显示这里的问题。

如果我运行该代码,点会按预期向右移动,但是当我更新标签文本时,点视图会重置并跳回原来的位置。所以更新我的标签文本会重置我在情节提要上的其他视图,这完全让我感到困惑。

有人可以重现甚至解释吗?

谢谢大家,提前:)

亚历克斯

【问题讨论】:

您是否在情节提要中设置了一些 AutoLayout 约束?顺便说一句,喜欢这个(int)10.0 我没有设置任何特定的 AutoLayout 约束,所以视图有默认设置。 也许你有一些自动布局约束,你没有设置它的框架,对吧? 很有可能。没错,我没有明确设置它的框架。我只是将它放在情节提要上,其余部分默认保留。我只是不知道视图的默认 AutoLayout 约束是否会导致这种行为。有人知道吗? 你能把你的故事板作为截图贴在这里吗? 【参考方案1】:

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

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

为了解决,我建议正确指定 AutoLayout 约束并更新它们而不是直接定位。

【讨论】:

【参考方案2】:

差不多就是这样,AutoLayout 约束总是将视图推回原来的位置,我猜这有点道理,这就是 AutoLayout 应该做的。

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

我制作了两个自定义 AutoLayout 约束,告诉它始终保持视图距离父视图左侧 120 像素和距离父视图顶部 100 像素。我还为每个 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];

它起作用了,改变约束而不是实际视图现在将视图移动到屏幕上。如果这是最佳实践,我不知道。如果我不是为了练习目的而尝试它,遵循一个古老的教程,我一开始就不会想出这个。

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

亚历克斯

【讨论】:

【参考方案3】:

这似乎是一个老问题,但它也困扰着我。 我很困惑的是,在视觉层次结构底部更改 UILabel 中的文本会使整个故事板重新布局。

不仅如此,我还拥有一些 android 开发背景,我从未在 Android 中使用(类似的)TextView 目睹过这种行为。您可以按照自己的意愿更改其中的文本——从不更新更高级别的 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)

【讨论】:

以上是关于更新 UILabel Text 会重置情节提要?的主要内容,如果未能解决你的问题,请参考以下文章

从情节提要加载 UILabel,无法更改 cellForRowAtIndexPath 中的框架

在情节提要中定位 UILabel

如何根据自适应布局和情节提要使 uitableviewcell 中的 uilabel 相对于设备进行包装

如何在情节提要中为uilabel设置大于300的字体大小?

如何在情节提要中的 UILabel 的右边缘添加前导约束?

如何仅使用情节提要使 UILabel 的 UIView 超级视图适合 UILabel 的固有高度?