To, do czego używam zdarzenia tap, jest bardzo wrażliwe na czas, więc jestem ciekawy, czy możliwe jest aktywowanie UITapGestureRecognizer, gdy użytkownik po prostu dotknie, zamiast wymagać od niego również poprawienia?
To, do czego używam zdarzenia tap, jest bardzo wrażliwe na czas, więc jestem ciekawy, czy możliwe jest aktywowanie UITapGestureRecognizer, gdy użytkownik po prostu dotknie, zamiast wymagać od niego również poprawienia?
Odpowiedzi:
Utwórz własną podklasę TouchDownGestureRecognizer i zaimplementuj gesty w dotknięciach
TouchDownGestureRecognizer.h
#import <UIKit/UIKit.h>
@interface TouchDownGestureRecognizer : UIGestureRecognizer
@end
TouchDownGestureRecognizer.m
#import "TouchDownGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
@implementation TouchDownGestureRecognizer
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateRecognized;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
self.state = UIGestureRecognizerStateFailed;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
self.state = UIGestureRecognizerStateFailed;
}
@end
realizacja:
#import "TouchDownGestureRecognizer.h"
TouchDownGestureRecognizer *touchDown = [[TouchDownGestureRecognizer alloc] initWithTarget:self action:@selector(handleTouchDown:)];
[yourView addGestureRecognizer:touchDown];
-(void)handleTouchDown:(TouchDownGestureRecognizer *)touchDown{
NSLog(@"Down");
}
Szybka realizacja:
import UIKit
import UIKit.UIGestureRecognizerSubclass
class TouchDownGestureRecognizer: UIGestureRecognizer
{
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent)
{
if self.state == .Possible
{
self.state = .Recognized
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent)
{
self.state = .Failed
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent)
{
self.state = .Failed
}
}
Oto składnia Swift dla 2017 do wklejenia:
import UIKit.UIGestureRecognizerSubclass
class SingleTouchDownGestureRecognizer: UIGestureRecognizer {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
if self.state == .possible {
self.state = .recognized
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
self.state = .failed
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
self.state = .failed
}
}
Zwróć uwagę, że jest to zamiennik typu drop-in UITap
. Więc w kodzie takim jak ...
func add(tap v:UIView, _ action:Selector) {
let t = UITapGestureRecognizer(target: self, action: action)
v.addGestureRecognizer(t)
}
możesz bezpiecznie przełączyć się na ....
func add(hairtriggerTap v:UIView, _ action:Selector) {
let t = SingleTouchDownGestureRecognizer(target: self, action: action)
v.addGestureRecognizer(t)
}
Testy pokazują, że nie będzie to wywoływane więcej niż raz. Działa jako zamiennik typu drop-in; możesz po prostu przełączać się między dwoma połączeniami.
Użyj UILongPressGestureRecognizer i ustaw jego minimumPressDuration
wartość na 0. Będzie działać jak przyziemienie podczas UIGestureRecognizerStateBegan
stanu.
func setupTap() {
let touchDown = UILongPressGestureRecognizer(target:self, action: #selector(didTouchDown))
touchDown.minimumPressDuration = 0
view.addGestureRecognizer(touchDown)
}
@objc func didTouchDown(gesture: UILongPressGestureRecognizer) {
if gesture.state == .began {
doSomething()
}
}
-(void)setupLongPress
{
self.longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(didLongPress:)];
self.longPress.minimumPressDuration = 0;
[self.view addGestureRecognizer:self.longPress];
}
-(void)didLongPress:(UILongPressGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan){
[self doSomething];
}
}
UIGestureRecognizerStateEnded
minimumPressDuration
może wynosić 0 tys.
Oto wersja Swift podobna do odpowiedzi Objective-C Roba Carawaya .
Chodzi o to, aby użyć aparatu rozpoznawania gestów długiego naciśnięcia z minimumPressDuration
ustawieniem na zero, zamiast używać rozpoznawania gestów dotknięcia. Dzieje się tak, ponieważ aparat rozpoznawania gestów długiego naciśnięcia zgłasza zdarzenia związane z dotknięciem, podczas gdy gest dotknięcia nie.
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Add "long" press gesture recognizer
let tap = UILongPressGestureRecognizer(target: self, action: #selector(tapHandler))
tap.minimumPressDuration = 0
myView.addGestureRecognizer(tap)
}
// called by gesture recognizer
@objc func tapHandler(gesture: UITapGestureRecognizer) {
// handle touch down and touch up events separately
if gesture.state == .began {
// do something...
print("tap down")
} else if gesture.state == .ended { // optional for touch up event catching
// do something else...
print("tap up")
}
}
}
To jest inne rozwiązanie. Utwórz podklasę UIControl. Możesz go używać jak UIView nawet w Storyboard, ponieważ UIControl jest podklasą UIView.
class TouchHandlingView: UIControl {
}
I dodaj do niego cel:
@IBOutlet weak var mainView: TouchHandlingView!
...
mainView.addTarget(self, action: "startAction:", forControlEvents: .TouchDown)
...
Następnie wyznaczona akcja zostanie nazwana jak UIButton:
func startAction(sender: AnyObject) {
print("start")
}
Potrzebowałem zdolności do tego, aby mój widok miał spust włosa, więc gdy tylko zostanie dotknięty, zareaguje. Używanie zarówno odpowiedzi @LESANG działało, jak i odpowiedzi @RobCaraway . Problem, na który natknąłem się przy obu odpowiedziach, polegał na tym, że straciłem zdolność rozpoznawania przeciągnięć. Potrzebowałem, aby mój widok obracał się po przesunięciu, ale gdy tylko mój palec dotknął widoku, rozpoznawano tylko kran. TapRecognizer był zbyt czuły i nie mógł odróżnić stuknięcia od machnięcia.
Oto, co wymyśliłem na podstawie odpowiedzi @LESANG w połączeniu z tą odpowiedzią i tą odpowiedzią .
W każdym przypadku umieściłem 6 komentarzy.
import UIKit.UIGestureRecognizerSubclass
class SingleTouchDownGestureRecognizer: UIGestureRecognizer {
var wasSwiped = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
guard let view = self.view else { return }
guard let touches = event.touches(for: view) else { return } // 1. compare that event in touchesBegan has touches for the view that is the same as the view to which your gesture recognizer was assigned
if touches.first != nil {
print("Finger touched!") // 2. this is when the user's finger first touches the view and is at locationA
wasSwiped = false // 3. it would seem that I didn't have to set this to false because the property was already set to false but for some reason when I didn't add this it wasn't responding correctly. Basically set this to false
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
guard let touch = touches.first else { return }
let newLocation = touch.location(in: self.view)
let previousLocation = touch.previousLocation(in: self.view)
if (newLocation.x > previousLocation.x) || (newLocation.x < previousLocation.x) {
print("finger touch went right or left") // 4. when the user's finger first touches it's at locationA. If the the user moves their finger to either the left or the right then the finger is no longer at locationA. That means it moved which means a swipe occurred so set the "wasSwiped" property to true
wasSwiped = true // 5. set the property to true because the user moved their finger
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
print("finger is no longer touching.") // 6. the user has lifted their finger off of the view. If "wasSwiped" is true then ".fail" but if it wasn't swiped then ".recognize"
if wasSwiped {
self.state = .failed
} else {
self.state = .recognized
}
}
}
I użyć go tak, aby widok, który go używa, otrzymał odpowiedź spustu włosów i gesty przesunięcia w lewo i w prawo .:
let tapGesture = SingleTouchDownGestureRecognizer(target: self, action: #selector(viewWasTapped(_:)))
myView.addGestureRecognizer(tapGesture)
let rightGesture = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture(recognizer:)))
rightGesture.direction = .right
myView.addGestureRecognizer(rightGesture)
let leftGesture = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture(recognizer:)))
leftGesture.direction = .left
myView.addGestureRecognizer(leftGesture)