我正在构建一个使用地理围栏的应用程序。我的 didEnterRegion 和 didExitRegion 方法按预期调用,似乎顺序正确,但无法相应地更新 UI。
什么有效:
- 用户输入区域
- didEnterRegion被调用
- UI 在该方法中正确更新
什么不起作用:
- 用户输入区域
- 用户从一个区域直接转到另一个区域
- didExitRegion 被稱為
- 用户界面更新
- didEnterRegion被称为
- NSLogs 指示所有内容都以正确的顺序执行
- UI 未更新。在 didExitRegion 中完成的 UI 更新仍然存在。
我的方法:
用于更新标签的自定义函数(从didEnterRegion和didExitRegion调用):
-(void)updateCurrentLocationLabelAndImage:(NSString *)locationText subLocationText:(NSString *)subLocationText;
{
// Clear existing animations before we begin
[self.locationLabel.layer removeAllAnimations];
[self.subLocationLabel.layer removeAllAnimations];
[self.ovalImageView.layer removeAllAnimations];
if (![locationText isEqual:@""])
{
// Only animate if the text changes
if (![self.locationLabel.text isEqualToString:locationText])
{
// Update the ovalImageView
CGSize maxLabelSize = CGSizeMake(([UIScreen mainScreen].bounds.size.width - (([UIScreen mainScreen].bounds.size.width * 0.0267) * 2)), 64); // maximum label size
float expectedLabelWidth = [locationText boundingRectWithSize:maxLabelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{ NSFontAttributeName:self.locationLabel.font } context:nil].size.width; // get expected width
CGFloat xValueForImage = ((([UIScreen mainScreen].bounds.size.width - expectedLabelWidth) / 2) - 25); // Calcuate the x-coordinate for the ovalImageView
if (xValueForImage < 15)
{
xValueForImage = 15; // we don't want it to display off-screen
}
self.ovalImageViewLeadingConstraint.constant = xValueForImage;
[self.view setNeedsUpdateConstraints];
[self changeLabelText:self.subLocationLabel string:subLocationText];
// Update the subLocationLabel
[UIView animateWithDuration:.15 animations:^{
// Animate
self.locationLabel.alpha = 0;
self.ovalImageView.alpha = 1;
[self.view layoutIfNeeded]; // update the UI
}completion:^(BOOL finished) {
// Set the text
self.locationLabel.text = locationText;
self.locationLabel.adjustsFontSizeToFitWidth = YES;
[UIView animateWithDuration:.15 animations:^{
// Animate
self.locationLabel.alpha = 1;
}completion:^(BOOL finished) {
// Complete
}];
}];
}
} else if ([locationText isEqual:@""])
{
// Move it to the center
self.ovalImageViewLeadingConstraint.constant = (([UIScreen mainScreen].bounds.size.width / 2) - 9); // Default center calculation for this image
[self.view setNeedsUpdateConstraints];
[self changeLabelText:self.subLocationLabel string:subLocationText]; // Update the subLocationLabel
[UIView animateWithDuration:.15 animations:^{
self.locationLabel.alpha = 0;
self.ovalImageView.alpha = 1;
[self.view layoutIfNeeded];
}completion:^(BOOL finished) {
// Complete
self.locationLabel.text = @"";
}];
}
}
但是标签保持不变,即使它记录了正确的执行顺序并且一切看起来都很好。有什么想法吗?我真的被困住了..
谢谢!
详细解释一下,
让我们考虑用户退出区域 1 和直接进入区域 2 的场景。
第 1 步:
因此,触发事件出口,执行以下行,
NSLog(@"changing text from: %@, to: %@", label.text, string);
// Only animate if the text changes
if (![label.text isEqualToString:string])
在此 If 选中时,标签文本为"内部区域"(用于区域 1)。由于该方法是从 exit 方法调用的,因此参数 string
的值将为"外部区域"。这两个值不相同,因此控件进入此区域。
第 2 步:此时,您启动了持续时间为 0.15 的动画,但是在动画完成之前,标签的值不会更改,因为代码位于完成块中。
// Complete
label.text = string;
第 3 步:将触发"确实进入区域 2"事件。标签文本尚未更新,因此它会激发以下行
NSLog(@"changing text from: %@, to: %@", label.text, string);
但是,由于标签文本是"内部区域",字符串值也是"内部区域",因此控件移出 if 条件。
if (![label.text isEqualToString:string])
要验证:
在调用更改标签文本时传入自定义字符串值,使文本特定,即"区域 1 内"、"退出区域 1"、"区域 2 内"等,这样值将不同并得到更新。
在动画之前设置标签的值。
将值分配给原子字符串属性,并检查属性值。
例如:
@property (atomic, strong) NSString * currentLabelText;
-(void)changeLabelText:(UILabel *)label string:(NSString *)string
{
NSLog(@"changing text from: %@, to: %@", label.text, string);
// Only animate if the text changes
if (![self. currentLabelText isEqualToString:string])
{
self. currentLabelText = string; //Ultimately this would be our value
[UIView animateWithDuration:.15 animations:^{
// Animate
label.alpha = 0;
}completion:^(BOOL finished) {
// Complete
label.text = self. currentLabelText;
[UIView animateWithDuration:.15 animations:^{
// Animate
label.alpha = 1;
}completion:^(BOOL finished) {
// Complete
}];
}];
}
}
或者另一种方式,因为它符合您的要求。
试试这个...
static NSString *currentText;
currentText = locationText;
[UIView animateWithDuration:.15 animations: ^{
// Animate
self.locationLabel.alpha = 0;
self.ovalImageView.alpha = 1;
[self.view layoutIfNeeded]; // update the UI
} completion: ^(BOOL finished) {
// Set the text
if (![currentText isEqualToString:locationText]) {
return;
}
self.locationLabel.text = locationText;
self.locationLabel.adjustsFontSizeToFitWidth = YES;
[UIView animateWithDuration:.15 animations: ^{
// Animate
self.locationLabel.alpha = 1;
} completion: ^(BOOL finished) {
// Complete
}];
}];
我建议你将你的UI更新代码放在调度块中,以确保UI更新将在主线程上执行。
dispatch_async(dispatch_get_main_queue(), ^{
//... UI Update Code
});
我想主线的事情是你最大的问题。对我来说,代码在这一点上看起来有点奇怪:
- 您正在混合不同的数据类型(float,CGFloat,int)
参考CocoaTouch64BitGuide这可能是一个问题,但我认为它不能解决您的布局问题。更关键的是一般的幻数。
- 您的自动布局代码可能有问题
我相信没有必要通过操作 LeadingConstraint 来移动 ovalImageView。只需将内容模式设置为居中/左/右,自动布局就会重置。如果您确实需要更改约束,请在 [yourView updateConstraint] 方法中进行。如果你想要标签宽度要求它:[label intrisicContentsize],如果需要,请使用setPreferredMaxLayoutWidth。如果您的自动布局代码正确,则不会显示"屏幕外"的任何视图。
- 您的动画可能有点跳跃
您首先使用删除所有动画。基本上是正确的,但如果您期望频繁更新,我建议您在以前的动画运行时更改标签/图像内容。否则,您的图像将跳回并启动新动画。