UI 팬 제스처 인식기 - 수직 또는 수평만
저는 다음과 같은 견해를 가지고 있습니다.UIPanGestureRecognizer
보기를 수직으로 끕니다.그래서 인식기 콜백에서는 y 좌표만 업데이트하여 이동합니다.이 뷰의 개요는 다음과 같습니다.UIPanGestureRecognizer
X 좌표만 업데이트하면 보기가 수평으로 끌립니다.
문제는 첫째가UIPanGestureRecognizer
보기를 수직으로 이동하기 위해 이벤트를 수행하는 중이므로 수퍼뷰 제스처를 사용할 수 없습니다.
난 시도했다.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:
(UIGestureRecognizer *)otherGestureRecognizer;
효있 거 하 요 전 원 하 지 않 아 요 그 걸 다 만 지 과 가 예 을 ▁is ▁movement ▁i ▁only ▁ ▁to ▁the ▁if ▁horizont ▁want ▁detected ▁the 요 둘 않 아▁clearly ▁be 다 효 있 과 을 거저는 움직임이 수평일 때만 수평이 감지되기를 원합니다.그래서 만약에 그가 좋을 것입니다.UIPanGestureRecognizer
방향 속성이 있습니다.
이 동작을 수행하려면 어떻게 해야 합니까?저는 그 문서들이 매우 혼란스럽다고 생각하기 때문에, 아마도 누군가가 여기서 그것을 더 잘 설명할 수 있을 것입니다.
수직 팬 제스처 인식기에 대해 이 작업을 수행하면 다음과 같은 작업이 가능합니다.
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)panGestureRecognizer {
CGPoint velocity = [panGestureRecognizer velocityInView:someView];
return fabs(velocity.y) > fabs(velocity.x);
}
스위프트의 경우:
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIPanGestureRecognizer) -> Bool {
let velocity = gestureRecognizer.velocity(in: someView)
return abs(velocity.y) > abs(velocity.x)
}
저는 @LocoMike가 제공한 답변과 같이 하위 분류로 솔루션을 만들었지만 @Henjazi가 제공한 것처럼 초기 속도를 통해 보다 효과적인 탐지 메커니즘을 사용했습니다.저도 Swift를 사용하고 있지만, 원한다면 Obj-C로 번역하기 쉬울 것입니다.
다른 솔루션에 비해 장점:
- 다른 하위 분류 솔루션보다 단순하고 간결합니다.관리할 추가 상태가 없습니다.
- 방향 탐지는 시작 작업을 보내기 전에 수행되므로 잘못된 방향을 스와이프해도 이동 제스처 선택기에 메시지가 표시되지 않습니다.
- 초기 방향이 결정된 후에는 방향 로직을 더 이상 참조하지 않습니다.따라서 초기 방향이 올바르면 인식기를 활성화하는 일반적으로 원하는 동작이 발생하지만 사용자의 손가락이 방향을 따라 완벽하게 이동하지 않는 경우에는 시작 후 제스처를 취소하지 않습니다.
코드는 다음과 같습니다.
import UIKit.UIGestureRecognizerSubclass
enum PanDirection {
case vertical
case horizontal
}
class PanDirectionGestureRecognizer: UIPanGestureRecognizer {
let direction: PanDirection
init(direction: PanDirection, target: AnyObject, action: Selector) {
self.direction = direction
super.init(target: target, action: action)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
if state == .began {
let vel = velocity(in: view)
switch direction {
case .horizontal where fabs(vel.y) > fabs(vel.x):
state = .cancelled
case .vertical where fabs(vel.x) > fabs(vel.y):
state = .cancelled
default:
break
}
}
}
}
사용 예:
let panGestureRecognizer = PanDirectionGestureRecognizer(direction: .horizontal, target: self, action: #selector(handlePanGesture(_:)))
panGestureRecognizer.cancelsTouchesInView = false
self.view.addGestureRecognizer(panGestureRecognizer)
func handlePanGesture(_ pan: UIPanGestureRecognizer) {
let percent = max(pan.translation(in: view).x, 0) / view.frame.width
switch pan.state {
case .began:
...
}
UI 팬 제스처 인식기의 하위 클래스를 만드는 것을 알게 되었습니다.
방향판 제스처 인식기:
#import <Foundation/Foundation.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
typedef enum {
DirectionPangestureRecognizerVertical,
DirectionPanGestureRecognizerHorizontal
} DirectionPangestureRecognizerDirection;
@interface DirectionPanGestureRecognizer : UIPanGestureRecognizer {
BOOL _drag;
int _moveX;
int _moveY;
DirectionPangestureRecognizerDirection _direction;
}
@property (nonatomic, assign) DirectionPangestureRecognizerDirection direction;
@end
방향판 제스처 인식기.m:
#import "DirectionPanGestureRecognizer.h"
int const static kDirectionPanThreshold = 5;
@implementation DirectionPanGestureRecognizer
@synthesize direction = _direction;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
if (self.state == UIGestureRecognizerStateFailed) return;
CGPoint nowPoint = [[touches anyObject] locationInView:self.view];
CGPoint prevPoint = [[touches anyObject] previousLocationInView:self.view];
_moveX += prevPoint.x - nowPoint.x;
_moveY += prevPoint.y - nowPoint.y;
if (!_drag) {
if (abs(_moveX) > kDirectionPanThreshold) {
if (_direction == DirectionPangestureRecognizerVertical) {
self.state = UIGestureRecognizerStateFailed;
}else {
_drag = YES;
}
}else if (abs(_moveY) > kDirectionPanThreshold) {
if (_direction == DirectionPanGestureRecognizerHorizontal) {
self.state = UIGestureRecognizerStateFailed;
}else {
_drag = YES;
}
}
}
}
- (void)reset {
[super reset];
_drag = NO;
_moveX = 0;
_moveY = 0;
}
@end
이렇게 하면 사용자가 선택한 동작을 끌어오기 시작할 때만 제스처가 트리거됩니다.방향 속성을 올바른 값으로 설정하면 모든 설정이 완료됩니다.
UIPanGesture Recognizer를 사용하여 유효한 영역을 수평으로 제한하려고 했습니다.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint velocity = [panGesture velocityInView:panGesture.view];
double radian = atan(velocity.y/velocity.x);
double degree = radian * 180 / M_PI;
double thresholdAngle = 20.0;
if (fabs(degree) > thresholdAngle) {
return NO;
}
}
return YES;
}
그런 다음 수평 방향으로 각도를 스위핑해야만 이 팬 제스처를 트리거할 수 있습니다.
빠른 3.0 답변: 손잡이만 수직 제스처 수행
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let pan = gestureRecognizer as? UIPanGestureRecognizer {
let velocity = pan.velocity(in: self)
return fabs(velocity.y) > fabs(velocity.x)
}
return true
}
다음 솔루션으로 문제가 해결되었습니다.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if ([gestureRecognizer.view isEqual:self.view] && [otherGestureRecognizer.view isEqual:self.tableView]) {
return NO;
}
return YES;
}
이것은 실제로 이동이 기본 보기 또는 테이블 보기에서 진행되는지 확인하는 것입니다.
게으른 사람들을 위한 리의 대답의 스위프트 3 버전
import UIKit
import UIKit.UIGestureRecognizerSubclass
enum PanDirection {
case vertical
case horizontal
}
class UIPanDirectionGestureRecognizer: UIPanGestureRecognizer {
let direction : PanDirection
init(direction: PanDirection, target: AnyObject, action: Selector) {
self.direction = direction
super.init(target: target, action: action)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
if state == .began {
let vel = velocity(in: self.view!)
switch direction {
case .horizontal where fabs(vel.y) > fabs(vel.x):
state = .cancelled
case .vertical where fabs(vel.x) > fabs(vel.y):
state = .cancelled
default:
break
}
}
}
}
Swift 5의 사용자 지정 팬 제스처는 다음과 같습니다.
U는 방향과 방향의 최대 각도를 제한할 수 있으며, 방향의 최소 속도도 제한할 수 있습니다.
enum PanDirection {
case vertical
case horizontal
}
struct Constaint {
let maxAngle: Double
let minSpeed: CGFloat
static let `default` = Constaint(maxAngle: 50, minSpeed: 50)
}
class PanDirectionGestureRecognizer: UIPanGestureRecognizer {
let direction: PanDirection
let constraint: Constaint
init(direction orientation: PanDirection, target: AnyObject, action: Selector, constraint limits: Constaint = Constaint.default) {
direction = orientation
constraint = limits
super.init(target: target, action: action)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
let tangent = tan(constraint.maxAngle * Double.pi / 180)
if state == .began {
let vel = velocity(in: view)
switch direction {
case .horizontal where abs(vel.y)/abs(vel.x) > CGFloat(tangent) || abs(vel.x) < constraint.minSpeed:
state = .cancelled
case .vertical where abs(vel.x)/abs(vel.y) > CGFloat(tangent) || abs(vel.y) < constraint.minSpeed:
state = .cancelled
default:
break
}
}
}
}
다음과 같이 부릅니다.
let pan = PanDirectionGestureRecognizer(direction: .vertical, target: self, action: #selector(self.push(_:)))
view.addGestureRecognizer(pan)
@objc func push(_ gesture: UIPanGestureRecognizer){
if gesture.state == .began{
// command for once
}
}
또는
let pan = PanDirectionGestureRecognizer(direction: .horizontal, target: self, action: #selector(self.push(_:)), constraint: Constaint(maxAngle: 5, minSpeed: 80))
view.addGestureRecognizer(pan)
저는 리 굿리치의 답변을 받아 특별히 단일 방향 팬이 필요했기 때문에 연장했습니다.다음과 같이 사용합니다.let pan = PanDirectionGestureRecognizer(direction: .vertical(.up), target: self, action: #selector(handleCellPan(_:)))
실제로 어떤 결정이 내려지고 있는지 조금 더 명확히 하기 위해 논평을 추가했습니다.
import UIKit.UIGestureRecognizerSubclass
enum PanVerticalDirection {
case either
case up
case down
}
enum PanHorizontalDirection {
case either
case left
case right
}
enum PanDirection {
case vertical(PanVerticalDirection)
case horizontal(PanHorizontalDirection)
}
class PanDirectionGestureRecognizer: UIPanGestureRecognizer {
let direction: PanDirection
init(direction: PanDirection, target: AnyObject, action: Selector) {
self.direction = direction
super.init(target: target, action: action)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
if state == .began {
let vel = velocity(in: view)
switch direction {
// expecting horizontal but moving vertical, cancel
case .horizontal(_) where fabs(vel.y) > fabs(vel.x):
state = .cancelled
// expecting vertical but moving horizontal, cancel
case .vertical(_) where fabs(vel.x) > fabs(vel.y):
state = .cancelled
// expecting horizontal and moving horizontal
case .horizontal(let hDirection):
switch hDirection {
// expecting left but moving right, cancel
case .left where vel.x > 0: state = .cancelled
// expecting right but moving left, cancel
case .right where vel.x < 0: state = .cancelled
default: break
}
// expecting vertical and moving vertical
case .vertical(let vDirection):
switch vDirection {
// expecting up but moving down, cancel
case .up where vel.y > 0: state = .cancelled
// expecting down but moving up, cancel
case .down where vel.y < 0: state = .cancelled
default: break
}
}
}
}
}
스위프트 4.2
해결책은 수평과 마찬가지로 수직으로 팬 제스처를 지지하는 것입니다.
let pan = UIPanGestureRecognizer(target: self, action: #selector(test1))
pan.cancelsTouchesInView = false
panView.addGestureRecognizer(pan)
솔루션 1:
@objc func panAction(pan: UIPanGestureRecognizer) {
let velocity = pan.velocity(in: panView)
guard abs(velocity.y) > abs(velocity.x) else {
return
}
}
솔루션 2:
[UISwipeGestureRecognizer.Direction.left, .right].forEach { direction in
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(swipeAction))
swipe.direction = direction
panView.addGestureRecognizer(swipe)
pan.require(toFail: swipe)
}
그러면 스와이프 제스처가 팬 제스처를 삼킬 것입니다.물론, 당신은 아무것도 할 필요가 없습니다.swipeAction
.
시간을 끌면 방향을 찾을 수 있습니다.UIView
를 통하여UIPanGestureRecognizer
코드를 따르세요.
- (void)viewDidLoad {
[super viewDidLoad];
flipFoward = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(doFlipForward:)];
[flipFoward setMaximumNumberOfTouches:1];
[flipFoward setMinimumNumberOfTouches:1];
[flipFoward setDelegate:self];
[self.view addGestureRecognizer:flipFoward];
flipBack = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(doFlipBack:)];
[flipBack setMaximumNumberOfTouches:1];
[flipBack setMinimumNumberOfTouches:1];
[flipBack setDelegate:self];
[self.view addGestureRecognizer:flipBack];
}
#pragma mark -
#pragma mark RESPONDER
-(void)doFlipForward:(UIGestureRecognizer *)aGestureRecognizer{
NSLog(@"doFlipForward");
if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateBegan) {
NSLog(@"UIGestureRecognizerStateBegan");
}
if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateChanged) {
NSLog(@"UIGestureRecognizerStateChanged");
}
if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateEnded) {
NSLog(@"UIGestureRecognizerStateEnded");
}
}
-(void)doFlipBack:(UIGestureRecognizer *)aGestureRecognizer{
NSLog(@"doFlipBack");
if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateBegan) {
NSLog(@"UIGestureRecognizerStateBegan1");
}
if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateChanged) {
NSLog(@"UIGestureRecognizerStateChanged1");
}
if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateEnded) {
NSLog(@"UIGestureRecognizerStateEnded1");
}
}
#pragma mark -
#pragma mark DELEGATE
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
CGSize size = [self.view bounds].size;
CGFloat touchX = [gestureRecognizer locationInView:self.view].x;
if((gestureRecognizer == flipFoward)
&& touchX >= (size.width - 88.0f))
{
return YES;
}
if((gestureRecognizer == flipBack)
&& touchX <= 88.0f)
{
return YES;
}
return NO;
}
해결 방법은 다음과 같습니다.
먼저 동시에 팬 제스처 인식을 활성화했습니다.
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
그런 다음 수평 및 수직 팬 제스처를 분리합니다(누적기는 NSMutableArray 속성)
- (void)verticalPan :(UIPanGestureRecognizer *) sender {
CGPoint touch = [sender translationInView:self];
NSValue *value = [NSValue valueWithCGPoint:touch];
[accumulator addObject:value];
int firstXObjectValue = (int)[[accumulator objectAtIndex:0] CGPointValue].x ;
int lastXObjectValue = (int)[[accumulator lastObject] CGPointValue].x;
int firstYObjectValue = (int)[[accumulator objectAtIndex:0] CGPointValue].y;
int lastYObjectValue = (int)[[accumulator lastObject] CGPointValue].y;
if (abs(lastYObjectValue - firstYObjectValue) < 4 && abs(lastXObjectValue - firstXObjectValue) > 4) {
NSLog(@"Horizontal Pan");
//do something here
}
else if (abs(lastYObjectValue - firstYObjectValue) > 4 && abs(lastXObjectValue - firstXObjectValue) < 4){
NSLog(@"Vertical Pan");
//do something here
}
if (accumulator.count > 3)
[accumulator removeAllObjects];
여기에 예제를 하나 추가했습니다.
let pangesture = UIPanGestureRecognizer(target: self, action: "dragview:")
yourview.addGestureRecognizer(pangesture)
func dragview(panGestureRecognizer:UIPanGestureRecognizer)
{
let touchlocation = panGestureRecognizer.locationInView(parentview)
yourview.center.y = touchlocation.y //x for horizontal
}
단순하게 사용할 수 있습니다.panGestureRecognizer
사할필없을 사용할 .pandirectionregognizer
뭐그거런. 를 사용하면 .translationInview
만 위 합니다.
- (void)gesturePan_Handle:(UIPanGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [gesture translationInView:gesture.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x, recognizer.view.center.y + translation.y);
[gesture setTranslation:CGPointMake(0, 0) inView:gesture.view];
}
}
- (void)dragAction:(UIPanGestureRecognizer *)gesture{
UILabel *label = (UILabel *)gesture.view;
CGPoint translation = [gesture translationInView:label];
label.center = CGPointMake(label.center.x + translation.x,
label.center.y + 0);
[gesture setTranslation:CGPointZero inView:label];}
수평 스크롤만 필요한 객체에 대해 PanGesture Recognizer @selector 액션 메서드를 만들었습니다.
UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(smileyDragged:)];
[buttonObject addGestureRecognizer:gesture];
빠른 길
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
return isVerticalGesture(panGestureRecognizer)
}
return false
}
private func isVerticalGesture(_ recognizer: UIPanGestureRecognizer) -> Bool {
let translation = recognizer.translation(in: superview!)
if fabs(translation.y) > fabs(translation.x) {
return true
}
return false
}
Swift의 모든 사용자들에게, 이것은 그 일을 할 것입니다 :)
import Foundation
import UIKit.UIGestureRecognizerSubclass
class DirectionPanGestureRecognizer: UIPanGestureRecognizer {
let kDirectionPanThreshold = CGFloat(5)
var drag = true
var moveX = CGFloat(0)
var moveY = CGFloat(0)
override init(target: AnyObject, action: Selector) {
super.init(target: target, action: action)
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
super.touchesMoved(touches, withEvent: event)
if state == .Failed {
return
}
let nowPoint = touches.anyObject()?.locationInView(view)
let prevPoint = touches.anyObject()?.previousLocationInView(view)
moveX += prevPoint!.x - nowPoint!.x
moveY += prevPoint!.y - nowPoint!.y
if !drag {
if abs(moveX) > kDirectionPanThreshold {
state = .Failed
} else {
drag = true
}
}
}
override func reset() {
super.reset()
moveX = 0
moveY = 0
drag = false
}
}
리 굿리치의 훌륭한 답변을 받아 스위프트 3에 포팅했습니다.
import UIKit
import UIKit.UIGestureRecognizerSubclass
enum PanDirection {
case vertical
case horizontal
}
class PanDirectionGestureRecognizer: UIPanGestureRecognizer {
let direction : PanDirection
init(direction: PanDirection, target: AnyObject, action: Selector) {
self.direction = direction
super.init(target: target, action: action)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
if state == .began {
let vel = velocity(in: self.view!)
switch direction {
case .horizontal where fabs(vel.y) > fabs(vel.x):
state = .cancelled
case .vertical where fabs(vel.x) > fabs(vel.y):
state = .cancelled
default:
break
}
}
}
}
다른 모든 접근 방식은 다음 중 하나를 기반으로 하기 때문에 저는 제 접근 방식을 공유하고 싶습니다.UIGestureRecognizerDelegate
하위분류 는하위분류또분UIPanGestureRecognizer
.
제 접근 방식은 런타임과 스위즐링을 기반으로 합니다.이 접근 방식에 대해 100% 확신할 수는 없지만, 직접 테스트하고 개선할 수 있습니다.
합니다.UIPanGestureRecognizer
코드 한 줄만 사용하면 됩니다.
UITableView().panGestureRecognizer.direction = UIPanGestureRecognizer.Direction.vertical
사용하다pod 'UIPanGestureRecognizerDirection'
또는 코드:
public extension UIPanGestureRecognizer {
override open class func initialize() {
super.initialize()
guard self === UIPanGestureRecognizer.self else { return }
func replace(_ method: Selector, with anotherMethod: Selector, for clаss: AnyClass) {
let original = class_getInstanceMethod(clаss, method)
let swizzled = class_getInstanceMethod(clаss, anotherMethod)
switch class_addMethod(clаss, method, method_getImplementation(swizzled), method_getTypeEncoding(swizzled)) {
case true:
class_replaceMethod(clаss, anotherMethod, method_getImplementation(original), method_getTypeEncoding(original))
case false:
method_exchangeImplementations(original, swizzled)
}
}
let selector1 = #selector(UIPanGestureRecognizer.touchesBegan(_:with:))
let selector2 = #selector(UIPanGestureRecognizer.swizzling_touchesBegan(_:with:))
replace(selector1, with: selector2, for: self)
let selector3 = #selector(UIPanGestureRecognizer.touchesMoved(_:with:))
let selector4 = #selector(UIPanGestureRecognizer.swizzling_touchesMoved(_:with:))
replace(selector3, with: selector4, for: self)
}
@objc private func swizzling_touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
self.swizzling_touchesBegan(touches, with: event)
guard direction != nil else { return }
touchesBegan = true
}
@objc private func swizzling_touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
self.swizzling_touchesMoved(touches, with: event)
guard let direction = direction, touchesBegan == true else { return }
defer {
touchesBegan = false
}
let forbiddenDirectionsCount = touches
.flatMap({ ($0.location(in: $0.view) - $0.previousLocation(in: $0.view)).direction })
.filter({ $0 != direction })
.count
if forbiddenDirectionsCount > 0 {
state = .failed
}
}
}
public extension UIPanGestureRecognizer {
public enum Direction: Int {
case horizontal = 0
case vertical
}
private struct UIPanGestureRecognizerRuntimeKeys {
static var directions = "\(#file)+\(#line)"
static var touchesBegan = "\(#file)+\(#line)"
}
public var direction: UIPanGestureRecognizer.Direction? {
get {
let object = objc_getAssociatedObject(self, &UIPanGestureRecognizerRuntimeKeys.directions)
return object as? UIPanGestureRecognizer.Direction
}
set {
let policy = objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC
objc_setAssociatedObject(self, &UIPanGestureRecognizerRuntimeKeys.directions, newValue, policy)
}
}
fileprivate var touchesBegan: Bool {
get {
let object = objc_getAssociatedObject(self, &UIPanGestureRecognizerRuntimeKeys.touchesBegan)
return (object as? Bool) ?? false
}
set {
let policy = objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC
objc_setAssociatedObject(self, &UIPanGestureRecognizerRuntimeKeys.touchesBegan, newValue, policy)
}
}
}
fileprivate extension CGPoint {
var direction: UIPanGestureRecognizer.Direction? {
guard self != .zero else { return nil }
switch fabs(x) > fabs(y) {
case true: return .horizontal
case false: return .vertical
}
}
static func -(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
}
}
저는 이것을 시도했습니다: 질문에 설명된 대로 저에게 효과가 있었습니다.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer is UIPanGestureRecognizer {
return true
} else {
return false
}
}
SWIFT 4.2
저는 더 나아가서 팬 제스처 방향을 만들었습니다.
enum PanDirection {
case up
case left
case right
case down
}
class PanDirectionGestureRecognizer: UIPanGestureRecognizer {
fileprivate let direction: PanDirection
init(direction: PanDirection, target: AnyObject, action: Selector) {
self.direction = direction
super.init(target: target, action: action)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
guard state != .failed else { return }
let vel = velocity(in: view)
let velocities: [PanDirection: CGFloat]
= [.up: -vel.y,
.left: -vel.x,
.right: vel.x,
.down: vel.y]
let sortedKeys = velocities.sorted { $0.1 < $1.1 }
if let key = sortedKeys.last?.key,
key != direction {
state = .cancelled
}
}
}
(사용: https://github.com/fastred/SloppySwiper 및 https://stackoverflow.com/a/30607392/5790492)
PanGestureRecognizer
interface에는 다음 정의가 포함되어 있습니다.
unsigned int _canPanHorizontally:1;
unsigned int _canPanVertically:1;
제가 확인하지는 않았지만, 아마 서브 클래스를 통해 접근할 수 있을 것입니다.
언급URL : https://stackoverflow.com/questions/7100884/uipangesturerecognizer-only-vertical-or-horizontal
'programing' 카테고리의 다른 글
Oracle Client란 무엇입니까? (0) | 2023.07.03 |
---|---|
배열이 정의되지 않았거나 초기 크기가 없음을 선언하려면 어떻게 해야 합니까? (0) | 2023.07.03 |
Quartz 사용법메일을 트리거하는 작업을 예약하기 위해 ASP.NET을 사용하는 net? (0) | 2023.07.03 |
MongoClient.connect()를 사용할 때 sslprep 주의 (0) | 2023.07.03 |
Angular2의 입력을 검사합니다. (0) | 2023.07.03 |