我在屏幕中央画了一个简单的圆圈:
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;
}
然而,圆圈不会停留在死亡中心。相反,它会在中间反弹,直到手势结束才会稳定下来。
有谁知道为什么会这样,如果有,我怎么能阻止它?
答案 0 :(得分:2)
您的代码中存在一些问题。作为@tc。说,你没有设置形状图层的框架(或边界)。默认图层大小为CGSizeZero
,这就是为什么每次更改半径时都必须将图层的位置偏移半径。
此外,形状图层的position
和path
属性是可动画的。因此,默认情况下,当您更改它们时,Core Animation会将它们设置为新值。路径动画会导致您的不良行为。
此外,您应该根据self.view.bounds
设置图层的位置或框架,而不是self.view.frame
,因为图层的位置/框架是self.view
的坐标系,而不是坐标系self.view.superview
。如果self.view
是顶级视图并且您支持界面自动旋转,则无关紧要。
我建议您修改一下如何实现这一点。将radius
设为CGFloat
属性,并设置属性更新图层的bounds
和path
:
@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
属性,让该setter负责设置图层的边界和路径。还要推迟设置图层的位置,直到系统的布局阶段。这样,在界面旋转后,您将再次将圆圈重新定位在中心。
- (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));
}
最后,要处理捏合手势,只需将新半径设置为旧半径乘以手势的比例。 radius
setter将负责更新图层的路径和边界。然后将手势的比例重置为1.这比跟踪手势的先前比例更简单。另外,使用CATransaction
禁用path
属性的动画。
- (IBAction)pinchGestureWasRecognized:(UIPinchGestureRecognizer *)recognizer {
[CATransaction begin]; {
[CATransaction setDisableActions:YES];
self.radius *= recognizer.scale;
recognizer.scale = 1;
} [CATransaction commit];
}