更新 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 中的框架