जवाबों:
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
आप आसानी से किसी भी यूआईवीवाईवाई (यहां तक कि सिस्टम के विचारों) को एक दृश्य में बदल सकते हैं जो केवल इन विधियों के साथ दृश्य को उप-वर्ग करके हिला घटना को प्राप्त कर सकते हैं (और फिर आईबी में आधार प्रकार के बजाय इस नए प्रकार का चयन कर सकते हैं, या आवंटन करते समय इसका उपयोग कर सकते हैं) राय)।
व्यू कंट्रोलर में, आप पहले उत्तरदाता बनने के लिए इस दृश्य को सेट करना चाहते हैं:
- (void) viewWillAppear:(BOOL)animated
{
[shakeView becomeFirstResponder];
[super viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[shakeView resignFirstResponder];
[super viewWillDisappear:animated];
}
यह मत भूलो कि यदि आपके पास अन्य दृश्य हैं जो उपयोगकर्ता क्रियाओं (जैसे एक खोज बार या पाठ प्रविष्टि क्षेत्र) से पहली प्रतिक्रिया हो जाते हैं, तो आपको दूसरे दृश्य के इस्तीफा देने पर पहले मिलाए जाने वाले उत्तरदाता की स्थिति को भी पुनर्स्थापित करने की आवश्यकता होगी!
यदि आप ApplicationSupportsShakeToEdit को NO पर सेट करते हैं तो भी यह विधि काम करती है।
motionEnded
वास्तव में शेक बंद होने से पहले फायर करना पसंद करता है । इसलिए इस दृष्टिकोण का उपयोग करने से आपको एक लंबे समय के बजाय छोटे झटकों की एक निराश श्रृंखला मिलती है। अन्य उत्तर इस मामले में बहुत बेहतर काम करता है।
[super respondsToSelector:
आप जो चाहते हैं वह नहीं करेंगे, क्योंकि यह कॉल करने के बराबर है [self respondsToSelector:
जो वापस आ जाएगा YES
। आपको क्या चाहिए [[ShakingView superclass] instancesRespondToSelector:
।
मेरे 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
जब तक उपयोगकर्ता शेक को रोकता नहीं है हेटरसिस कई बार ट्रिगर करने से शेक इवेंट को रोकता है।
motionBegan
और motionEnded
इवेंट बहुत सटीक या सटीक नहीं हैं। यह दृष्टिकोण आपको जितना चाहे उतना सटीक होने की अनुमति देता है।
मैंने अंत में इस पूर्ववत / फिर से प्रबंधक ट्यूटोरियल से कोड उदाहरणों का उपयोग करके काम किया ।
यह वही है जो आपको करने की आवश्यकता है:
- (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
}
}
applicationSupportsShakeToEdit
है YES
।
[self resignFirstResponder];
आगे फोन क्यों [super viewWillDisappear:animated];
? यह अजीब लगता है।
सबसे पहले, केंडल का 10 जुलाई का उत्तर हाजिर है।
अब ... मैं ऐसा ही कुछ करना चाहता था (आईफोन ओएस 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 टेम्प्लेट सामान) का उपयोग करते हैं, तो वहां जाएं और UIWindow से MotionWindow या जो भी आप इसे कहते हैं , अपने विंडो ऑब्जेक्ट की कक्षा को बदलें । Xib को सहेजें। यदि आप UIWindow प्रोग्रामेटिक रूप से सेट करते हैं, तो इसके बजाय अपने नए विंडो क्लास का उपयोग करें।
अब आपका ऐप विशिष्ट UIWindow वर्ग का उपयोग कर रहा है । जहाँ भी आपको शेक के बारे में बताया जाना है, उनके लिए साइन अप करें! ऐशे ही:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(deviceShaken) name:@"DeviceShaken" object:nil];
एक पर्यवेक्षक के रूप में खुद को दूर करने के लिए:
[[NSNotificationCenter defaultCenter] removeObserver:self];
मैंने अपना व्यू व्यूविलेयर में रखा : और व्यूविलाडिसैपियर: जहां व्यू कंट्रोलर चिंतित हैं। सुनिश्चित करें कि शेक इवेंट में आपकी प्रतिक्रिया जानती है कि यह "पहले से प्रगति पर है" या नहीं। अन्यथा, यदि डिवाइस उत्तराधिकार में दो बार हिलाया जाता है, तो आपके पास एक लेल ट्रैफिक जाम होगा। इस तरह से आप अन्य सूचनाओं को अनदेखा कर सकते हैं जब तक कि आप वास्तव में मूल अधिसूचना का जवाब नहीं देते।
इसके अलावा: आप से दूर संकेत के लिए चुन सकते motionBegan बनाम motionEnded । यह आप पर निर्भर करता है। मेरे मामले में, उपकरण को आराम करने के बाद हमेशा प्रभाव की आवश्यकता होती है (बनाम जब वह हिलना शुरू होता है), इसलिए मैं गतिरोध का उपयोग करता हूं । दोनों का प्रयास करें और देखें कि कौन सा अधिक समझ में आता है ... या दोनों का पता लगाने / सूचित करने के लिए!
एक और (जिज्ञासु?) यहाँ अवलोकन: सूचना इस कोड में पहले प्रत्युत्तर प्रबंधन का कोई संकेत नहीं है। मैंने अब तक केवल टेबल व्यू कंट्रोलर्स के साथ यह कोशिश की है और सब कुछ एक साथ काफी अच्छी तरह से काम करता है! मैं हालांकि अन्य परिदृश्यों के लिए वाउच नहीं कर सकता।
केंडल, एट। अल - क्या कोई बोल सकता है कि UIWindow उपवर्गों के लिए ऐसा क्यों हो सकता है ? क्या यह इसलिए है क्योंकि खिड़की खाद्य श्रृंखला के शीर्ष पर है?
मैं इस पोस्ट पर आया था एक "मिलाते हुए" कार्यान्वयन की तलाश में। सहस्राब्दी के जवाब ने मेरे लिए अच्छा काम किया, हालाँकि मैं ऐसी चीज़ की तलाश कर रहा था जिसे ट्रिगर करने के लिए थोड़ा और "हिलाने की क्रिया" की आवश्यकता हो। मैंने बूलियन मूल्य को एक इंटेक शेकाउंट के साथ बदल दिया है। मैंने ऑब्जेक्टिव-सी में L0AccelerationIsShaking () विधि को भी लागू किया। आप हिला करने के लिए जोड़ा ammount tweaking द्वारा आवश्यक मिलाते के ammount tweak कर सकते हैं। मुझे यकीन नहीं है कि मुझे अभी तक इष्टतम मूल्य मिल गए हैं, लेकिन ऐसा लगता है कि यह अभी तक अच्छी तरह से काम कर रहा है। उम्मीद है कि यह किसी की मदद करता है:
- (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)];
आपको एक्सेलेरोमीटर के माध्यम से एक्सेलेरोमीटर की जांच करने की आवश्यकता है: didAccelerate: विधि जो UIAccelerometerDelegate प्रोटोकॉल का हिस्सा है और जांचें कि क्या मान किसी हिला के लिए आवश्यक आंदोलन की मात्रा के लिए एक सीमा से अधिक है।
एक्सेलेरोमीटर में सभ्य नमूना कोड है: didAccelerate: GLPaint उदाहरण में AppController.m के निचले भाग में सही विधि जो iPhone डेवलपर साइट पर उपलब्ध है।
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!")
}
}
यह मूल प्रतिनिधि कोड है जिसकी आपको आवश्यकता है:
#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>
GLPaint उदाहरण देखें।
http://developer.apple.com/library/ios/#samplecode/GLPaint/Introduction/Intro.html
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
}
एक टिप्पणी के बजाय एक उत्तर के रूप में इसे पोस्ट करने के लिए क्षमा करें, लेकिन जैसा कि आप देख सकते हैं कि मैं ढेर अतिप्रवाह के लिए नया हूं और इसलिए मैं अभी तक टिप्पणी पोस्ट करने के लिए पर्याप्त सम्मानित नहीं हूं!
वैसे भी जब मैं दृश्य पदानुक्रम का हिस्सा होता हूं, तो पहले उत्तरदाता की स्थिति निर्धारित करने के बारे में मैं दूसरा @cire करता हूं। इसलिए आपके विचार नियंत्रक viewDidLoad
विधि में पहला उत्तरदाता स्थिति सेट करना उदाहरण के लिए काम नहीं करेगा। और यदि आप अनिश्चित हैं कि क्या यह काम कर रहा [view becomeFirstResponder]
है तो आपको एक बूलियन देता है जिसे आप परीक्षण कर सकते हैं।
एक अन्य बिंदु: यदि आप अनावश्यक रूप से एक UIView उपवर्ग बनाना नहीं चाहते हैं तो आप शेक ईवेंट को कैप्चर करने के लिए एक व्यू कंट्रोलर का उपयोग कर सकते हैं। मुझे पता है कि यह उतनी तकलीफदेह नहीं है लेकिन फिर भी विकल्प मौजूद है। कोड स्निपेट को स्थानांतरित करें, जो केंडल ने UIView उपवर्ग में आपके नियंत्रक में डाल दिया और UIView उपवर्ग के बजाय संदेश becomeFirstResponder
और resignFirstResponder
संदेश भेजें self
।
सबसे पहले, मुझे पता है कि यह एक पुरानी पोस्ट है, लेकिन यह अभी भी प्रासंगिक है, और मैंने पाया कि दो सबसे अधिक वोट किए गए उत्तरों ने जितनी जल्दी हो सके शेक का पता नहीं लगाया । यह इस तरह से करना चाहिये:
आपके ViewController में:
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake) {
// Shake detected.
}
}
सबसे आसान समाधान अपने आवेदन के लिए एक नई रूट विंडो प्राप्त करना है:
@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
बस इसे करने के लिए इन तीन तरीकों का उपयोग करें
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event{
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event{
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event{
बहुत पहले जवाब के आधार पर एक स्विफ्टेज़ संस्करण!
override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
if ( event?.subtype == .motionShake )
{
print("stop shaking me!")
}
}
इस एप्लिकेशन को सक्षम करने के लिए, मैंने UIWindow पर एक श्रेणी बनाई:
@implementation UIWindow (Utils)
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake) {
// Do whatever you want here...
}
}
@end
viewDidAppear
इसके बजाय अपने नियंत्रक को ओवरराइड करने की आवश्यकता थीviewWillAppear
। मुझे यकीन नहीं है क्यों; शायद इससे पहले कि यह हिला घटनाओं को प्राप्त करने के लिए जो कुछ भी करता है उसे देखने के लिए दृश्य को देखने की आवश्यकता है?