누군가가 iPhone을 흔들면 반응하고 싶습니다. 나는 그들이 어떻게 그것을 흔들리는 지에 대해 신경 쓰지 않고 단지 순간적으로 격렬하게 흔들렸다. 누구든지 이것을 감지하는 방법을 알고 있습니까?
답변
3.0에서는 이제 더 쉬운 방법이 있습니다. 새로운 모션 이벤트에 연결하십시오.
주요 요령은 흔들림 이벤트 메시지를 수신하기 위해 firstResponder로 원하는 일부 UIView (UIViewController가 아님)가 있어야한다는 것입니다. 모든 UIView에서 흔들림 이벤트를 얻을 수있는 코드는 다음과 같습니다.
@implementation ShakingView
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if ( event.subtype == UIEventSubtypeMotionShake )
{
// Put in code here to handle shake
}
if ( [super respondsToSelector:@selector(motionEnded:withEvent:)] )
[super motionEnded:motion withEvent:event];
}
- (BOOL)canBecomeFirstResponder
{ return YES; }
@end
UIView (시스템 뷰조차 포함)를 이러한 메소드만으로 뷰를 서브 클래 싱 한 다음 IB에서 기본 유형 대신이 새로운 유형을 선택하거나 또는 전망).
뷰 컨트롤러에서이 뷰를 첫 번째 응답자가되도록 설정하려고합니다.
- (void) viewWillAppear:(BOOL)animated
{
[shakeView becomeFirstResponder];
[super viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[shakeView resignFirstResponder];
[super viewWillDisappear:animated];
}
검색 창이나 텍스트 입력 필드와 같이 사용자 작업에서 첫 번째 응답자가되는 다른보기가있는 경우 다른보기가 사임 할 때 흔들리는보기 첫 번째 응답자 상태도 복원해야합니다.
이 메소드는 applicationSupportsShakeToEdit를 NO로 설정 한 경우에도 작동합니다.
답변
내 Diceshaker 응용 프로그램에서 :
// Ensures the shake is strong enough on at least two axes before declaring it a shake.
// "Strong enough" means "greater than a client-supplied threshold" in G's.
static BOOL L0AccelerationIsShaking(UIAcceleration* last, UIAcceleration* current, double threshold) {
double
deltaX = fabs(last.x - current.x),
deltaY = fabs(last.y - current.y),
deltaZ = fabs(last.z - current.z);
return
(deltaX > threshold && deltaY > threshold) ||
(deltaX > threshold && deltaZ > threshold) ||
(deltaY > threshold && deltaZ > threshold);
}
@interface L0AppDelegate : NSObject <UIApplicationDelegate> {
BOOL histeresisExcited;
UIAcceleration* lastAcceleration;
}
@property(retain) UIAcceleration* lastAcceleration;
@end
@implementation L0AppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[UIAccelerometer sharedAccelerometer].delegate = self;
}
- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
if (self.lastAcceleration) {
if (!histeresisExcited && L0AccelerationIsShaking(self.lastAcceleration, acceleration, 0.7)) {
histeresisExcited = YES;
/* SHAKE DETECTED. DO HERE WHAT YOU WANT. */
} else if (histeresisExcited && !L0AccelerationIsShaking(self.lastAcceleration, acceleration, 0.2)) {
histeresisExcited = NO;
}
}
self.lastAcceleration = acceleration;
}
// and proper @synthesize and -dealloc boilerplate code
@end
히스테리시스는 사용자가 흔들림을 멈출 때까지 흔들림 이벤트가 여러 번 트리거되는 것을 방지합니다.
답변
마지막으로이 Undo / Redo Manager Tutorial의 코드 예제를 사용하여 작동하게했습니다 .
이것은 당신이해야 할 일입니다.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
application.applicationSupportsShakeToEdit = YES;
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
-(BOOL)canBecomeFirstResponder {
return YES;
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[self resignFirstResponder];
[super viewWillDisappear:animated];
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake)
{
// your code
}
}
답변
첫째, Kendall의 7 월 10 일 답변은 현장에 있습니다.
이제 … 나는 비슷한 일을하고 싶었습니다 (iPhone OS 3.0 이상). 제 경우에만 앱 전체에서 원했기 때문에 흔들림이 발생했을 때 앱의 다양한 부분을 경고 할 수있었습니다 . 여기 내가 한 일이 있습니다.
먼저 UIWindow를 서브 클래 싱했습니다 . 쉬워요. 다음과 같은 인터페이스를 사용하여 새 클래스 파일을 만듭니다 MotionWindow : UIWindow
(자유롭게 선택하십시오). 다음과 같은 방법을 추가하십시오.
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) {
[[NSNotificationCenter defaultCenter] postNotificationName:@"DeviceShaken" object:self];
}
}
@"DeviceShaken"
선택한 알림 이름으로 변경하십시오 . 파일을 저장하십시오.
이제 MainWindow.xib (스톡 Xcode 템플릿)를 사용하는 경우 거기에 들어가서 Window 객체의 클래스를 UIWindow 에서 MotionWindow 또는 원하는 이름으로 변경하십시오. xib를 저장하십시오. 프로그래밍 방식으로 UIWindow 를 설정하는 경우 대신 새 Window 클래스를 사용하십시오.
이제 앱에서 특수한 UIWindow 클래스를 사용하고 있습니다. 흔들림에 대해 듣고 싶은 곳이라면 어디든지 알림을 신청하십시오! 이처럼 :
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(deviceShaken) name:@"DeviceShaken" object:nil];
관찰자로 자신을 제거하려면 :
[[NSNotificationCenter defaultCenter] removeObserver:self];
viewWillAppear : 및 viewWillDisappear : View Controller가 관련된 곳에 넣었습니다 . 흔들림 이벤트에 대한 응답이 “이미 진행 중”인지 아닌지 확인하십시오. 그렇지 않으면 장치가 연속해서 두 번 흔들리면 교통 체증이 발생할 수 있습니다. 이렇게하면 원래 알림에 실제로 응답 할 때까지 다른 알림을 무시할 수 있습니다.
또한 : 당신은 motionBegan 대 motionEnded 큐를 선택할 수 있습니다 . 그것은 당신에게 달려 있습니다. 필자의 경우 장치가 정지 한 후에 ( 효과 가 흔들 리기 시작할 때) 효과가 항상 발생해야 하므로 motionEnded 사용 합니다. 둘 다 시도하고 어느 것이 더 의미가 있는지 확인하십시오 … 또는 둘 다 감지 / 알림하십시오!
여기에 한 가지 더 궁금한 점이 있습니다.이 코드에서 첫 번째 응답자 관리의 징후가 없음을 주목하십시오. 나는 지금까지 테이블 뷰 컨트롤러로 이것을 시도했지만 모든 것이 아주 잘 작동하는 것 같습니다! 그래도 다른 시나리오를 보증 할 수는 없습니다.
켄달 등 al- 왜 이것이 UIWindow 서브 클래스에 대해 그렇게 될 수 있는지 이야기 할 수 있습니까? 창문이 먹이 사슬의 상단에 있기 때문입니까?
답변
나는 “흔들기 (shaking)”구현을 찾기 위해이 포스트를 발견했다. millenomi의 대답은 나를 위해 잘 작동했지만 트리거하기 위해 조금 더 “떨리는 행동”이 필요한 것을 찾고있었습니다. 부울 값을 int shakeCount로 바꿨습니다. 또한 Objective-C에서 L0AccelerationIsShaking () 메서드를 다시 구현했습니다. shakeCount에 추가 된 금액을 조정하여 필요한 흔들림 량을 조정할 수 있습니다. 아직 최적의 값을 찾았는지 확실하지 않지만 지금까지는 잘 작동하는 것 같습니다. 이것이 누군가를 돕기를 바랍니다.
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
if (self.lastAcceleration) {
if ([self AccelerationIsShakingLast:self.lastAcceleration current:acceleration threshold:0.7] && shakeCount >= 9) {
//Shaking here, DO stuff.
shakeCount = 0;
} else if ([self AccelerationIsShakingLast:self.lastAcceleration current:acceleration threshold:0.7]) {
shakeCount = shakeCount + 5;
}else if (![self AccelerationIsShakingLast:self.lastAcceleration current:acceleration threshold:0.2]) {
if (shakeCount > 0) {
shakeCount--;
}
}
}
self.lastAcceleration = acceleration;
}
- (BOOL) AccelerationIsShakingLast:(UIAcceleration *)last current:(UIAcceleration *)current threshold:(double)threshold {
double
deltaX = fabs(last.x - current.x),
deltaY = fabs(last.y - current.y),
deltaZ = fabs(last.z - current.z);
return
(deltaX > threshold && deltaY > threshold) ||
(deltaX > threshold && deltaZ > threshold) ||
(deltaY > threshold && deltaZ > threshold);
}
추신 : 업데이트 간격을 1/15 초로 설정했습니다.
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / 15)];
답변
UIAccelerometerDelegate 프로토콜의 일부인 accelerometer : didAccelerate : 메소드를 통해 가속도계를 확인하고 값이 흔들림에 필요한 이동량의 임계 값을 초과하는지 확인해야합니다.
iPhone 개발자 사이트에서 사용 가능한 GLPaint 예제의 AppController.m 하단에 가속도계 : didAccelerate : 메소드에 적절한 샘플 코드가 있습니다.
답변
Swift를 사용하는 iOS 8.3 (아마도)에서는 뷰 컨트롤러에서 motionBegan
또는 motionEnded
메서드 를 재정의하는 것만 큼 간단 합니다.
class ViewController: UIViewController {
override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent) {
println("started shaking!")
}
override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent) {
println("ended shaking!")
}
}