1

GeoFencing を使用するアプリを構築しています。私の didEnterRegion および didExitRegion メソッドは、想定どおりに呼び出され、一見正しい順序で呼び出されますが、それに応じて UI を更新できません。

機能するもの:

  • ユーザーが地域に入る
  • didEnterRegion が呼び出される
  • UI はそのメソッド内で正しく更新されます

機能しないもの:

  • ユーザーが地域に入る
  • ユーザーはある地域から別の地域に直行します
  • didExitRegion が呼び出されます
  • UI の更新
  • 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 = @"";
    }];
}
}

ただし、正しい実行順序がログに記録され、すべて問題ないように見えても、ラベルは同じままです。何か案は?私は本当に立ち往生しています..

ありがとう!

4

3 に答える 3

0

UI 更新コードをディスパッチ ブロックに入れて、UI 更新がメイン スレッドで確実に実行されるようにすることをお勧めします。

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

メインスレッドがあなたの最大の問題だと思います。私には、この時点でコードが少し奇妙に見えます。

  • 異なるデータ型 (float、CGFloat、int) を混在させている

CocoaTouch64BitGuideを参照してください。これは問題になる可能性がありますが、レイアウトの問題は解決しないと思います。より重要なのは、一般的なマジック ナンバーです。

  • 自動レイアウト コードが問題になる可能性があります

LeadingConstraint を操作して ovalImageView を移動する必要はないと思います。contentModeを center/left/right に設定するだけで、autolayout がリセットを行います。本当に制約を変更する必要がある場合は、[yourView updateConstraints]メソッドで変更してください。ラベルの幅が必要な場合は、 [label embeddedContentsize]を指定し、必要に応じてsetPreferredMaxLayoutWidthを使用します。自動レイアウト コードが正しい場合、ビューは「画面外」に表示されません。

  • あなたのアニメーションは少しびくびくするかもしれません

最初に removeAllAnimations を使用します。基本的には正しいですが、頻繁な更新が予想される場合は、以前のアニメーションの実行中にラベル/画像のコンテンツを変更することをお勧めします. そうしないと、画像が元に戻り、新しいアニメーションが開始されます。

于 2015-02-19T19:33:43.380 に答える
0

これを試すことができます…</p>

            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
                }];
            }];
于 2015-02-19T15:53:11.597 に答える
0

詳しく説明すると、

ユーザーが region1 を出て、そのまま region2 に入るシナリオを考えてみましょう。

ステップ1:

したがって、イベント出口が起動され、次の行が実行されます。

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

この If チェックでは、ラベル テキストは「inside region」(領域 1 用) です。このメソッドは exit メソッドから呼び出されるため、パラメーターstringの値は「領域外」になります。両方の値が同じではないため、コントロールはこの領域に入ります。

ステップ 2: この時点で、持続時間 0.15 のアニメーションを開始しましたが、コードが完了ブロックにあるため、アニメーションが完了するまでラベルの値は変更されません。

   // Complete
    label.text = string;

ステップ 3: did enter region 2 イベントが発生します。ラベルのテキストはまだ最新ではないため、下の行を励起します

NSLog(@"changing text from: %@, to: %@", label.text, string);

ただし、ラベル テキストは「領域内」であり、文字列値も「領域内」であるため、コントロールは if 条件の外に移動します。

if (![label.text isEqualToString:string])

検証します:

  1. 変更ラベル テキストを呼び出すときに、カスタマイズされた文字列値を渡します。これにより、テキストが特定の Viz になります。「領域 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
    }];
}];
}
}

または、要件に合った別の方法。

于 2015-01-29T09:59:47.060 に答える