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;這一行注釋似乎也不影響運行結果,不知這一行的目的?
結束。