나는이 가지고있는보기가 UIPanGestureRecognizer
수직으로 뷰를 드래그합니다. 인식기 콜백에서는 y 좌표 만 업데이트하여 이동합니다. 이 뷰의 슈퍼 뷰 UIPanGestureRecognizer
에는 뷰를 가로로 드래그하여 x 좌표 만 업데이트하는 뷰가 있습니다.
문제는 첫 번째 UIPanGestureRecognizer
로 뷰를 세로로 이동하는 이벤트를 수행하므로 슈퍼 뷰 제스처를 사용할 수 없다는 것입니다.
나는 시도했다
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:
(UIGestureRecognizer *)otherGestureRecognizer;
둘 다 작동하지만, 나는 그것을 원하지 않습니다. 움직임이 명확하게 수평 인 경우에만 수평을 감지하고 싶습니다. 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.x) > abs(velocity.y)
}
답변
제공된 @LocoMike와 같은 하위 클래스를 사용하여 솔루션을 만들었지 만 @Hejazi가 제공 한 초기 속도를 통해보다 효과적인 탐지 메커니즘을 사용했습니다. 나는 또한 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:
...
}
답변
UIPanGestureRecognizer의 서브 클래스를 생성하는 것으로 파악했습니다.
DirectionPanGestureRecognizer :
#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
DirectionPanGestureRecognizer.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
사용자가 선택한 비헤이비어에서 드래그를 시작하면 제스처가 트리거됩니다. 방향 속성을 올바른 값으로 설정하면 모든 설정이 완료됩니다.
답변
UIPanGestureRecognizer를 사용하여 유효한 영역을 가로로 제한하려고했습니다.
- (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;
}
그런 다음 thresholdAngle 도 내에서 가로 로만 스 와이프 하면이 팬 제스처가 트리거 될 수 있습니다.
답변
Swift 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;
}
이것은 실제로 팬이 기본보기 또는 tableView에서 진행되고 있는지 확인하는 것입니다.
답변
게으른에 대한 리의 답변 스위프트 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
}
}
}
}
