2014-12-22 2 views
2

나는 사용자에게 약간의 힌트를주기 위해 표시하고 숨기기 위해 View을 가지고있다. 새로운 뷰를 표시 할 때GCD를 사용하여 애니메이션 시퀀스를 제어하는 ​​방법

-(void)show{ 
    [UIView animateWithDuration:3.0f 
       animations:^{ 
        //do something to show self to give hint; 
        self.frame = CGRectMake(0,0,0,0); 
       } completion:nil]; 
} 

-(void)hide{ 
    [UIView animateWithDuration:3.0f 
       animations:^{ 
        //do something to hide self to give hint; 
        self.frame = CGRectMake(centerX,centerY,100,100); 
       } completion:nil]; 
} 

, 내가 hide method 다음 show method를 호출해야합니다 :

쇼 및 숨기기 방법은 다음과 같이 몇 가지를 본다. 그러나 지속 시간 지연 3.0f는 약간의 오류를 유발합니다. 나는이 같은 방법을 사용했다 : 바로 hide methodshow method를 호출했다

dispatch_async(dispatch_get_main_queue(), ^{ 
    [view hide]; 
}); 

dispatch_async(dispatch_get_main_queue(), ^{ 
    [view show]; 
}); 

. 애니메이션은 대기열에 제출되는 시퀀스로 실행할 수 없습니다. 내가 원하는 것은 hide method 완료된 후 정확히 실행 된 show method입니다. 어떻게이 두 가지 방법의 순서를 제어 할 수 있습니까?

완료 처리기를 사용할 수없는 이유는이 두 메서드가 호출되는 위치를 보장 할 수 없거나 다른 show method 또는 hide method을 호출 할 때보기가 표시되는지 여부 때문입니다.

명확하지 않은 의견이 있으면 알려주십시오. 나는 내 질문을 재 편집 할 것이다.


PS : 그냥 플래시 아니다

. 다음 show 메서드가 호출되면 마지막 뷰가 표시되거나 숨겨지고 마지막 뷰가 표시되는 시간을 보장 할 수 없습니다. 즉, 뷰가 표시되고 hide 메서드가 호출되어 이미 완료된 경우 show 메서드가 호출되면 결과가 올바르다. 뷰가 표시되고있는 경우 main_queue이 연속이지만 애니메이션 블록이 동기식으로 실행되므로 결과가 잘못 표시되어 다른 힌트보기를 제시해야합니다. 먼저 hide을 호출 한 다음 show을 호출합니다. 내가 찾고있는 GCD에서 마지막으로 대기열에 블록을 완료 후 블록을 실행하는 데 도움이 될 수있는 일종의 잠금을 찾고 있습니다 showhide 방법을 변경하는 것보다 완료됩니다. 많은 다른 종류의 매개 변수가있는 showhide 메서드에 대한 다른 많은 호출이 있기 때문에 코드에서 많은 부분을 수정해야합니다.

+0

[이 질문]에 대한 해답을 숨기 : //stackoverflow.com/questions/26090071/show-hide-uiview-twice-every-5-seconds-using-nstimer)는 키 프레임 애니메이션을 제안합니다. 당신을 위해 일할 수도 있습니다. – Droppy

+0

show 또는 hide 메서드에 플래그를 전달하여 다음 호출 할 것인지를 나타냅니다. 그런 다음 완성 방법으로 작업하십시오. – jrturton

+0

@ jrturton의 해결책이 효과적입니다. 또한 NSOperationQueue를 생성하고 show/hide 명령을이 큐에 추가 할 수 있습니다. 더 이상 실행되지 않으면 작업에 대해'cancel'을 호출 할 수 있습니다. –

답변

1

대기열에 추가 된 순서대로 한 번에 하나의 작업을 실행하려면 직렬 대기열을 사용하십시오.

그래서 직렬 대기열을 사용하여 추가 된 순서로 한 번에 작업을 표시하고 숨길 수 있습니다. 그래, 메인 큐는 괜찮아.

그러나 UIView -animateWithDuration : animations : 메서드는 일종의 비동기 호출이며 메서드는 즉시 반환됩니다. 따라서 완성 블록이 호출 될 때까지 기다려야합니다.

일부 작업이 완료 될 때까지 기다리려면 발송 그룹을 사용하십시오. 하지만 메인 대기열에서 기다리는 것을 피해야합니다. 메인 큐를 차단합니다. 잘못된 앱입니다.

따라서 직렬 대기열 및 발송 그룹을 다음과 같이 사용해야 할 수 있습니다.

특성 및 (HTTP를

@property (nonatomic, strong) dispatch_queue_t serialQueue; 
@property (nonatomic, strong) dispatch_group_t group; 

-(void)initQueue { 
    // create a serial queue 
    self.serialQueue = dispatch_queue_create("com.example.serialQueue", 0); 
    // create a dispatch group 
    self.group = dispatch_group_create(); 
} 

직렬 큐 디스패치 그룹

-(void)animateSyncWithDuration:(NSTimeInterval)duration animations:(block_t)animations { 
    dispatch_async(self.serialQueue, ^{ 
     /* 
     * This block is invoked on the serial queue 
     * This block would never be executed concurrently 
     */ 

     /* 
     * Enter the dispatch group 
     */ 
     dispatch_group_enter(self.group); 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      /* 
      * This block is invoked on the main queue 
      * It is safe to use UIKit 
      */ 
      [UIView animateWithDuration:duration animations:animations completion:^{ 
       /* 
       * This completion block is invoked on the main queue 
       * Now leave the dispatch group 
       */ 
       dispatch_group_leave(self.group); 
      }]; 
     }); 

     /* 
     * Wait until leaving the dispatch group from the UIView animation completion block 
     * It means it blocks the serial queue 
     */ 
     dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER); 
    }); 
} 

표시를 사용하는 방법을 초기화

-(void)show{ 
    [self animateSyncWithDuration:3.0f animations:^{ 
     //do something to show self to give hint; 
     self.frame = CGRectMake(0,0,0,0); 
    }]; 
} 

-(void)hide{ 
    [self animateSyncWithDuration:3.0f animations:^{ 
     //do something to hide self to give hint; 
     self.frame = CGRectMake(centerX,centerY,100,100); 
    }]; 
} 
0

다음과 같은 방법으로 delayfunction calling에 넣습니다. 무엇을 당신이 원하는 것은 하나 개의 동작은 (다음 그 자체를 보여 숨기기) 인 경우

- (void) doAnimation : (double) delay { 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     NSLog(@"Call your First function here"); 
    }); 

    double delayInSeconds = delay; 
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 

     NSLog(@"Call your second function here"); 

    }); 
} 
+0

지연 초가 변경 될 수 있습니다. 지연 초를 사용하지 않는 제안이 있습니까? – llch

+0

'delay seconds '를 인수로 사용하는 create 함수. 또는 '애니메이션'에서 '완료 블록'을 사용할 수 있습니다. 'updated answer'을 보십시요. –

1

, 당신은이 작업을 수행하는 대신 두 개의 애니메이션에 가입 한 애니메이션을 만들어야합니다.

두 가지 가능한 솔루션이 있습니다.

1 애니메이션 반복 및 자동 역방향을 사용 키 프레임 애니메이션을

-(void) flash { 
    CGRect bounds = self.bounds; 

    [UIView animateWithDuration:1.0f 
         delay:0.0f 
         options:UIViewAnimationOptionAutoreverse | 
           UIViewAnimationOptionRepeat 
        animations:^{ 
        [UIView setAnimationRepeatCount:1]; 
        self.bounds = CGRectZero; 
        } 
        completion:^(BOOL finished) { 
        self.bounds = bounds; 
        }]; 
} 

(2)를 사용하여 (완료 콜백 원래 크기로 다시 재설정해야)

-(void) flash2 { 
    [UIView animateKeyframesWithDuration:1.0f 
     delay:0.0f 
     options:UIViewKeyframeAnimationOptionCalculationModeLinear 
    animations:^{ 
     CGRect bounds = self.bounds; 

     [UIView addKeyframeWithRelativeStartTime:0.0 
           relativeDuration:0.5 
            animations:^{ self.bounds = CGRectZero; }]; 

     [UIView addKeyframeWithRelativeStartTime:0.5 
           relativeDuration:0.5 
            animations:^{ self.bounds = bounds; }]; 
    } 
    completion:nil]; 
} 
0

나는 유스 케이스를 완전히 이해하지는 못했지만 여기에서해야한다고 생각하는 것은 숨기기 작업이 실제로 발생해야하는지 여부를 확인하는 것입니다. 또한, 숨기기 코드 3 초 애니메이션 기간을 가지고 있기 때문에, 당신은 완료 블록 당신의 방법을 만들어야합니다, 그래서 의사에 아래 작성한 것을 당신은 유사한 작업을 수행 할 수 있습니다 다음

- (void)hideIfNeededWithCompletionBlock:((^)())completionBlock { 
    if (self.isShowing) { 
     [self hideWithCompletionBlock:^(BOOL didHide) { 
      if (completionBlock) { 
       completionBlock(); 
      } 
     }]; 
    } else { 
     if (completionBlock) { 
      //We didn't need to hide anything, so we're done 
      completionBlock(); 
     } 
    } 
} 

다음과 같이 호출 할 수 있습니다.

[self hideIfNeededWithCompletionBlock:^(){ 
    [self show]; 
}]; 

유연성이 필요한 경우 show 메소드와 비슷한 기능을 수행 할 수 있습니다.

또한 필요에 따라 표시/숨기기를 애니메이션으로 표시할지 여부를 BOOL로 지정하고 NO를 전달하는 경우 기간을 0.0으로 사용할 수 있습니다.

UIView 애니메이션 API를 사용하면 dispatch_async 블록에서 래핑을 시작할 수 있다고 생각합니다. API를 사용하여 모든 것을 처리 할 수 ​​있습니다.

+0

나는 그것을 안다. 심지어 GCD를 사용하지 않고, 그냥 직접 쇼와 함께 사용하면 결과가 false가됩니다. 단, 쇼 블록을 호출하거나 완료 블록 안에 숨겨야합니다. – llch

+0

어떤 종류의 잠금과 같은 더 나은 솔루션을 찾고 있는데, show 메서드가 완료되지 않았 으면 hide 메서드는 show 메서드가 완료 될 때까지 기다립니다. – llch

+0

따라서 숨기기 작업이 보류중인 경우 추적하려면 BOOL을 사용하고 표시 애니메이션이 발생하는 경우 추적하려면 BOOL을 수행하면됩니다. 쇼 애니메이션에 참여 중이면 Bending Bide BOOL을 YES로 설정합니다. 보류중인 숨기기가 표시되면 애니메이션 완료 블록에서 호출하여 수행합니다. – cotugs

관련 문제