2015-09-24 10 views
29

उपयोगकर्ता यह देखने के लिए 3 डी टच को कैसे कार्यान्वित कर सकता है कि उपयोगकर्ता UIView पर टैप करता है या UIView पर टच स्पर्श करता है?3 डी टच/फोर्स टच कार्यान्वयन

क्या UIGestureRecognize या केवल UITouch के साथ ऐसा करने का कोई तरीका है?

उत्तर

16

आप इसे नामित इशारा पहचानकर्ता के बिना कर सकते हैं। आपको स्पर्शों को समायोजित करने की आवश्यकता नहीं है एंडेड और स्पर्श बेगन विधि, लेकिन केवल सही मान प्राप्त करने के लिए स्पर्श स्पर्श किए गए हैं। शुरू/समाप्ति से uitouch की शक्ति प्राप्त करने से अजीब मूल्य वापस आ जाएंगे।

UITouch *touch = [touches anyObject]; 

CGFloat maximumPossibleForce = touch.maximumPossibleForce; 
CGFloat force = touch.force; 
CGFloat normalizedForce = force/maximumPossibleForce; 

फिर, एक बल सीमा निर्धारित करें और सामान्य दहलीज की तुलना इस दहलीज से करें (0.75 मेरे लिए ठीक लगता है)।

+6

देखने के लिए DFContinuousForceTouchGestureRecognizer जोड़ने की आवश्यकता नहीं है, आप केवल संपूर्ण कोड क्यों नहीं देंगे .. – Esqarrouth

8

3 डी टच गुण are available on UITouch objects

आप UIView के touchesBegan: और touchesMoved: विधियों को ओवरराइड करके इन स्पर्शों को प्राप्त कर सकते हैं। सुनिश्चित नहीं है कि आप अभी तक touchesEnded: में क्या देखते हैं।

यदि आप नए इशारे पहचानकर्ताओं को तैयार करने के इच्छुक हैं, तो es पर UIGestureRecognizerSubclass में आपके संपर्क में पूर्ण पहुंच है।

मुझे यकीन नहीं है कि आप परंपरागत UIGestureRecognizer में 3 डी स्पर्श गुणों का उपयोग कैसे कर सकते हैं। शायद UIGestureRecognizerDelegate प्रोटोकॉल के gestureRecognizer:shouldReceiveTouch: विधि के माध्यम से।

+0

मैं जाँच करना चाहते हैं, तो UIView या UIView –

+0

पर बल छूने पर उपयोगकर्ता नल 'UITapGestureRecognizer' 3 डी टच के लिए अद्यतन नहीं किया गया है, तो आप अपने खुद के' UIGestureRecognizer' उपवर्ग बनाने या विचारों उपवर्ग करना होगा और 'स्पर्शों को व्यवस्थित करें' और 'स्पर्श' हटाएं। –

+1

यदि कोई स्पर्श नहीं चलता है लेकिन यह बल परिवर्तन करता है 'स्पर्श करता है:' कॉल किया जाता है? – Warpling

5

जिस तरह से मैं यह कर रहा हूं वह UITapGestureRecognizer (ऐप्पल द्वारा प्रदान किया गया) और DFContinuousForceTouchGestureRecognizer (मेरे द्वारा प्रदान किया गया) के संयोजन का उपयोग करना है।

DFContinuousForceTouchGestureRecognizer अच्छा है क्योंकि यह दबाव में परिवर्तनों के बारे में निरंतर अपडेट प्रदान करता है ताकि आप दृश्य को बढ़ाने जैसे चीजें कर सकें क्योंकि उपयोगकर्ता एक ही घटना के विपरीत, इसके दबाव को बदलता है। यदि आप केवल एक ही ईवेंट चाहते हैं तो - (void) forceTouchRecognized कॉलबैक को छोड़कर आप DFContinuousForceTouchDelegate में eveything को अनदेखा कर सकते हैं।

https://github.com/foggzilla/DFContinuousForceTouchGestureRecognizer

आप इस डाउनलोड करने और एक युक्ति बल प्रेस का समर्थन करता है कि देखने के लिए कि यह कैसे महसूस करता है पर नमूना एप्लिकेशन चला सकते हैं। बल स्पर्श के लिए प्रतिनिधि प्रोटोकॉल लागू

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    _forceTouchRecognizer = [[DFContinuousForceTouchGestureRecognizer alloc] init]; 
    _forceTouchRecognizer.forceTouchDelegate = self; 

    //here to demonstrate how this works alonside a tap gesture recognizer 
    _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)]; 

    [self.imageView addGestureRecognizer:_tapGestureRecognizer]; 
    [self.imageView addGestureRecognizer:_forceTouchRecognizer]; 
} 

टैप जेस्चर

#pragma UITapGestureRecognizer selector 

- (void)tapped:(id)sender { 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     [[[UIAlertView alloc] initWithTitle:@"Tap" message:@"YEAH!!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; 
    }); 
} 

के लिए चयनकर्ता लागू:

अपने में UIViewController निम्नलिखित लागू

#pragma DFContinuousForceTouchDelegate 

- (void)forceTouchRecognized:(DFContinuousForceTouchGestureRecognizer *)recognizer { 
    self.imageView.transform = CGAffineTransformIdentity; 
    [self.imageView setNeedsDisplay]; 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     [[[UIAlertView alloc] initWithTitle:@"Force Touch" message:@"YEAH!!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; 
    }); 
} 

- (void)forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer *)recognizer didStartWithForce:(CGFloat)force maxForce:(CGFloat)maxForce { 
    CGFloat transformDelta = 1.0f + ((force/maxForce)/3.0f); 
    self.imageView.transform = CGAffineTransformMakeScale(transformDelta, transformDelta); 
    [self.imageView setNeedsDisplay]; 
} 

- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer *)recognizer didMoveWithForce:(CGFloat)force maxForce:(CGFloat)maxForce { 
    CGFloat transformDelta = 1.0f + ((force/maxForce)/3.0f); 
    self.imageView.transform = CGAffineTransformMakeScale(transformDelta, transformDelta); 
    [self.imageView setNeedsDisplay]; 
} 

- (void)forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer *)recognizer didCancelWithForce:(CGFloat)force maxForce:(CGFloat)maxForce { 
    self.imageView.transform = CGAffineTransformIdentity; 
    [self.imageView setNeedsDisplay]; 
} 

- (void)forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer *)recognizer didEndWithForce:(CGFloat)force maxForce:(CGFloat)maxForce { 
    self.imageView.transform = CGAffineTransformIdentity; 
    [self.imageView setNeedsDisplay]; 
} 

- (void)forceTouchDidTimeout:(DFContinuousForceTouchGestureRecognizer *)recognizer { 
    self.imageView.transform = CGAffineTransformIdentity; 
    [self.imageView setNeedsDisplay]; 
} 

ध्यान दें कि यह केवल होगा बल स्पर्श का समर्थन करने वाले डिवाइस पर उपयोगी हो।

इसके अलावा, आप किसी दृश्य पर DFContinuousForceTouchGestureRecognizer नहीं जोड़ना चाहिए अगर आप iOS 8 पर या के तहत चल रहे हैं, क्योंकि यह UITouch पर नए force संपत्ति आईओएस 9.

में ही उपलब्ध आप iOS 8 उस पर इस जोड़ देते हैं तो का उपयोग करता है क्रैश हो जाएगा, इसलिए यदि आप आईओएस 9 से पुराने संस्करणों का समर्थन कर रहे हैं तो आईओएस संस्करण के आधार पर आप इस पहचानकर्ता को सशर्त रूप से जोड़ सकते हैं।

+0

वाह धन्यवाद! क्या आप अपना उत्तर स्विफ्ट 2.0 में बदल सकते हैं? और मेरा ऐप आईओएस 8-9 का समर्थन करता है इसलिए मुझे –

3

मैंने एक UIGestureRecognizer बनाया जो ऐप्पल मेल ऐप के व्यवहार को अनुकरण करता है। 3 डी स्पर्श पर, यह एक छोटी एकल पल्स कंपन के साथ शुरू होता है और फिर प्रारंभिक प्रेस के तुरंत बाद हार्ड दबाने के द्वारा बुलाया जाने वाला वैकल्पिक माध्यमिक क्रिया (हार्डटाइक्लिंग) और नाड़ी।

से https://github.com/FlexMonkey/DeepPressGestureRecognizer

परिवर्तन अनुकूलित

  • 3 डी स्पर्श आईओएस प्रणाली व्यवहार की तरह कंपन दालों
  • स्पर्श अंत करने के लिए, सिस्टम के लिए
  • सीमा चूक इसके लिए आना चाहिए की तरह एप्पल मेल एप्लिकेशन डिफ़ॉल्ट स्तर
  • हार्ड टच ट्रिगर्स हार्ड मेल कॉल ऐप जैसे मेल ऐप

नोट: मैंने अनियंत्रित सिस्टम ध्वनि k_PeakSoundID जोड़ा, लेकिन अगर आप दस्तावेज श्रेणी से अधिक निरंतर उपयोग करके असहज हैं तो इसे बंद करने के लिए स्वतंत्र महसूस करें। मैं वर्षों से अनजान स्थिरांक के साथ सिस्टम ध्वनियों का उपयोग कर रहा हूं, लेकिन कंपन का उपयोग करके कंपन दालों को बंद करने के लिए आपका स्वागत है।

import AudioToolbox 
import UIKit.UIGestureRecognizerSubclass 

class DeepPressGestureRecognizer: UIGestureRecognizer 
{ 
    var vibrateOnDeepPress = true 
    var threshold:CGFloat = 0.75 
    var hardTriggerMinTime:NSTimeInterval = 0.5 

    private var deepPressed: Bool = false 
    private var deepPressedAt: NSTimeInterval = 0 
    private var k_PeakSoundID:UInt32 = 1519 
    private var hardAction:Selector? 
    private var target: AnyObject? 

    required init(target: AnyObject?, action: Selector, hardAction:Selector?=nil, threshold: CGFloat = 0.75) 
    { 
     self.target = target 
     self.hardAction = hardAction 
     self.threshold = threshold 

     super.init(target: target, action: action) 
    } 

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent) 
    { 
     if let touch = touches.first 
     { 
      handleTouch(touch) 
     } 
    } 

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent) 
    { 
     if let touch = touches.first 
     { 
      handleTouch(touch) 
     } 
    } 

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent) 
    { 
     super.touchesEnded(touches, withEvent: event) 

     state = deepPressed ? UIGestureRecognizerState.Ended : UIGestureRecognizerState.Failed 

     deepPressed = false 
    } 

    private func handleTouch(touch: UITouch) 
    { 
     guard let _ = view where touch.force != 0 && touch.maximumPossibleForce != 0 else 
     { 
      return 
     } 

     let forcePercentage = (touch.force/touch.maximumPossibleForce) 
     let currentTime = NSDate.timeIntervalSinceReferenceDate() 

     if !deepPressed && forcePercentage >= threshold 
     { 
      state = UIGestureRecognizerState.Began 

      if vibrateOnDeepPress 
      { 
       AudioServicesPlaySystemSound(k_PeakSoundID) 
      } 

      deepPressedAt = NSDate.timeIntervalSinceReferenceDate() 
      deepPressed = true 
     } 
     else if deepPressed && forcePercentage <= 0 
     { 
      endGesture() 
     } 
     else if deepPressed && currentTime - deepPressedAt > hardTriggerMinTime && forcePercentage == 1.0 
     { 
      endGesture() 

      if vibrateOnDeepPress 
      { 
       AudioServicesPlaySystemSound(k_PeakSoundID) 
      } 

      //fire hard press 
      if let hardAction = self.hardAction, let target = self.target { 
       target.performSelector(hardAction, withObject: self) 
      } 
     } 
    } 

    func endGesture() { 
     state = UIGestureRecognizerState.Ended 
     deepPressed = false 
    } 
} 

// MARK: DeepPressable protocol extension 
protocol DeepPressable 
{ 
    var gestureRecognizers: [UIGestureRecognizer]? {get set} 

    func addGestureRecognizer(gestureRecognizer: UIGestureRecognizer) 
    func removeGestureRecognizer(gestureRecognizer: UIGestureRecognizer) 

    func setDeepPressAction(target: AnyObject, action: Selector) 
    func removeDeepPressAction() 
} 

extension DeepPressable 
{ 
    func setDeepPressAction(target: AnyObject, action: Selector) 
    { 
     let deepPressGestureRecognizer = DeepPressGestureRecognizer(target: target, action: action, threshold: 0.75) 

     self.addGestureRecognizer(deepPressGestureRecognizer) 
    } 

    func removeDeepPressAction() 
    { 
     guard let gestureRecognizers = gestureRecognizers else 
     { 
      return 
     } 

     for recogniser in gestureRecognizers where recogniser is DeepPressGestureRecognizer 
     { 
      removeGestureRecognizer(recogniser) 
     } 
    } 
}