簡體   English   中英

使用UIGestureRecognizer(iOS)平移,縮放,圍繞anchorPoint旋轉UIView

[英]Pan, zoom, rotate UIView around anchorPoint using UIGestureRecognizer (iOS)

我正在嘗試使用UIGestureRecognizers旋轉,平移和縮放UIView。 識別器被添加到超視圖中,而旋轉,縮放等應用於子視圖(_baseImage),這使我能夠在將來接收手勢事件時將其他事物覆蓋在子視圖之上。

這個想法是UIView應該在兩個觸摸點下方的子視圖上圍繞“錨點”進行縮放/旋轉,因為這似乎是最自然的。 我遇到的問題是設置anchorPoint后子視圖的位置,以及縮放和旋轉似乎沒有使用set anchorPoint。 我對重疊坐標系統/ CGAffine變換缺乏了解可能會讓我陷入困境。 代碼來自各種示例。

這是我現在的代碼:

-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
    CGPoint oldOrigin = view.frame.origin;
    view.layer.anchorPoint = anchorPoint;
    CGPoint newOrigin = view.frame.origin;

    CGPoint transition;
    transition.x = newOrigin.x - oldOrigin.x;
    transition.y = newOrigin.y - oldOrigin.y;

    view.center = CGPointMake (view.center.x - transition.x, view.center.y - transition.y);

}
- (void) updateTransformWithOffset: (CGPoint) translation
{
    // Create a blended transform representing translation,
    // rotation, and scaling
    _baseImage.transform = CGAffineTransformMakeTranslation(translation.x + tx, translation.y + ty);
    _baseImage.transform = CGAffineTransformRotate(_baseImage.transform, theta);
    _baseImage.transform = CGAffineTransformScale(_baseImage.transform, scale, scale);
}
- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)uigr {
    if (uigr.state == UIGestureRecognizerStateBegan) {
        UIView *piece = self.view;
        CGPoint locationInView = [uigr locationInView:_baseImage];
        myFrame = _baseImage.frame;
        CGPoint newAnchor = CGPointMake( (locationInView.x / piece.bounds.size.width), (locationInView.y / piece.bounds.size.height ));
       [self setAnchorPoint:newAnchor forView:_baseImage];
    }
}
- (void) handlePinch: (UIPinchGestureRecognizer *) uigr
{
    [self adjustAnchorPointForGestureRecognizer:uigr];
    if (uigr.state == UIGestureRecognizerStateBegan) {
        initScale = scale;
    }
    scale = initScale*uigr.scale;
    [self updateTransformWithOffset:CGPointZero];
}

我找到了一個解決我對anchorPoint特定問題的解決方案。 我試圖將變換應用於在Interface Builder中添加的UIView,這會導致錨點問題並設置新的中心點,刪除然后重新添加子視圖似乎可以修復它。 如果有人有類似的問題,我在視圖控制器上使用的最終代碼,它使用觸摸位置作為旋轉和縮放的中心,在UIView上進行縮放,旋轉和平移:

#import "ViewController.h"

@interface ViewController (){
    CGFloat tx; // x translation
    CGFloat ty; // y translation
    CGFloat scale; // zoom scale
    CGFloat theta; // rotation angle
    CGFloat initScale ;
    CGFloat initTheta ;
}
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotation:)];
    [rotationGesture setDelegate:self];
    [self.view addGestureRecognizer:rotationGesture];
    UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
    [pinchGesture setDelegate:self];
    [self.view addGestureRecognizer:pinchGesture];
    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    [panGesture setDelegate:self];
    [panGesture setMinimumNumberOfTouches:1];
    [panGesture setMaximumNumberOfTouches:1];
    [self.view addGestureRecognizer:panGesture];
    _baseImage.transform = CGAffineTransformIdentity;
    tx = 0.0f; ty = 0.0f; scale = 1.0f; theta = 0.0f;
    scale = 1.0;
    //removing and adding back to the view seems to fix problems with anchor point I was having, I suspect because of IB layout/scaling and constraints etc
    UIView *mySuperView =_baseImage.superview;
    [_baseImage removeFromSuperview];
    [mySuperView addSubview:_baseImage];
}
-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)myview
{
    CGPoint oldOrigin = myview.frame.origin;
    myview.layer.anchorPoint = anchorPoint;
    CGPoint newOrigin = myview.frame.origin;
    CGPoint transition;
    transition.x = (newOrigin.x - oldOrigin.x);
    transition.y = (newOrigin.y - oldOrigin.y);
    CGPoint myNewCenter = CGPointMake (myview.center.x - transition.x, myview.center.y - transition.y);
    myview.center =  myNewCenter;
}
- (void) updateTransformWithOffset: (CGPoint) translation
{
    // Create a blended transform representing translation,
    // rotation, and scaling
    _baseImage.transform = CGAffineTransformMakeTranslation(translation.x + tx, translation.y + ty);
    _baseImage.transform = CGAffineTransformRotate(_baseImage.transform, theta);
    _baseImage.transform = CGAffineTransformScale(_baseImage.transform, scale, scale);
}
- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)uigr {
    if (uigr.state == UIGestureRecognizerStateBegan) {
        tx =_baseImage.transform.tx;
        ty =_baseImage.transform.ty;
        CGPoint locationInView = [uigr locationInView:_baseImage];
        CGPoint newAnchor = CGPointMake( (locationInView.x / _baseImage.bounds.size.width), (locationInView.y / _baseImage.bounds.size.height ));
        [self setAnchorPoint:newAnchor forView:_baseImage];
    }
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    // if the gesture recognizers are on different views, don't allow simultaneous recognition
    if (gestureRecognizer.view != otherGestureRecognizer.view)
        return NO;

    if (![gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] && ![otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        return YES;
    }
    return NO;
}
- (void) handleRotation: (UIRotationGestureRecognizer *) uigr
{
    if (uigr.state == UIGestureRecognizerStateBegan) {
        initTheta = theta;
    }
    theta = initTheta+uigr.rotation;
    [self adjustAnchorPointForGestureRecognizer:uigr];
    [self updateTransformWithOffset:CGPointZero];
}
- (void) handlePinch: (UIPinchGestureRecognizer *) uigr
{
    if (uigr.state == UIGestureRecognizerStateBegan) {
        initScale = scale;
    }
    scale = initScale*uigr.scale;
    [self adjustAnchorPointForGestureRecognizer:uigr];
    [self updateTransformWithOffset:CGPointZero];

}
- (void) handlePan: (UIPanGestureRecognizer *) uigr
{
    CGPoint translation = [uigr translationInView:_baseImage.superview];
    [self adjustAnchorPointForGestureRecognizer:uigr];
    [self updateTransformWithOffset:translation];
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

OP的原始解決方案轉換為Swift 2.0。 我省略了解決方法,因為它似乎不再是一個問題。

class ViewController: UIViewController {

    var tx:CGFloat = 0.0 // x translation
    var ty:CGFloat = 0.0 // y translation
    var scale:CGFloat = 1.0 // zoom scale
    var theta:CGFloat = 0.0 // rotation angle
    var initScale:CGFloat = 1.0
    var initTheta:CGFloat = 0.0
    var transformedView: UIView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        transformedView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        transformedView.backgroundColor = UIColor.blueColor()
        view.addSubview(transformedView)

        let rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(OHPlastyViewController.handleRotation(_:)))
        rotationGesture.delegate = self
        view.addGestureRecognizer(rotationGesture)


        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(OHPlastyViewController.handlePinch(_:)))
        pinchGesture.delegate = self
        view.addGestureRecognizer(pinchGesture)

        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(OHPlastyViewController.handlePan(_:)))
        panGesture.delegate = self
        panGesture.minimumNumberOfTouches = 1
        panGesture.maximumNumberOfTouches = 1
        view.addGestureRecognizer(panGesture)

        // The workaround wasn't translated to Swift because it doesn't seem to be needed anymore
        /*
         _baseImage.transform = CGAffineTransformIdentity;
         //removing and adding back to the view seems to fix problems with anchor point I was having, I suspect because of IB layout/scaling and constraints etc
         UIView *mySuperView =_baseImage.superview;
         [_baseImage removeFromSuperview];
         [mySuperView addSubview:_baseImage];*/
    }

    func setAnchorPoint(anchorPoint: CGPoint, forView myView: UIView) {
        let oldOrigin: CGPoint = myView.frame.origin
        myView.layer.anchorPoint = anchorPoint
        let newOrigin = myView.frame.origin
        let transition = CGPoint(x: newOrigin.x - oldOrigin.x, y: newOrigin.y - oldOrigin.y)
        let myNewCenter = CGPoint(x: myView.center.x - transition.x, y: myView.center.y - transition.y)
        myView.center = myNewCenter
    }

    func updateTransformWithOffset(translation: CGPoint) {
        transformedView.transform = CGAffineTransformMakeTranslation(translation.x + tx, translation.y + ty)
        transformedView.transform = CGAffineTransformRotate(transformedView.transform, theta)
        transformedView.transform = CGAffineTransformScale(transformedView.transform, scale, scale)
    }

    func adjustAnchorPointForGestureRecognizer(recognizer: UIGestureRecognizer) {
        if (recognizer.state == .Began) {
            tx = transformedView.transform.tx
            ty = transformedView.transform.ty
            let locationInView = recognizer.locationInView(transformedView)
            let newAnchor = CGPoint(x: (locationInView.x / transformedView.bounds.size.width), y: (locationInView.y / transformedView.bounds.size.height))
            setAnchorPoint(newAnchor, forView: transformedView)
        }
    }

    func handleRotation(recognizer: UIRotationGestureRecognizer) {
        if recognizer.state == .Began {
            initTheta = theta
        }
        theta = initTheta + recognizer.rotation
        adjustAnchorPointForGestureRecognizer(recognizer)
        updateTransformWithOffset(CGPointZero)
    }

    func handlePinch(recognizer: UIPinchGestureRecognizer) {
        if recognizer.state == .Began {
            initScale = scale
        }
        scale = initScale * recognizer.scale
        adjustAnchorPointForGestureRecognizer(recognizer)
        updateTransformWithOffset(CGPointZero)
    }

    func handlePan(recognizer: UIPanGestureRecognizer) {
        let translation = recognizer.translationInView(transformedView.superview)
        adjustAnchorPointForGestureRecognizer(recognizer)
        updateTransformWithOffset(translation)
    }
}

extension ViewController: UIGestureRecognizerDelegate {

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer.view != otherGestureRecognizer.view {
            return false
        }

        if !gestureRecognizer.isKindOfClass(UITapGestureRecognizer.self) && !otherGestureRecognizer.isKindOfClass(UITapGestureRecognizer.self) {
            return true
        }
        return false
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM