iOS 기기 흔들기 감지 및 시각적 효과 구현

1. iOS 흔들기 감지 메커니즘

iOS 애플리케이션에서 사용자의 기기 흔들림 동작을 감지하는 기능은 `UIResponder` 클래스를 통해 구현할 수 있습니다. `UIResponder`는 사용자 인터페이스 이벤트를 처리하는 데 사용되는 기본 클래스이며, 모션(흔들림) 이벤트를 위한 특정 메서드를 제공합니다. 이러한 메서드를 활용하여 앱에서 흔들림 감지 기능을 활성화할 수 있습니다.

주요 모션 이벤트 관련 메서드는 다음과 같습니다:

  • motionBegan:withEvent:: 기기 흔들림 동작이 시작될 때 호출됩니다.
  • motionEnded:withEvent:: 기기 흔들림 동작이 완료되었을 때 호출됩니다. 일반적으로 이 메서드 내에서 흔들림 감지 후 실행할 핵심 로직을 구현합니다.
  • motionCancelled:withEvent:: 기기 흔들림 동작이 어떤 이유로든 취소되었을 때 호출됩니다.

특정 뷰 컨트롤러에서 이러한 흔들림 이벤트를 받으려면, 해당 뷰 컨트롤러를 퍼스트 리스폰더(First Responder)로 설정하고, `UIApplication` 객체가 흔들기-편집(Shake to Edit) 기능을 지원하도록 명시적으로 활성화해야 합니다. 이 설정은 일반적으로 뷰 컨트롤러의 `viewDidLoad` 메서드에서 수행됩니다.


#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h> // 사운드 효과를 위해 필요

@interface ShakeDetectionViewController : UIViewController
// 애니메이션에 사용될 이미지 뷰 예시
@property (nonatomic, strong) UIImageView *upperVisualElement;
@property (nonatomic, strong) UIImageView *lowerVisualElement;
@end

@implementation ShakeDetectionViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 애플리케이션이 흔들기-편집 기능을 지원하도록 설정합니다.
    // 이는 흔들림 감지에 필수적인 단계입니다.
    [[UIApplication sharedApplication] setApplicationSupportsShakeToEdit:YES];
    
    // 현재 뷰 컨트롤러를 퍼스트 리스폰더로 설정하여 이벤트를 수신할 수 있게 합니다.
    [self becomeFirstResponder];

    // 예시 시각적 요소 초기화 (실제 앱에서는 적절한 이미지 리소스를 사용)
    self.upperVisualElement = [[UIImageView alloc] initWithFrame:CGRectMake(80, 80, 160, 100)];
    self.upperVisualElement.backgroundColor = [UIColor grayColor]; // Placeholder
    [self.view addSubview:self.upperVisualElement];

    self.lowerVisualElement = [[UIImageView alloc] initWithFrame:CGRectMake(80, 300, 160, 100)];
    self.lowerVisualElement.backgroundColor = [UIColor darkGrayColor]; // Placeholder
    [self.view addSubview:self.lowerVisualElement];
}

// 뷰 컨트롤러가 화면에서 사라질 때 퍼스트 리스폰더 상태를 해제합니다.
// 메모리 누수를 방지하고 적절한 이벤트 체인을 유지하기 위함입니다.
- (void)viewWillDisappear:(BOOL)animated {
    [self resignFirstResponder];
    [super viewWillDisappear:animated];
}

// 흔들림 동작이 시작될 때 호출되는 메서드
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    if (motion == UIEventSubtypeMotionShake) {
        // 흔들림 시작 시 필요한 초기화 또는 시각적 피드백 로직을 여기에 구현할 수 있습니다.
        NSLog(@"기기 흔들림 감지 시작.");
    }
}

// 흔들림 동작이 끝났을 때 호출되는 메서드
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    if (motion == UIEventSubtypeMotionShake) {
        // 기기 흔들림이 성공적으로 감지되었을 때 실행할 주요 로직입니다.
        NSLog(@"기기 흔들림 감지 완료!");
        // 여기에 원하는 액션(예: 애니메이션 시작, 데이터 새로고침 등)을 트리거합니다.
        [self activateShakeVisualEffects];
    }
}

// 흔들림 동작이 어떤 이유로든 취소되었을 때 호출되는 메서드
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    if (motion == UIEventSubtypeMotionShake) {
        // 흔들림 동작이 취소되었을 때 필요한 정리 작업을 수행할 수 있습니다.
        NSLog(@"기기 흔들림 동작 취소됨.");
    }
}

// 흔들림 후 시각적 효과를 담당하는 사용자 정의 메서드 (다음 섹션에서 구현)
- (void)activateShakeVisualEffects {
    // 구현 내용 없음 - 다음 섹션에서 추가됩니다.
}

@end

2. 시각적 흔들림 효과 애니메이션 구현

기기 흔들림이 감지된 후, 사용자에게 즉각적인 시각적 피드백을 제공하는 것은 앱의 사용자 경험을 향상시키는 데 매우 중요합니다. `Core Animation` 프레임워크의 `CABasicAnimation`을 사용하여 동적인 흔들림 효과를 구현할 수 있습니다. 예를 들어, 화면에 있는 두 개의 시각적 요소를 서로 멀어졌다가 다시 가까워지는 방식으로 애니메이션 할 수 있습니다.

다음 예시 코드는 `motionEnded:` 메서드에서 호출되는 `activateShakeVisualEffects` 메서드에 애니메이션 로직을 추가하는 방법을 보여줍니다. 이 메서드는 이미지 뷰를 위아래로 움직여 흔들리는 듯한 효과를 생성하고, 시스템 사운드를 재생하여 청각적 피드백도 제공합니다.


// ShakeDetectionViewController.m 에 추가되는 내용
@implementation ShakeDetectionViewController (AnimationEffects)

// 흔들림 감지 후 시각적 및 청각적 효과를 주는 메서드
- (void)activateShakeVisualEffects {
    // 1. 사운드 효과 재생
    SystemSoundID shakeFeedbackSoundID;
    // 사용자 정의 사운드 파일 경로를 지정합니다.
    NSString *soundPath = [[NSBundle mainBundle] pathForResource:@"shake_feedback" ofType:@"caf"]; 
    if (soundPath) {
        NSURL *fileURL = [NSURL fileURLWithPath:soundPath];
        AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileURL, &shakeFeedbackSoundID);
        AudioServicesPlaySystemSound(shakeFeedbackSoundID);
        // 사운드가 재생된 후 SystemSoundID를 해제합니다.
        // AudioServicesDisposeSystemSoundID(shakeFeedbackSoundID); // 필요하다면
    } else {
        // 사용자 정의 사운드 파일이 없을 경우 기본 진동 효과를 사용합니다.
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); 
    }

    // 2. 상단 시각적 요소 애니메이션: 위로 이동 후 제자리로 복귀
    CABasicAnimation *topElementAnimation = [CABasicAnimation animationWithKeyPath:@"position.y"];
    topElementAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    topElementAnimation.fromValue = @(self.upperVisualElement.center.y); // 현재 Y 위치
    topElementAnimation.toValue = @(self.upperVisualElement.center.y - 70.0); // 위로 70포인트 이동
    topElementAnimation.duration = 0.3; // 애니메이션 지속 시간
    topElementAnimation.repeatCount = 1; // 한 번만 실행
    topElementAnimation.autoreverses = YES; // 애니메이션 역재생 (원래 위치로 돌아옴)

    // 3. 하단 시각적 요소 애니메이션: 아래로 이동 후 제자리로 복귀
    CABasicAnimation *bottomElementAnimation = [CABasicAnimation animationWithKeyPath:@"position.y"];
    bottomElementAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    bottomElementAnimation.fromValue = @(self.lowerVisualElement.center.y); // 현재 Y 위치
    bottomElementAnimation.toValue = @(self.lowerVisualElement.center.y + 70.0); // 아래로 70포인트 이동
    bottomElementAnimation.duration = 0.3; // 애니메이션 지속 시간
    bottomElementAnimation.repeatCount = 1; // 한 번만 실행
    bottomElementAnimation.autoreverses = YES; // 애니메이션 역재생 (원래 위치로 돌아옴)

    // 애니메이션을 해당 레이어에 추가하여 실행합니다.
    [self.upperVisualElement.layer addAnimation:topElementAnimation forKey:@"animateUpperElementShake"];
    [self.lowerVisualElement.layer addAnimation:bottomElementAnimation forKey:@"animateLowerElementShake"];
}

@end

태그: iOS UIResponder 흔들기 감지 Core Animation CABasicAnimation

7월 23일 10:24에 게시됨