Loc*_*ike 142 uigesturerecognizer ios
我有一个视图,UIPanGestureRecognizer可以垂直拖动视图.所以在识别器回调中,我只更新y坐标来移动它.这个视图的超级视图有一个UIPanGestureRecognizer水平拖动视图,只是更新x坐标.
问题是第一个UIPanGestureRecognizer是事件是垂直移动视图,所以我不能使用超视图手势.
我试过了
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:
(UIGestureRecognizer *)otherGestureRecognizer;
Run Code Online (Sandbox Code Playgroud)
两者都会奏效,但我不希望如此.我希望只有在运动明显水平的情况下才能检测水平.所以如果UIPanGestureRecognizer有一个方向属性会很棒.
我怎样才能实现这种行为?我发现文档很混乱,所以也许有人可以在这里更好地解释它.
Hej*_*azi 207
只需为垂直平移手势识别器执行此操作,它适用于我:
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)panGestureRecognizer {
CGPoint velocity = [panGestureRecognizer velocityInView:someView];
return fabs(velocity.y) > fabs(velocity.x);
}
Run Code Online (Sandbox Code Playgroud)
小智 72
我在@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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Loc*_*ike 51
我想出了创建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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这将仅在用户开始拖动所选行为时触发手势.将direction属性设置为正确的值,然后全部设置.
小智 11
我试图用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) > enableThreshold) {
return NO;
}
}
return YES;
}
Run Code Online (Sandbox Code Playgroud)
然后,只能在水平阈值范围内滑动才能触发此平移手势.
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
}
Run Code Online (Sandbox Code Playgroud)
以下解决方案解决了我的问题:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if ([gestureRecognizer.view isEqual:self.view] && [otherGestureRecognizer.view isEqual:self.tableView]) {
return NO;
}
return YES;
}
Run Code Online (Sandbox Code Playgroud)
这实际上只是检查pan是否在主视图或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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
像这样调用:
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
}
}
Run Code Online (Sandbox Code Playgroud)
或者
let pan = PanDirectionGestureRecognizer(direction: .horizontal, target: self, action: #selector(self.push(_:)), constraint: Constaint(maxAngle: 5, minSpeed: 80))
view.addGestureRecognizer(pan)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
61963 次 |
| 最近记录: |