iOS 图片的同时旋转缩放

占位图.jpeg

最近项目中的一个小需求,要求图片同时进行旋转和缩放两种操作,做一个简单的总结,先看下效果图:


效果图.gif

需求分析

  1. 图片有两种缩放模式,一是点击右下角按钮进行旋转缩放,二是用手势进行旋转缩放;
  2. 点击按钮是单击操作,不是旋转和捏合手势的两指操作,所以只能用平移手势,通过平移手势的移动距离,来计算图片应该缩放的比例;
  3. 图片需要能同时进行多种手势操作;

手势操作

/** 旋转缩放参考点 */
@property (nonatomic, assign) CGPoint originalPoint;
/** 视图初始化宽高 */
@property (nonatomic, assign) CGFloat originalWidth;
@property (nonatomic, assign) CGFloat originalHeight;
//旋转手势
- (void)rotateAction:(UIRotationGestureRecognizer *)rotateGesture{
    NSUInteger touchCount = rotateGesture.numberOfTouches;
    if (touchCount <= 1) {
        return;
    }
    
    CGPoint p1 = [rotateGesture locationOfTouch: 0 inView:self];
    CGPoint p2 = [rotateGesture locationOfTouch: 1 inView:self];
    CGPoint newCenter = CGPointMake((p1.x+p2.x)/2,(p1.y+p2.y)/2);
    self.originalPoint = CGPointMake(newCenter.x/self.bounds.size.width, newCenter.y/self.bounds.size.height);
    
    CGPoint oPoint = [self convertPoint:[self getRealOriginalPoint] toView:self.superview];
    self.center = oPoint;
    
    self.transform = CGAffineTransformRotate(self.transform, rotateGesture.rotation);
    rotateGesture.rotation = 0;
    
    oPoint = [self convertPoint:[self getRealOriginalPoint] toView:self.superview];
    self.center = CGPointMake(self.center.x + (self.center.x - oPoint.x),
                              self.center.y + (self.center.y - oPoint.y));
}

//捏合手势
- (void)pinchAction:(UIPinchGestureRecognizer *)pinchGesture{
    NSUInteger touchCount = pinchGesture.numberOfTouches;
    if (touchCount <= 1) {
        return;
    }
    
    CGPoint p1 = [pinchGesture locationOfTouch: 0 inView:self];
    CGPoint p2 = [pinchGesture locationOfTouch: 1 inView:self];
    CGPoint newCenter = CGPointMake((p1.x+p2.x)/2,(p1.y+p2.y)/2);
    self.originalPoint = CGPointMake(newCenter.x/self.bounds.size.width, newCenter.y/self.bounds.size.height);
    
    CGPoint oPoint = [self convertPoint:[self getRealOriginalPoint] toView:self.superview];
    self.center = oPoint;
    
    CGFloat scale = pinchGesture.scale;
    
    if (scale < 1 && self.frame.size.width <= self.originalWidth/2) {
        //当缩小到初始化宽高的一半时,停止缩小
    }else{
        self.transform = CGAffineTransformScale(self.transform, scale, scale);
        [self fitCtrlScaleX:scale scaleY:scale];
    }
    
    oPoint = [self convertPoint:[self getRealOriginalPoint] toView:self.superview];
    self.center = CGPointMake(self.center.x + (self.center.x - oPoint.x),
                              self.center.y + (self.center.y - oPoint.y));
    pinchGesture.scale = 1;
}

originalPoint为旋转缩放的参考点比例,默认是按视图中心旋转,即
self.originalPoint = CGPointMake(0.5, 0.5)

旋转和缩放手势,都需要先获取两个操作点的中心,获取新的参考点比例,重新确定视图的中心坐标(针对默认参考点不是中心点的情况)。

/** 获取参考点坐标 */
- (CGPoint)getRealOriginalPoint {
    return CGPointMake(self.bounds.size.width * self.originalPoint.x,
                       self.bounds.size.height * self.originalPoint.y);
}

然后就是正常的操作,注意,在缩放的时候,四个角的控制按钮要相反的放缩,保证大小不变,如果有其他元素,同理。

/* 控制按钮保持大小不变 */
- (void)fitCtrlScaleX:(CGFloat)scaleX scaleY:(CGFloat)scaleY {
    self.removeCtrl.transform = CGAffineTransformScale(self.removeCtrl.transform, 1/scaleX, 1/scaleY);
    self.rotateCtrl.transform = CGAffineTransformScale(self.rotateCtrl.transform, 1/scaleX, 1/scaleY);
}

按钮操作缩放

#pragma mark - === 视图控制按钮 手势事件 ===

//缩放旋转
- (void)rotateCtrlPanGesture:(UIPanGestureRecognizer *)panGesture{
    if (panGesture.state == UIGestureRecognizerStateBegan) {
        self.lastCtrlPoint = [self convertPoint:self.rotateCtrl.center toView:self.superview];
        return;
    }
    
    if (panGesture.state == UIGestureRecognizerStateEnded) {
        return;
    }
    
    CGPoint ctrlPoint = [panGesture locationInView:self.superview];
    [self scaleViewWithCtrlPoint:ctrlPoint];
    [self rotateViewWithCtrlPoint:ctrlPoint];
    self.lastCtrlPoint = ctrlPoint;
}

在控制按钮上添加平移手势,记录每一次平移的点ctrlPoint,以及上一个平移点,就是self.lastCtrlPoint

#pragma mark - === 旋转 ===

- (void)rotateViewWithCtrlPoint:(CGPoint)ctrlPoint {
    
    CGPoint oPoint = [self convertPoint:[self getRealOriginalPoint] toView:self.superview];
    self.center = CGPointMake(self.center.x - (self.center.x - oPoint.x),
                              self.center.y - (self.center.y - oPoint.y));
    
    
    float angle = atan2(self.center.y - ctrlPoint.y, ctrlPoint.x - self.center.x);
    float lastAngle = atan2(self.center.y - self.lastCtrlPoint.y, self.lastCtrlPoint.x - self.center.x);
    angle = - angle + lastAngle;
    self.transform = CGAffineTransformRotate(self.transform, angle);
    
    
    oPoint = [self convertPoint:[self getRealOriginalPoint] toView:self.superview];
    self.center = CGPointMake(self.center.x + (self.center.x - oPoint.x),
                              self.center.y + (self.center.y - oPoint.y));
}

旋转的角度,根据上一个平移点和视图中心点的角度,与当前平移点和视图中心点的角度偏差,进行transform处理。

#pragma mark - === 缩放 ===

/* 等比缩放 */
- (void)scaleViewWithCtrlPoint:(CGPoint)ctrlPoint {
    CGPoint oPoint = [self convertPoint:[self getRealOriginalPoint] toView:self.superview];
    self.center = oPoint;
    
    //上一个控制点距离中心的距离
    CGFloat preDistance = [self distanceWithStartPoint:self.center endPoint:self.lastCtrlPoint];
    //当前控制点距离中心的距离
    CGFloat newDistance = [self distanceWithStartPoint:self.center endPoint:ctrlPoint];
    CGFloat scale = newDistance / preDistance;
    
    if (scale < 1 && self.frame.size.width <= self.originalWidth/2) {
        //当缩小到初始化宽高一半时,停止缩小
    }else{
        self.transform = CGAffineTransformScale(self.transform, scale, scale);
        [self fitCtrlScaleX:scale scaleY:scale];
    }
    
    
    oPoint = [self convertPoint:[self getRealOriginalPoint] toView:self.superview];
    self.center = CGPointMake(self.center.x + (self.center.x - oPoint.x),
                              self.center.y + (self.center.y - oPoint.y));
}
/* 计算两点间距 */
- (CGFloat)distanceWithStartPoint:(CGPoint)start endPoint:(CGPoint)end {
    CGFloat x = start.x - end.x;
    CGFloat y = start.y - end.y;
    return sqrt(x * x + y * y);
}

缩放也是类似,计算上一个平移点与中心点的距离preDistance,以及当前平移点和中心点的距离newDistance,那么两次平移距离的比例,就是视图缩放的比例。这里做了一个判断,在缩小到一半时停止继续变小。

GitHub:https://github.com/TonyHYH/HYHRotateScaleImageView.git

你可能感兴趣的:(iOS 图片的同时旋转缩放)