【问题标题】:didEnterRegion and didExitRegion animation conflictingdidEnterRegion 和 didExitRegion 动画冲突
【发布时间】:2015-01-27 18:52:15
【问题描述】:

我正在构建一个使用 GeoFencing 的应用程序。我的 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 = @"";
    }];
}
}

但标签保持不变,即使它记录了正确的执行顺序并且一切看起来都很好。有任何想法吗?我真的被困住了..

谢谢!

【问题讨论】:

  • 日志“Entered work region ...”从何而来?
  • 您进入区域 2 的事件会在退出区域 1 后立即覆盖该值。尝试查看两个不同标签的值并检查..
  • @NaveenPrasadR 我现在添加的测试标签设置正确
  • @NaveenPrasadR 你对我能做些什么来解决这个问题有什么想法吗?
  • 它按预期工作。你想实现的功能是什么?

标签: ios objective-c location geofencing clregion


【解决方案1】:

详细解释一下,

让我们考虑一个用户退出区域 1 并直接进入区域 2 的场景。

第 1 步:

所以,事件退出被触发,以下行被执行,

    NSLog(@"changing text from: %@, to: %@", label.text, string);
    // Only animate if the text changes
    if (![label.text isEqualToString:string])

在此如果检查,标签文本是“区域内”(即区域 1)。由于该方法是从退出方法调用的,因此参数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 内”、“退出区域 1”、“区域 2 内”等,这样该值将是不同并且会得到更新。

  2. 在动画前立即设置标签的值。

  3. 将值分配给原子字符串属性并检查属性值。

例如:

@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
    }];
}];
}
}

或其他适合您要求的方式。

【讨论】:

  • 嗯,我不太明白如何在我的代码中实现。标签可能包含另一个字符串而不是“内部区域的东西”等。我需要以某种方式检测动画当前是否正在为给定标签运行,如果是,则覆盖它
【解决方案2】:

你可以试试这个……

            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
                }];
            }];

【讨论】:

    【解决方案3】:

    我建议您将 UI 更新代码放在调度块中,以确保 UI 更新将在主线程上执行。

    dispatch_async(dispatch_get_main_queue(), ^{
        //... UI Update Code
    });
    

    我猜主线程的事情是你最大的问题。对我来说,此时代码看起来有点奇怪:

    • 您正在混合不同的数据类型(float、CGFloat、int)

    参考CocoaTouch64BitGuide 这可能是个问题,但我认为它不能解决您的布局问题。更关键的是一般的神奇数字。

    • 您的自动布局代码可能有问题

    我相信没有必要通过操纵LeadingConstraint 来移动ovalImageView。只需将 contentMode 设置为 center/left/right,自动布局就会重置。如果您确实需要更改约束,请在 [yourView updateConstraints] 方法中进行。如果您想要标签宽度,请询问:[label intrinsicContentsize] 并在需要时使用 setPreferredMaxLayoutWidth。如果您的自动布局代码正确,则不会出现“屏幕外”视图。

    • 您的动画可能有点跳动

    您首先使用 removeAllAnimations。基本上是对的,但如果您期望频繁更新,我建议您在之前的动画运行时更改标签/图像内容。否则,您的图像会跳回并开始新的动画。

    【讨论】:

    • 我会试试这个,但为什么最好确保它在主线程上执行?
    • 我相信你误解了这个问题。当我进入一个区域,走出一个区域,然后进入一个区域时,动画 100% 完美无瑕 - 但是如果我直接从一个区域跳到另一个区域而没有先去一个空白区域,那么它会调用执行两次动画的方法,因此 UILabel 中显示的文本是错误的。但所有控件始终保持在正确的位置
    猜你喜欢
    • 2013-12-13
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 2013-04-27
    • 1970-01-01
    • 2015-12-12
    • 1970-01-01
    相关资源
    最近更新 更多