Popping笔记。Github上搜索"Popping"即可下载源代码。
Circle View
分析动画。
这个动画很简单,一个圆圈,一个slider,滑动slider圆圈会变,并且有spring的效果。
CircleView.m
-(id)initWithFrame:(CGRect)frame方法中首先进行断言:一个圆的高和宽一定是相同的。接着添加circleLayer,来到addCircleLayer方法。
- (void)addCircleLayer
{
CGFloat lineWidth = 4.f;
CGFloat radius = CGRectGetWidth(self.bounds)/2 - lineWidth/2;
self.circleLayer = [CAShapeLayer layer];
CGRect rect = CGRectMake(lineWidth/2, lineWidth/2, radius * 2, radius * 2);
self.circleLayer.path = [UIBezierPath bezierPathWithRoundedRect:rect
cornerRadius:radius].CGPath;
self.circleLayer.strokeColor = self.tintColor.CGColor;
self.circleLayer.fillColor = nil;
self.circleLayer.lineWidth = lineWidth;
self.circleLayer.lineCap = kCALineCapRound;
self.circleLayer.lineJoin = kCALineJoinRound;
[self.layer addSublayer:self.circleLayer];
}
我们首先得到一个CAShapeLayer,通过设置其path属性来画一个圆。
path属性是通过UIBezierPath来设置的,注意其类型是CGPathRef。
接着设置shape layer的strokeColor, lineWidth等属性来画出我们想要的圆。
接着到CircleViewController.m文件中。
首先添加circleView,即我们刚才分析的对象。设置其宽度高度都为200,中点为屏幕的中点。
此时运行程序,应该会有一个完整的圆环。
接下来我们需要添加一个slider。
- (void)addSlider
{
UISlider *slider = [UISlider new];
slider.value = 0.7f;
slider.tintColor = [UIColor customBlueColor];
slider.translatesAutoresizingMaskIntoConstraints = NO;
[slider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:slider];
NSDictionary *views = NSDictionaryOfVariableBindings(slider, _circleView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_circleView]-(40)-[slider]"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[slider]-|"
options:0
metrics:nil
views:views]];
[self.circleView setStrokeEnd:slider.value animated:NO];
}
创建一个slider,设置其初始值为0.7f(这就是为什么刚上来圆环并不完整),注意这里并没有在刚开始创建slider的时候设置其frame,center之类的属性,而是通过addConstraints:方法来限定slider的位置。
首先需要设置slider.translatesAutoresizingMaskIntoConstraints = NO,意思是说我们不使用autoresizingMask而是通过addConstraints。
NSDictionary *views = NSDictionaryOfVariableBindings(slider, _circleView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_circleView]-(40)-[slider]"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[slider]-|"
options:0
metrics:nil
views:views]];
看代码可以知道我们加了两个constraints:一个是水平方向的(H),一个是竖直方向的(V)
在竖直方向上,我们竖直排列circleView和slider,其间距为40。
在水平方向上,我们将slider放在一行上,两边距离边界的长度默认(处于蓝色虚线?)
而NSDictionaryOfVariableBingdings()的作用在于,说明@"V:[_circleView]-(40)-[slider]"和@"H:|-[slider]-|"中,_circleView和slider所代表的对象是哪个。相当于:
@"_circleView":_circleView (或者self.circleView)
@"slider":slider
现在运行程序,发现圆环已经不完整(0.7),现在我们需要监听slider:改变slider的值,圆环也会跟着改变。
在addSlider方法中,
[slider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
接着sliderChanged:方法:
[self.circleView setStrokeEnd:slider.value animated:YES];
回到CircleView.m中,找到setStrokeEnd:animated:方法。
- (void)setStrokeEnd:(CGFloat)strokeEnd animated:(BOOL)animated
{
if (animated) {
[self animateToStrokeEnd:strokeEnd];
return;
}
self.circleLayer.strokeEnd = strokeEnd;
}
可以看到,如果animated的话,则设置spring动画,并返回;如果!animated的话,则直接设置shape layer的strokeEnd的值。这也就对应了两种不同的情况:应用刚进入的时候直接设置strokeEnd的值使圆环处于0.7处;拖动slider,每次变化的时候将根据当前的value变化圆环。
- (void)animateToStrokeEnd:(CGFloat)strokeEnd
{
POPSpringAnimation *strokeAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd];
strokeAnimation.toValue = @(strokeEnd);
strokeAnimation.springBounciness = 12.f;
strokeAnimation.removedOnCompletion = NO;
[self.circleLayer pop_addAnimation:strokeAnimation forKey:@"layerStrokeAnimation"];
}
这个方法很简单,给shape layer的strokeEnd属性加上动画效果。(strokeEnd可以理解为所占的比例?)
将strokeAnimation.removedOnCompletion = NO;这一行注释似乎也不影响运行结果,不知这一行的目的?
结束。
网友评论