ฉันจะตรวจจับได้เมื่อมีคนเขย่า iPhone ได้อย่างไร


340

ฉันต้องการที่จะตอบสนองเมื่อมีคนเขย่า iPhone ฉันไม่สนใจว่าพวกเขาจะสั่นอย่างไรโดยเฉพาะว่ามันโบกสะบัดอย่างแรงประมาณเสี้ยววินาที ไม่มีใครรู้วิธีการตรวจสอบนี้

คำตอบ:


292

ใน 3.0 ตอนนี้มีวิธีที่ง่ายกว่า - ขอเข้าร่วมกิจกรรมการเคลื่อนไหวใหม่

เคล็ดลับหลักคือคุณต้องมี UIView (ไม่ใช่ UIViewController) บางอย่างที่คุณต้องการเป็น firstResponder เพื่อรับข้อความสั่นเหตุการณ์ นี่คือรหัสที่คุณสามารถใช้ใน 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 ใด ๆ (แม้แต่มุมมองของระบบ) ให้เป็นมุมมองที่สามารถรับเหตุการณ์การสั่นโดยเพียงแค่ทำการ subclassing มุมมองด้วยวิธีเหล่านี้เท่านั้น (จากนั้นเลือกชนิดใหม่นี้แทนประเภทฐานใน IB หรือใช้เมื่อทำการจัดสรร ดู).

ในตัวควบคุมมุมมองคุณต้องการตั้งค่ามุมมองนี้ให้เป็นการตอบกลับครั้งแรก:

- (void) viewWillAppear:(BOOL)animated
{
    [shakeView becomeFirstResponder];
    [super viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
    [shakeView resignFirstResponder];
    [super viewWillDisappear:animated];
}

อย่าลืมว่าหากคุณมีมุมมองอื่น ๆ ที่กลายเป็นการตอบกลับครั้งแรกจากการกระทำของผู้ใช้ (เช่นแถบค้นหาหรือช่องป้อนข้อความ) คุณจะต้องเรียกคืนสถานะมุมมองการสั่นครั้งแรกเมื่อมุมมองอื่น ๆ ลาออก!

วิธีนี้ใช้ได้แม้ว่าคุณจะตั้งค่า applicationSupportsShakeToEdit เป็น NO


5
นี้ไม่ได้ผลค่อนข้างสำหรับฉัน: ฉันต้องการที่จะแทนที่การควบคุมของฉันแทนviewDidAppear viewWillAppearฉันไม่แน่ใจว่าทำไม บางทีมุมมองต้องมองเห็นได้ก่อนที่จะสามารถทำอะไรก็ได้เพื่อเริ่มรับเหตุการณ์สั่น
Kristopher Johnson

1
ง่ายกว่า แต่ไม่จำเป็นต้องดีกว่า หากคุณต้องการตรวจจับเป็นเวลานานการเขย่าอย่างต่อเนื่องวิธีนี้จะไม่มีประโยชน์อย่างที่ iPhone ชอบใช้motionEndedก่อนที่การสั่นจะหยุดลงจริง ๆ ดังนั้นเมื่อใช้วิธีนี้คุณจะได้รับชุดเขย่าสั้น ๆ ที่แยกจากกันแทนที่จะเป็นแบบยาว คำตอบอื่น ๆ ทำงานได้ดีขึ้นมากในกรณีนี้
aroth

3
@Kendall - UIViewControllers ใช้ UIResponder และอยู่ในห่วงโซ่การตอบกลับ UIWindow ระดับบนสุดก็เช่นกัน developer.apple.com/library/ios/DOCUMENTATION/EventHandling/…
DougW

1
[super respondsToSelector:จะไม่ทำสิ่งที่คุณต้องการเพราะมันเทียบเท่ากับการโทรที่จะกลับมา[self respondsToSelector: สิ่งที่คุณต้องการYES [[ShakingView superclass] instancesRespondToSelector:
Vadim Yelagin

2
แทนที่จะใช้: if (event.subtype == UIEventSubtypeMotionShake) คุณสามารถใช้: if (motion == UIEventSubtypeMotionShake)
Hashim Akhtar

179

จากแอปพลิเคชัน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

การทำซ้ำของเขาจะป้องกันเหตุการณ์สั่นไม่ให้ทำงานหลายครั้งจนกว่าผู้ใช้จะหยุดการสั่นไหว


7
หมายเหตุฉันได้เพิ่มคำตอบด้านล่างเพื่อนำเสนอวิธีที่ง่ายกว่าสำหรับ 3.0
Kendall Helmstetter Gelner

2
จะเกิดอะไรขึ้นถ้าพวกเขาสั่นอย่างแม่นยำบนแกนใดแกนหนึ่ง
jprete

5
คำตอบที่ดีที่สุดเพราะ iOS 3.0 motionBeganและmotionEndedเหตุการณ์ไม่แม่นยำหรือแม่นยำมากในแง่ของการตรวจจับการเริ่มต้นและสิ้นสุดของการสั่น วิธีนี้ช่วยให้คุณมีความแม่นยำเท่าที่คุณต้องการ
aroth

2
UIAccelerometer เร่งความเร็วผู้แทน: didAccelerate:เลิกใช้แล้วใน iOS5
Yantao Xie

คำตอบอื่น ๆ นี้ดีกว่าและเร็วกว่าในการใช้stackoverflow.com/a/2405692/396133
Abramodj

154

ในที่สุดฉันก็ทำให้มันทำงานโดยใช้ตัวอย่างโค้ดจากบทช่วยสอน Undo / Redo Managerนี้
นี่คือสิ่งที่คุณต้องทำ:

  • ตั้งค่าคุณสมบัติapplicationSupportsShakeToEditในตัวแทนของแอป:
  • 
        - (void)applicationDidFinishLaunching:(UIApplication *)application {
    
            application.applicationSupportsShakeToEdit = YES;
    
            [window addSubview:viewController.view];
            [window makeKeyAndVisible];
    }

  • เพิ่ม / แทนที่canBecomeFirstResponder , viewDidAppear:และviewWillDisappear:เมธอดใน View Controller ของคุณ:
  • 
    -(BOOL)canBecomeFirstResponder {
        return YES;
    }
    
    -(void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        [self becomeFirstResponder];
    }
    
    - (void)viewWillDisappear:(BOOL)animated {
        [self resignFirstResponder];
        [super viewWillDisappear:animated];
    }

  • เพิ่มเมธอดmotionEndedให้กับ View Controller ของคุณ:
  • 
    - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
    {
        if (motion == UIEventSubtypeMotionShake)
        {
            // your code
        }
    }

    เพียงเพิ่มไปยังโซลูชัน Eran Talmor: คุณควรใช้ตัวควบคุมการนำทางแทนตัวควบคุม viewview ในกรณีที่คุณเลือกแอปพลิเคชันในตัวเลือกโครงการใหม่
    Rob

    ฉันลองใช้มัน แต่บางครั้งก็หนักหรือสั่นเบา ๆ มันหยุดแล้ว
    vinothp

    ขั้นตอนที่ 1 คือตอนนี้ซ้ำซ้อนเป็นค่าเริ่มต้นของมีapplicationSupportsShakeToEdit YES
    DonVaughn

    1
    โทร[self resignFirstResponder];ล่วงหน้า[super viewWillDisappear:animated];ทำไม นี่มันแปลกประหลาด
    JaredH

    94

    ก่อนอื่นคำตอบที่ 10 กรกฎาคมของ Kendall เป็นจุด ๆ

    ตอนนี้ ... ฉันต้องการทำสิ่งที่คล้ายกัน (ใน iPhone OS 3.0+) เฉพาะในกรณีของฉันฉันต้องการให้แอพกว้างดังนั้นฉันจึงสามารถแจ้งเตือนส่วนต่างๆ ของแอปเมื่อเกิดการสั่นไหว นี่คือสิ่งที่ฉันทำ

    ครั้งแรกผม subclassed UIWindow นี่คือ peasy ง่าย สร้างไฟล์คลาสใหม่ด้วยอินเทอร์เฟซเช่นMotionWindow : UIWindow(อย่าลังเลที่จะเลือกของคุณเอง natch) เพิ่มวิธีการดังนี้:

    - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
        if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) {
            [[NSNotificationCenter defaultCenter] postNotificationName:@"DeviceShaken" object:self];
        }
    }

    เปลี่ยน@"DeviceShaken"เป็นชื่อการแจ้งเตือนที่คุณเลือก บันทึกไฟล์

    ตอนนี้ถ้าคุณใช้ MainWindow.xib (สิ่งเทมเพลต Xcode หุ้น) ไปที่นั่นและเปลี่ยนคลาสของวัตถุหน้าต่างของคุณจากUIWindowเป็นMotionWindowหรืออะไรก็ตามที่คุณเรียกมัน บันทึก xib หากคุณตั้งค่าUIWindow โดยทางโปรแกรมให้ใช้คลาส Window ใหม่ของคุณที่นั่นแทน

    ตอนนี้แอปของคุณกำลังใช้คลาสUIWindow เฉพาะ ไม่ว่าคุณต้องการได้รับการแจ้งเตือนเกี่ยวกับการสั่นไหวเมื่อใดก็ตามลงทะเบียนเพื่อรับการแจ้งเตือน! แบบนี้:

    [[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(deviceShaken) name:@"DeviceShaken" object:nil];

    ในการลบตัวคุณเองออกจากการเป็นผู้สังเกต:

    [[NSNotificationCenter defaultCenter] removeObserver:self];

    ฉันใส่ของฉันลงในviewWillAppear:และviewWillDisappear:โดยที่ตัวควบคุมมุมมองเกี่ยวข้อง ตรวจสอบให้แน่ใจว่าการตอบสนองของคุณต่อเหตุการณ์สั่นทราบว่าเป็น "กำลังดำเนินการอยู่" หรือไม่ มิฉะนั้นหากอุปกรณ์ถูกเขย่าอย่างต่อเนื่องสองครั้งคุณจะประสบปัญหาการจราจรติดขัด วิธีนี้คุณสามารถเพิกเฉยต่อการแจ้งเตือนอื่น ๆ จนกว่าคุณจะตอบกลับการแจ้งเตือนดั้งเดิมอย่างแท้จริง

    นอกจากนี้คุณอาจเลือกที่จะออกจากคิวmotionBeganกับmotionEnded มันขึ้นอยู่กับคุณ. ในกรณีของผลที่ออกมามักจะต้องการที่จะใช้สถานที่หลังจากที่อุปกรณ์ที่เหลือ (เทียบกับเมื่อมันเริ่มสั่น) ดังนั้นฉันใช้motionEnded ลองทั้งคู่และดูว่าอันไหนที่เหมาะสมกว่า ... หรือตรวจจับ / แจ้งเตือนสำหรับทั้งคู่!

    อีกข้อสังเกตหนึ่ง (อยากรู้อยากเห็น) ที่นี่: สังเกตว่าไม่มีสัญญาณของการจัดการการตอบกลับครั้งแรกในรหัสนี้ ฉันลองทำสิ่งนี้กับ Table View Controllers แล้วและทุกอย่างดูเหมือนจะทำงานร่วมกันได้ดีมาก! ฉันไม่สามารถรับรองสถานการณ์อื่น ๆ ได้

    เคนดัลและอื่น ๆ al - ใคร ๆ ก็พูดได้ว่าทำไมถึงเป็นเช่นนั้นสำหรับUIWindow subclasses เป็นเพราะหน้าต่างอยู่ด้านบนสุดของห่วงโซ่อาหารหรือไม่


    1
    นั่นคือสิ่งที่แปลกมาก มันทำงานได้ตามที่เป็น หวังว่ามันไม่ใช่กรณีของ "การทำงานทั้ง ๆ ที่ตัวเอง" แม้ว่า! กรุณาแจ้งให้เราทราบสิ่งที่คุณพบในการทดสอบของคุณเอง
    Joe D'Andrea

    ฉันชอบที่นี่เพื่อ subclassing UIView ปกติโดยเฉพาะอย่างยิ่งเมื่อคุณเพียงแค่ต้องการที่จะอยู่ในที่เดียวดังนั้นการวาง subclass ของหน้าต่างจึงดูเหมือนเป็นธรรมชาติ
    Shaggy Frog

    ขอบคุณ jdandrea ฉันใช้วิธีการของคุณ แต่สั่นรับหลาย ๆ ครั้ง !!! ฉันแค่ต้องการให้ผู้ใช้สามารถเขย่าครั้งเดียว (ในมุมมองที่มีการเขย่า) ... ! ฉันจะจัดการกับมันได้อย่างไร ฉันใช้ sth เช่นนี้ ฉันใช้รหัสของฉัน smht เช่นนี้: i-phone.ir/forums/uploadedpictures/… ---- แต่ปัญหาคือแอพพลิเคชั่นสั่นเพียง 1 ครั้งตลอดอายุการใช้งาน! ไม่เพียง แต่ดู
    มิโอ

    1
    Momeks: หากคุณต้องการให้การแจ้งเตือนเกิดขึ้นเมื่ออุปกรณ์อยู่ในสถานะที่เหลือ (post-shake) ให้ใช้ motionEnded แทน motionBegan นั่นควรจะทำ!
    Joe D'Andrea

    1
    @Joe D'Andrea - ใช้งานได้ตามที่เป็นเพราะ UIWindow อยู่ในห่วงโซ่การตอบกลับ หากมีสิ่งใดที่สูงกว่าการดักจับโซ่และใช้เหตุการณ์เหล่านี้มันจะไม่ได้รับ developer.apple.com/library/ios/DOCUMENTATION/EventHandling/…
    DougW

    34

    ฉันเจอโพสต์นี้เพื่อหาการใช้งานแบบ "เขย่า" คำตอบของ millenomi นั้นใช้ได้ดีสำหรับฉันแม้ว่าฉันกำลังมองหาบางสิ่งที่ต้องใช้ "การกระทำเขย่า" อีกเล็กน้อยเพื่อกระตุ้น ฉันได้เปลี่ยนเป็นค่าบูลีนด้วย int shakeCount ฉันยังใช้วิธี L0AccelerationIsShaking () อีกครั้งใน Objective-C คุณสามารถปรับแต่งปริมาณกระสุนที่ต้องการโดยการปรับแต่งปริมาณที่เพิ่มเข้าไปใน 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);
    }

    PS: ฉันได้ตั้งช่วงเวลาการอัปเดตเป็น 1/15 ของวินาที

    [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / 15)];

    ฉันจะตรวจจับการเคลื่อนไหวของอุปกรณ์เช่นเดียวกับพาโนรามาได้อย่างไร
    user2526811

    จะระบุการสั่นไหวได้อย่างไรหาก iPhone ถูกย้ายในทิศทาง X เท่านั้น ฉันไม่ต้องการตรวจจับการสั่นถ้าเป็นในทิศทาง Y หรือ Z
    ธัน

    12

    คุณต้องตรวจสอบ accelerometer ผ่าน accelerometer: didAccelerate: วิธีการซึ่งเป็นส่วนหนึ่งของโปรโตคอล UIAccelerometerDelegate และตรวจสอบว่าค่าผ่านเกณฑ์สำหรับปริมาณการเคลื่อนไหวที่จำเป็นสำหรับการสั่นหรือไม่

    accelerometer: didAccelerate: วิธีที่ด้านล่างของ AppController.m ในตัวอย่าง GLPaint ซึ่งมีอยู่ในเว็บไซต์นักพัฒนา iPhone


    12

    ใน iOS 8.3 (อาจก่อนหน้านี้) ด้วย Swift มันง่ายเหมือนการเอาชนะ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!")
        }
    }

    คุณลองหรือยัง ฉันคิดว่าการทำเช่นนี้จะทำงานได้เมื่อแอปอยู่ในพื้นหลัง
    nhgrif

    ไม่ .. จะเร็ว ๆ นี้ .. แต่ถ้าคุณสังเกตเห็น iPhone 6s มันมีคุณสมบัติ "รับหน้าจอปลุก" ที่หน้าจอสว่างขึ้นบางครั้งเมื่อคุณหยิบอุปกรณ์ ฉันต้องจับพฤติกรรมนี้
    nr5

    9

    นี่คือรหัสตัวแทนพื้นฐานที่คุณต้องการ:

    #define kAccelerationThreshold      2.2
    
    #pragma mark -
    #pragma mark UIAccelerometerDelegate Methods
        - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration 
        {   
            if (fabsf(acceleration.x) > kAccelerationThreshold || fabsf(acceleration.y) > kAccelerationThreshold || fabsf(acceleration.z) > kAccelerationThreshold) 
                [self myShakeMethodGoesHere];   
        }

    ตั้งค่าในรหัสที่เหมาะสมในส่วนต่อประสานด้วย เช่น:

    @interface MyViewController: UIViewController <UIPickerViewDelegate, UIPickerViewDataSource, UIAccelerometerDelegate>


    ฉันจะตรวจจับการเคลื่อนไหวของอุปกรณ์เช่นเดียวกับพาโนรามาได้อย่างไร
    user2526811

    จะระบุการสั่นไหวได้อย่างไรหาก iPhone ถูกย้ายในทิศทาง X เท่านั้น ฉันไม่ต้องการตรวจจับการสั่นถ้าเป็นในทิศทาง Y หรือ Z
    ธัน


    7

    เพิ่มวิธีการต่อไปนี้ในไฟล์ ViewController.m ซึ่งทำงานอย่างถูกต้อง

        -(BOOL) canBecomeFirstResponder
        {
             /* Here, We want our view (not viewcontroller) as first responder 
             to receive shake event message  */
    
             return YES;
        }
    
        -(void) motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
        {
                if(event.subtype==UIEventSubtypeMotionShake)
                {
                        // Code at shake event
    
                        UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"Motion" message:@"Phone Vibrate"delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
                        [alert show];
                        [alert release];
    
                        [self.view setBackgroundColor:[UIColor redColor]];
                 }
        }
        - (void)viewDidAppear:(BOOL)animated
        {
                 [super viewDidAppear:animated];
                 [self becomeFirstResponder];  // View as first responder 
         }

    5

    ขออภัยที่โพสต์สิ่งนี้เป็นคำตอบแทนที่จะเป็นความคิดเห็น แต่อย่างที่คุณเห็นฉันยังใหม่กับ Stack Overflow และฉันยังไม่ได้มีชื่อเสียงพอที่จะโพสต์ความคิดเห็น

    อย่างไรก็ตามฉันที่สอง @cire เกี่ยวกับการทำให้แน่ใจว่าการตั้งค่าสถานะการตอบกลับครั้งแรกเมื่อมุมมองเป็นส่วนหนึ่งของลำดับชั้นการดู ดังนั้นการตั้งค่าสถานะการตอบกลับครั้งแรกในviewDidLoadวิธีการของตัวควบคุมมุมมองของคุณจะไม่ทำงาน และถ้าคุณไม่แน่ใจว่ามันทำงานได้ดี[view becomeFirstResponder]คุณจะได้บูลีนที่คุณสามารถทดสอบได้

    อีกจุดหนึ่ง: คุณสามารถใช้ตัวควบคุมมุมมองเพื่อจับภาพเหตุการณ์การสั่นหากคุณไม่ต้องการสร้างคลาสย่อย UIView โดยไม่จำเป็น ฉันรู้ว่ามันไม่ยุ่งยากมาก แต่ก็ยังมีตัวเลือกอยู่ เพียงแค่ย้ายโค้ดขนาดสั้นที่ Kendall ใส่ลงในคลาสย่อย UIView ลงในคอนโทรลเลอร์ของคุณแล้วส่งbecomeFirstResponderและresignFirstResponderข้อความไปที่selfแทนที่จะเป็นคลาสย่อย UIView


    สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม หากต้องการวิจารณ์หรือขอคำชี้แจงจากผู้แต่งโปรดแสดงความคิดเห็นใต้โพสต์ของพวกเขา
    Alex Salauyou

    @SashaSalauyou ฉันระบุไว้อย่างชัดเจนในประโยคแรกที่นี่ฉันไม่มีชื่อเสียงพอที่จะโพสต์ความคิดเห็นในเวลา
    Newtz

    ขอโทษ เป็นไปได้ที่นี่สำหรับ 5-yo คำตอบเพื่อเข้าสู่คิวรีวิว))
    Alex Salauyou

    5

    ปิดครั้งแรกผมรู้ว่านี่เป็นโพสต์เก่า แต่มันก็ยังมีความเกี่ยวข้องและฉันพบว่าทั้งสองได้รับการโหวตมากที่สุดคำตอบไม่ได้ตรวจสอบการสั่นเร็วที่สุดเท่าที่เป็นไปได้ นี่คือวิธีที่จะทำ:

    1. เชื่อมโยง CoreMotion กับโครงการของคุณในขั้นตอนการสร้างของเป้าหมาย: CoreMotion
    2. ใน ViewController ของคุณ:

      - (BOOL)canBecomeFirstResponder {
          return YES;
      }
      
      - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
      {
          if (motion == UIEventSubtypeMotionShake) {
              // Shake detected.
          }
      }

    4

    ทางออกที่ง่ายที่สุดคือการรับรูทหน้าต่างใหม่สำหรับแอปพลิเคชันของคุณ:

    @implementation OMGWindow : UIWindow
    
    - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
        if (event.type == UIEventTypeMotion && motion == UIEventSubtypeMotionShake) {
            // via notification or something   
        }
    }
    @end

    จากนั้นในตัวแทนแอปพลิเคชันของคุณ:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.window = [[OMGWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        //…
    }

    หากคุณใช้สตอรีบอร์ดนี่อาจเป็นเรื่องที่ยากกว่านั้นฉันไม่รู้รหัสที่คุณจะต้องใช้ในการมอบหมายแอปพลิเคชันอย่างแม่นยำ


    และใช่คุณสามารถรับคลาสฐานของคุณใน@implementationตั้งแต่ Xcode 5
    mxcl

    ฉันใช้มันได้ในหลาย ๆ แอพ ดังนั้นไม่แน่ใจว่าทำไมมันถึงถูกลง
    mxcl

    ทำงานเหมือนจับใจ ในกรณีที่คุณสงสัยคุณสามารถแทนที่คลาสหน้าต่างเช่นนี้: stackoverflow.com/a/10580083/709975
    Edu

    จะใช้งานได้เมื่อแอปอยู่ในพื้นหลังหรือไม่ หากไม่มีแนวคิดอื่นใดเกี่ยวกับวิธีการตรวจจับเมื่ออยู่ในพื้นหลัง
    nr5

    สิ่งนี้อาจใช้ได้ถ้าคุณมีการตั้งค่าโหมดพื้นหลัง
    mxcl

    1

    เพียงใช้สามวิธีนี้ในการทำ

    - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event{
    - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event{
    - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event{

    สำหรับรายละเอียดที่คุณอาจจะตรวจสอบโค้ดตัวอย่างที่สมบูรณ์กว่ามี


    1

    รุ่น swiftease ขึ้นอยู่กับคำตอบแรก!

    override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
        if ( event?.subtype == .motionShake )
        {
            print("stop shaking me!")
        }
    }

    -1

    หากต้องการเปิดใช้งานทั้งแอปนี้ฉันสร้างหมวดหมู่ใน UIWindow:

    @implementation UIWindow (Utils)
    
    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    
    - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
    {
        if (motion == UIEventSubtypeMotionShake) {
            // Do whatever you want here...
        }
    }
    
    @end
    โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
    Licensed under cc by-sa 3.0 with attribution required.