0

我在屏幕中央画了一个简单的圆圈:

int radius = 100;

- (void)addCircle {
    self.circle = [CAShapeLayer layer];
    self.circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius)
                                             cornerRadius:radius].CGPath;
    self.circle.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius,
                                  CGRectGetMidY(self.view.frame)-radius);

    self.circle.fillColor = [UIColor clearColor].CGColor;
    self.circle.strokeColor = [UIColor blackColor].CGColor;
    self.circle.lineWidth = 5;

    [self.view.layer addSublayer:self.circle];
}

使用捏合手势,我允许用户增加/减少形状的半径:

- (void)scale:(UIPinchGestureRecognizer *)gestureRecognizer {    
    if (gestureRecognizer.state != UIGestureRecognizerStateBegan) {
        if (gestureRecognizer.scale < lastScale) {
            --radius;
        }
        else if (gestureRecognizer.scale > lastScale) {
            ++radius;
        }
        // Center the shape in self.view
        self.circle.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius, CGRectGetMidY(self.view.frame)-radius);

        self.circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) cornerRadius:radius].CGPath;
    }

    lastScale = gestureRecognizer.scale;
}

但是,圆圈​​不会停留在死点。相反,它会在中间反弹,直到手势完成才稳定下来。

有谁知道为什么会发生这种情况,如果是这样,我该如何预防?

4

1 回答 1

2

您的代码中存在一些问题。作为@tc。说,你没有设置形状层的框架(或边界)。默认图层大小是CGSizeZero,这就是为什么每次更改半径时都必须将图层位置偏移半径的原因。

此外,形状图层的positionpath属性是可动画的。因此,默认情况下,当您更改它们时,Core Animation 会将它们设置为新值。路径动画会导致您不想要的行为。

另外,您应该根据self.view.bounds,而不是来设置图层的位置或框架self.view.frame,因为图层的位置/框架是 的坐标系self.view,而不是 的坐标系self.view.superview。如果self.view是顶级视图并且您支持界面自动旋转,这将很重要。

我建议修改您的实施方式。创建radius一个CGFloat属性,并设置属性更新图层的boundspath

@interface ViewController ()

@property (nonatomic, strong) CAShapeLayer *circle;
@property (nonatomic) CGFloat radius;

@end

@implementation ViewController

- (void)setRadius:(CGFloat)radius {
    _radius = radius;
    self.circle.bounds = CGRectMake(0, 0, 2 * radius, 2 * radius);
    self.circle.path = [UIBezierPath bezierPathWithOvalInRect:self.circle.bounds].CGPath;
}

如果您真的想强制半径为整数,我建议在内部将其作为浮点数进行跟踪,因为如果它是浮点数,用户交互会更顺畅。CGRect在创建边界和路径之前,只需将其四舍五入到一个临时变量中:

    CGFloat intRadius = roundf(radius);
    self.circle.bounds = CGRectMake(0, 0, 2 * intRadius, 2 * intRadius);
    self.circle.path = [UIBezierPath bezierPathWithOvalInRect:self.circle.bounds].CGPath;

addCircle中,只需设置radius属性并让该设置器负责设置图层的边界和路径。还要推迟设置层的位置,直到系统的布局阶段。这样,您将在界面旋转后再次将圆重新定位在中心。

- (void)viewDidLoad {
    [super viewDidLoad];
    [self addCircle];
}

- (void)addCircle {
    self.circle = [CAShapeLayer layer];
    self.circle.fillColor = nil;
    self.circle.strokeColor = [UIColor blackColor].CGColor;
    self.circle.lineWidth = 5;
    self.radius = 100;
    [self.view.layer addSublayer:self.circle];
    [self.view setNeedsLayout];
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.circle.position = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds));
}

Finally, to handle a pinch gesture, just set the new radius to the old radius times the gesture's scale. The radius setter will take care of updating the layer's path and bounds. Then reset the gesture's scale to 1. This is simpler than tracking the gesture's prior scale. Also, use CATransaction to disable animation of the path property.

- (IBAction)pinchGestureWasRecognized:(UIPinchGestureRecognizer *)recognizer {
    [CATransaction begin]; {
        [CATransaction setDisableActions:YES];
        self.radius *= recognizer.scale;
        recognizer.scale = 1;
    } [CATransaction commit];
}
于 2012-11-10T02:37:21.443 回答