iOSピンチスケールと2本の指が同時に回転

ここに私のコードです:

viewDidLoad:

UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
[self.canvas addGestureRecognizer:pinch];
pinch.delegate = self;

UIRotationGestureRecognizer *twoFingersRotate = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(pinchRotate:)];
[[self canvas] addGestureRecognizer:twoFingersRotate];

twoFingersRotate.delegate = self;

ピンチと回転のコード:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

-(void)pinchRotate:(UIRotationGestureRecognizer*)rotate
{
    SMImage *selectedImage = [DataCenter sharedDataCenter].selectedImage;

    switch (rotate.state) 
    {
        case UIGestureRecognizerStateBegan:
        {
            selectedImage.referenceTransform = selectedImage.transform;
            break;
        }
        case UIGestureRecognizerStateChanged:
        {
            selectedImage.transform = CGAffineTransformRotate(selectedImage.referenceTransform, ([rotate rotation] * 55) * M_PI/180);
            break;
        }

        default:
            break;
    }
}

-(void)pinch:(UIPinchGestureRecognizer*)pinch
{
    SMImage *selectedImage = [DataCenter sharedDataCenter].selectedImage;
    [self itemSelected];

    switch (pinch.state) 
    {
        case UIGestureRecognizerStateBegan:
        {
            selectedImage.referenceTransform = selectedImage.transform;
            break;
        }
        case UIGestureRecognizerStateChanged:
        {
            CGAffineTransform transform = CGAffineTransformScale(selectedImage.referenceTransform, pinch.scale, pinch.scale);
            selectedImage.transform = transform;
            break;
        }

        default:
            break;
    }
}

My rotation works great on its own and my scale works great on its own, but they wont work together. One always works or the other doesn't. When I implement shouldRecognizeSimultaneouslyWithGestureRecognizer the two gestures seem to fight against each other and produce poor results. What am I missing? (Yes I have implemented )

26

3 答え

pinch:が呼び出されるたびに、ピンチレコグナイザのスケールに基づいてトランスフォームを計算するだけです。 pinchRotate:が呼び出されるたびに、回転認識器の回転に基づいて変換を計算するだけです。スケールと回転を1つの変換に結合することは決してありません。

ここにアプローチがあります。新しいインスタンス変数 _activeRecognizers を1つ与えてください。

NSMutableSet *_activeRecognizers;

viewDidLoad で初期化してください:

_activeRecognizers = [NSMutableSet set];

両方のレコグナイザのアクションとして、1つの方法を使用します。

- (IBAction)handleGesture:(UIGestureRecognizer *)recognizer
{
    SMImage *selectedImage = [DataCenter sharedDataCenter].selectedImage;

    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan:
            if (_activeRecognizers.count == 0)
                selectedImage.referenceTransform = selectedImage.transform;
            [_activeRecognizers addObject:recognizer];
            break;

        case UIGestureRecognizerStateEnded:
            selectedImage.referenceTransform = [self applyRecognizer:recognizer toTransform:selectedImage.referenceTransform];
            [_activeRecognizers removeObject:recognizer];
            break;

        case UIGestureRecognizerStateChanged: {
            CGAffineTransform transform = selectedImage.referenceTransform;
            for (UIGestureRecognizer *recognizer in _activeRecognizers)
                transform = [self applyRecognizer:recognizer toTransform:transform];
            selectedImage.transform = transform;
            break;
        }

        default:
            break;
    }
}

このヘルパーメソッドが必要です:

- (CGAffineTransform)applyRecognizer:(UIGestureRecognizer *)recognizer toTransform:(CGAffineTransform)transform
{
    if ([recognizer respondsToSelector:@selector(rotation)])
        return CGAffineTransformRotate(transform, [(UIRotationGestureRecognizer *)recognizer rotation]);
    else if ([recognizer respondsToSelector:@selector(scale)]) {
        CGFloat scale = [(UIPinchGestureRecognizer *)recognizer scale];
        return CGAffineTransformScale(transform, scale, scale);
    }
    else
        return transform;
}

これは回転とスケーリングだけを許可している場合に機能します。 (私はそれをテストしました!)

パンを追加する場合は、別のアクションメソッドを使用し、 selectedImage.center を調整してください。 selectedImage.transform を使用して回転とスケーリングでパンをしようとすると、はるかに複雑になります。

33
追加された
どのように私が同時に両方を適用できるかのコード例を教えてもらえますか?私のUIRotationGestureRecognizerには「スケール」プロパティがなく、UIPinchGestureRecognizerには「回転」プロパティがありません。そして私は同時にどちらのAffineを使うのか分からない。
追加された 著者 spentak,
美しく動作します。私はこの知識のおかげでずっと良いです!
追加された 著者 spentak,
お役に立てて嬉しいです。私はパンニングの方法について最後のビットを変更しました。また、XIBにジェスチャ認識機能を追加すると、 viewDidLoad にコードで作成する必要はありません。レコグナイザをビューにドラッグし、レコグナイザからFile's Ownerへのコントロールをドラッグして、レコグナイザのデリゲートとアクションアウトレットを接続します。
追加された 著者 rob mayoff,
どこからhandleGesture関数?
追加された 著者 Leang Socheat,

これを行うには、ジェスチャ代理人 shouldRecognizeSimultaneouslyWithGestureRecognizer を実装し、同時に認識したいジェスチャを配置する必要があります。

// ensure that the pinch and rotate gesture recognizers on a particular view can all recognize simultaneously
// prevent other gesture recognizers from recognizing simultaneously
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
   //if the gesture recognizers's view isn't one of our views, don't allow simultaneous recognition
    if (gestureRecognizer.view != firstView && gestureRecognizer.view != secondView)
        return NO;

   //if the gesture recognizers are on different views, don't allow simultaneous recognition
    if (gestureRecognizer.view != otherGestureRecognizer.view)
        return NO;

   //if either of the gesture recognizers is the long press, don't allow simultaneous recognition
    if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]])
        return NO;

    return YES;
}

このコードは、同時にジェスチャー認識子を必要とするビューに変更する必要があります。上記のコードは必要なものです。

8
追加された
彼はすでに shouldRecognizeSimultaneouslyWithGestureRecognizer:を持っています。これは常にYESを返します。
追加された 著者 rob mayoff,

スウィフト3、パン、回転、ピンチ

// MARK: - Gesturies

    func transformUsingRecognizer(_ recognizer: UIGestureRecognizer, transform: CGAffineTransform) -> CGAffineTransform {

        if let rotateRecognizer = recognizer as? UIRotationGestureRecognizer {
            return transform.rotated(by: rotateRecognizer.rotation)
        }

        if let pinchRecognizer = recognizer as? UIPinchGestureRecognizer {
            let scale = pinchRecognizer.scale
            return transform.scaledBy(x: scale, y: scale)
        }

        if let panRecognizer = recognizer as? UIPanGestureRecognizer {
            let deltaX = panRecognizer.translation(in: imageView).x
            let deltaY = panRecognizer.translation(in: imageView).y
            return transform.translatedBy(x: deltaX, y: deltaY)
        }

        return transform
    }

    var initialTransform: CGAffineTransform?

    var gestures = Set(minimumCapacity: 3)

    @IBAction func processTransform(_ sender: Any) {

        let gesture = sender as! UIGestureRecognizer

        switch gesture.state {

        case .began:
            if gestures.count == 0 {
                initialTransform = imageView.transform
            }
            gestures.insert(gesture)

        case .changed:
            if var initial = initialTransform {
                gestures.forEach({ (gesture) in
                    initial = transformUsingRecognizer(gesture, transform: initial)
                })
                imageView.transform = initial
            }

        case .ended:
            gestures.remove(gesture)

        default:
            break
        }
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {

        return true
    }
7
追加された
あなたはそれを試しましたか?
追加された 著者 Roi Mulia,
こんにちはマイク、大変申し訳ありません。何も間違っていない。ちょうどそれが安全であることを確認するために既にテストされているかどうかを尋ねたがっています(ちょうど私がいくつかの最終シナリオを見逃した場合)
追加された 著者 Roi Mulia,
@RoiMuliaは確かです。それを実際のアプリで使ってみましょう。どうしましたか?
追加された 著者 Mike Glukhov,